From 2ecb5fe885042ca6c25ee0a3e3da070ddec9e07e Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 11 Aug 2024 14:47:34 -0400 Subject: Add channels and threads --- builtins/channel.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ builtins/channel.h | 25 +++++++++++++ builtins/datatypes.h | 7 ++++ builtins/functions.c | 5 +++ builtins/functions.h | 2 + builtins/thread.c | 57 ++++++++++++++++++++++++++++ builtins/thread.h | 21 +++++++++++ builtins/tomo.h | 2 + builtins/types.h | 6 ++- 9 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 builtins/channel.c create mode 100644 builtins/channel.h create mode 100644 builtins/thread.c create mode 100644 builtins/thread.h (limited to 'builtins') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#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 #include +#include #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 #include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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*), \ -- cgit v1.2.3