aboutsummaryrefslogtreecommitdiff
path: root/builtins
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-08-11 14:47:34 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-08-11 14:47:34 -0400
commit2ecb5fe885042ca6c25ee0a3e3da070ddec9e07e (patch)
treecdd7c7d1d51982d4074f76a1bccc522fbc8b5eee /builtins
parent3bf8ea8e12a2728bf63968ca7b42359b089e318b (diff)
Add channels and threads
Diffstat (limited to 'builtins')
-rw-r--r--builtins/channel.c102
-rw-r--r--builtins/channel.h25
-rw-r--r--builtins/datatypes.h7
-rw-r--r--builtins/functions.c5
-rw-r--r--builtins/functions.h2
-rw-r--r--builtins/thread.c57
-rw-r--r--builtins/thread.h21
-rw-r--r--builtins/tomo.h2
-rw-r--r--builtins/types.h6
9 files changed, 225 insertions, 2 deletions
diff --git a/builtins/channel.c b/builtins/channel.c
new file mode 100644
index 00000000..0b5f7411
--- /dev/null
+++ b/builtins/channel.c
@@ -0,0 +1,102 @@
+// Functions that operate on channels
+
+#include <ctype.h>
+#include <err.h>
+#include <gc.h>
+#include <gc/cord.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/param.h>
+
+#include "array.h"
+#include "functions.h"
+#include "halfsiphash.h"
+#include "types.h"
+#include "util.h"
+
+public channel_t *Channel$new(void)
+{
+ channel_t *channel = new(channel_t);
+ channel->items = (array_t){};
+ channel->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+ channel->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
+ return channel;
+}
+
+public void Channel$push(channel_t *channel, const void *item, int64_t padded_item_size)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ Array$insert(&channel->items, item, 0, padded_item_size);
+ (void)pthread_mutex_unlock(&channel->mutex);
+ (void)pthread_cond_signal(&channel->cond);
+}
+
+public void Channel$push_all(channel_t *channel, array_t to_push, int64_t padded_item_size)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ Array$insert_all(&channel->items, to_push, 0, padded_item_size);
+ (void)pthread_mutex_unlock(&channel->mutex);
+ (void)pthread_cond_signal(&channel->cond);
+}
+
+public void Channel$pop(channel_t *channel, void *out, int64_t item_size, int64_t padded_item_size)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ while (channel->items.length == 0)
+ pthread_cond_wait(&channel->cond, &channel->mutex);
+ memcpy(out, channel->items.data, item_size);
+ Array$remove(&channel->items, 1, 1, padded_item_size);
+ (void)pthread_mutex_unlock(&channel->mutex);
+}
+
+public array_t Channel$view(channel_t *channel)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ ARRAY_INCREF(channel->items);
+ array_t ret = channel->items;
+ (void)pthread_mutex_unlock(&channel->mutex);
+ return ret;
+}
+
+public void Channel$clear(channel_t *channel)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ Array$clear(&channel->items);
+ (void)pthread_mutex_unlock(&channel->mutex);
+}
+
+public uint32_t Channel$hash(const channel_t **channel, const TypeInfo *type)
+{
+ (void)type;
+ uint32_t hash;
+ halfsiphash(*channel, sizeof(channel_t*), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
+ return hash;
+}
+
+public int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type)
+{
+ (void)type;
+ return (*x > *y) - (*x < *y);
+}
+
+bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type)
+{
+ (void)type;
+ return (*x == *y);
+}
+
+CORD Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type)
+{
+ const TypeInfo *item_type = type->ChannelInfo.item;
+ if (!channel) {
+ CORD typename = generic_as_text(NULL, false, item_type);
+ return colorize ? CORD_asprintf("\x1b[34;1m|:%s|\x1b[m", typename) : CORD_all("|:", typename, "|");
+ }
+ CORD typename = generic_as_text(NULL, false, item_type);
+ return CORD_asprintf(colorize ? "\x1b[34;1m|:%s|<%p>\x1b[m" : "|:%s|<%p>", typename, *channel);
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/channel.h b/builtins/channel.h
new file mode 100644
index 00000000..2ce71833
--- /dev/null
+++ b/builtins/channel.h
@@ -0,0 +1,25 @@
+#pragma once
+
+// Functions that operate on channels (thread-safe arrays)
+
+#include <stdbool.h>
+#include <gc/cord.h>
+
+#include "datatypes.h"
+#include "types.h"
+#include "util.h"
+
+channel_t *Channel$new(void);
+void Channel$push(channel_t *channel, const void *item, int64_t padded_item_size);
+#define Channel$push_value(channel, item, padded_item_size) ({ __typeof(item) _item = item; Channel$push(channel, &_item, padded_item_size); })
+void Channel$push_all(channel_t *channel, array_t to_push, int64_t padded_item_size);
+void Channel$pop(channel_t *channel, void *out, int64_t item_size, int64_t padded_item_size);
+#define Channel$pop_value(channel, t, padded_item_size) ({ t _val; Channel$pop(channel, &_val, sizeof(t), padded_item_size); _val; })
+void Channel$clear(channel_t *channel);
+array_t Channel$view(channel_t *channel);
+uint32_t Channel$hash(const channel_t **channel, const TypeInfo *type);
+int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type);
+bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type);
+CORD Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type);
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/datatypes.h b/builtins/datatypes.h
index b0f62d03..41a67a5e 100644
--- a/builtins/datatypes.h
+++ b/builtins/datatypes.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <pthread.h>
#define ARRAY_LENGTH_BITS 42
#define ARRAY_FREE_BITS 6
@@ -57,4 +58,10 @@ typedef struct Range_s {
int64_t first, last, step;
} Range_t;
+typedef struct {
+ array_t items;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+} channel_t;
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/functions.c b/builtins/functions.c
index 47350814..4e7d25ac 100644
--- a/builtins/functions.c
+++ b/builtins/functions.c
@@ -13,6 +13,7 @@
#include "array.h"
#include "bool.h"
+#include "channel.h"
#include "files.h"
#include "functions.h"
#include "halfsiphash.h"
@@ -101,6 +102,7 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type)
case PointerInfo: case FunctionInfo: return Pointer$hash(obj, type);
case TextInfo: return Text$hash(obj);
case ArrayInfo: return Array$hash(obj, type);
+ case ChannelInfo: return Channel$hash((const channel_t**)obj, type);
case TableInfo: return Table$hash(obj, type);
case EmptyStruct: return 0;
case CustomInfo:
@@ -122,6 +124,7 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ
case PointerInfo: case FunctionInfo: return Pointer$compare(x, y, type);
case TextInfo: return Text$compare(x, y);
case ArrayInfo: return Array$compare(x, y, type);
+ case ChannelInfo: return Channel$compare((const channel_t**)x, (const channel_t**)y, type);
case TableInfo: return Table$compare(x, y, type);
case EmptyStruct: return 0;
case CustomInfo:
@@ -140,6 +143,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type)
case PointerInfo: case FunctionInfo: return Pointer$equal(x, y, type);
case TextInfo: return Text$equal(x, y);
case ArrayInfo: return Array$equal(x, y, type);
+ case ChannelInfo: return Channel$equal((const channel_t**)x, (const channel_t**)y, type);
case TableInfo: return Table$equal(x, y, type);
case EmptyStruct: return true;
case CustomInfo:
@@ -159,6 +163,7 @@ public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type
case FunctionInfo: return Func$as_text(obj, colorize, type);
case TextInfo: return Text$as_text(obj, colorize, type);
case ArrayInfo: return Array$as_text(obj, colorize, type);
+ case ChannelInfo: return Channel$as_text((const channel_t**)obj, colorize, type);
case TableInfo: return Table$as_text(obj, colorize, type);
case TypeInfoInfo: return Type$as_text(obj, colorize, type);
case EmptyStruct: return colorize ? CORD_all("\x1b[0;1m", type->EmptyStruct.name, "\x1b[m()") : CORD_all(type->EmptyStruct.name, "()");
diff --git a/builtins/functions.h b/builtins/functions.h
index a62865bd..ac4fbf81 100644
--- a/builtins/functions.h
+++ b/builtins/functions.h
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include "datatypes.h"
#include "types.h"
extern uint8_t TOMO_HASH_KEY[8];
@@ -26,6 +27,7 @@ uint32_t generic_hash(const void *obj, const TypeInfo *type);
int32_t generic_compare(const void *x, const void *y, const TypeInfo *type);
bool generic_equal(const void *x, const void *y, const TypeInfo *type);
CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type);
+closure_t spawn(closure_t fn);
bool pop_flag(char **argv, int *i, const char *flag, CORD *result);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/thread.c b/builtins/thread.c
new file mode 100644
index 00000000..b9586917
--- /dev/null
+++ b/builtins/thread.c
@@ -0,0 +1,57 @@
+// Logic for the Thread type, representing a pthread
+
+#include <ctype.h>
+#include <err.h>
+#include <gc.h>
+#include <gc/cord.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/param.h>
+
+#include "array.h"
+#include "functions.h"
+#include "halfsiphash.h"
+#include "types.h"
+#include "util.h"
+
+public pthread_t *Thread$new(closure_t fn)
+{
+ pthread_t *thread = new(pthread_t);
+ pthread_create(thread, NULL, fn.fn, fn.userdata);
+ return thread;
+}
+
+public void Thread$join(pthread_t *thread)
+{
+ pthread_join(*thread, NULL);
+}
+
+public void Thread$cancel(pthread_t *thread)
+{
+ pthread_cancel(*thread);
+}
+
+public void Thread$detach(pthread_t *thread)
+{
+ pthread_detach(*thread);
+}
+
+CORD Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type)
+{
+ (void)type;
+ if (!thread) {
+ return colorize ? "\x1b[34;1mThread\x1b[m" : "Thread";
+ }
+ return CORD_asprintf(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *thread);
+}
+
+public const TypeInfo Thread = {
+ .size=sizeof(pthread_t*), .align=__alignof(pthread_t*),
+ .tag=CustomInfo,
+ .CustomInfo={.as_text=(void*)Thread$as_text},
+};
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/thread.h b/builtins/thread.h
new file mode 100644
index 00000000..efccae33
--- /dev/null
+++ b/builtins/thread.h
@@ -0,0 +1,21 @@
+#pragma once
+
+// Logic for the Thread type, representing a pthread
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <gc/cord.h>
+
+#include "datatypes.h"
+#include "types.h"
+#include "util.h"
+
+pthread_t *Thread$new(closure_t fn);
+void Thread$cancel(pthread_t *thread);
+void Thread$join(pthread_t *thread);
+void Thread$detach(pthread_t *thread);
+CORD Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type);
+
+extern TypeInfo Thread;
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/tomo.h b/builtins/tomo.h
index 595d6310..bbf48e2a 100644
--- a/builtins/tomo.h
+++ b/builtins/tomo.h
@@ -12,6 +12,7 @@
#include "array.h"
#include "bool.h"
#include "c_string.h"
+#include "channel.h"
#include "datatypes.h"
#include "functions.h"
#include "halfsiphash.h"
@@ -23,6 +24,7 @@
#include "range.h"
#include "table.h"
#include "text.h"
+#include "thread.h"
#include "types.h"
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/types.h b/builtins/types.h
index 4184e8fa..70f8dc00 100644
--- a/builtins/types.h
+++ b/builtins/types.h
@@ -18,7 +18,7 @@ typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*);
typedef struct TypeInfo {
int64_t size, align;
struct { // Anonymous tagged union for convenience
- enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag;
+ enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag;
union {
struct {
equal_fn_t equal;
@@ -36,7 +36,7 @@ typedef struct TypeInfo {
} TextInfo;
struct {
const struct TypeInfo *item;
- } ArrayInfo;
+ } ArrayInfo, ChannelInfo;
struct {
const struct TypeInfo *key, *value;
} TableInfo;
@@ -60,6 +60,8 @@ typedef struct TypeInfo {
.tag=ArrayInfo, .ArrayInfo.item=item_info})
#define $SetInfo(item_info) &((TypeInfo){.size=sizeof(table_t), .align=__alignof__(table_t), \
.tag=TableInfo, .TableInfo.key=item_info, .TableInfo.value=&$Void})
+#define $ChannelInfo(item_info) &((TypeInfo){.size=sizeof(channel_t), .align=__alignof__(channel_t), \
+ .tag=ChannelInfo, .ChannelInfo.item=item_info})
#define $TableInfo(key_expr, value_expr) &((TypeInfo){.size=sizeof(table_t), .align=__alignof__(table_t), \
.tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr})
#define $FunctionInfo(typestr) &((TypeInfo){.size=sizeof(void*), .align=__alignof__(void*), \