diff --git a/Makefile b/Makefile index d76990d..924aa7f 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ LDLIBS=-lgc -lcord -lm -lunistring -lgmp LIBTOMO_FLAGS=-shared ifeq ($(OS),OpenBSD) - LDLIBS += -lpthread -lexecinfo + LDLIBS += -lexecinfo endif ifeq ($(OS),Darwin) @@ -107,7 +107,7 @@ clean: examples: examples/base64/base64 examples/ini/ini examples/game/game \ examples/tomodeps/tomodeps examples/tomo-install/tomo-install examples/wrap/wrap examples/colorful/colorful ./build/tomo -qIL examples/time examples/commands examples/shell examples/base64 examples/log examples/ini examples/vectors examples/game \ - examples/http examples/threads examples/tomodeps examples/tomo-install examples/wrap examples/pthreads examples/colorful + examples/http examples/tomodeps examples/tomo-install examples/wrap examples/pthreads examples/colorful ./build/tomo examples/learnxiny.tm deps: check-gcc diff --git a/README.md b/README.md index 98dc31b..000013e 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,6 @@ of many language features or the other example programs/modules in - Built-in doctests with syntax highlighting - [Automatic command line argument parsing with type safety](docs/command-line-parsing.md) - [Easy interoperability with C](docs/c-interoperability.md) -- Support for [POSIX threads](docs/threads.tm) and mutex-guarded datastructures. - Built-in [data serialization and deserialization](docs/serialization.md). ## Dependencies diff --git a/docs/README.md b/docs/README.md index 0034ab8..f788432 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,7 +25,6 @@ Information about Tomo's built-in types can be found here: - [Floating point numbers](nums.md) - [Integers](integers.md) - [Languages](langs.md) -- [Mutexed Data](mutexed.md) - [Paths](paths.md) - [Random Number Generators](rng.md) - [Sets](sets.md) @@ -33,7 +32,6 @@ Information about Tomo's built-in types can be found here: - [Tables](tables.md) - [Text](text.md) - [Text Pattern Matching](patterns.md) -- [Threads](threads.md) ## Built-in Functions diff --git a/docs/mutexed.md b/docs/mutexed.md deleted file mode 100644 index 97357f3..0000000 --- a/docs/mutexed.md +++ /dev/null @@ -1,34 +0,0 @@ -# Mutexed Data - -To serve the general case of synchronizing access to shared datastructures, -Tomo uses the `mutexed` keyword, which allocates a mutex and some heap memory -for a value. Access to the heap-allocated value's memory can only be obtained -by using a `holding` block. `holding` blocks ensure that the underlying mutex -is locked before entering the block and unlocked before leaving it (even if a -short-circuiting control flow statement like `return` or `stop` is used). Here -is a simple example: - -```tomo -nums := mutexed [10, 20, 30] - ->> nums -= mutexed [Int]<0x12345678> : mutexed([Int]) - -holding nums: - # Inside this block, the type of `nums` is `&[Int]` - >> nums - = &[10, 20, 30] : &[Int] - -thread := Thread.new(func(): - holding nums: - nums:insert(30) -) - -holding nums: - nums:insert(40) - -thread:join() -``` - -Without using a mutex, the code above could run into concurrency issues leading -to data corruption. diff --git a/docs/serialization.md b/docs/serialization.md index 764a6b2..0f158be 100644 --- a/docs/serialization.md +++ b/docs/serialization.md @@ -70,7 +70,6 @@ only 9 bytes for the whole thing! ## Unserializable Types -Unfortunately, not all types can be easily serialized. In particular, -`Thread`s, types, and functions cannot be serialized because their data -contents cannot be easily converted to portable byte arrays. All other -datatypes _can_ be serialized. +Unfortunately, not all types can be easily serialized. In particular, types and +functions cannot be serialized because their data contents cannot be easily +converted to portable byte arrays. All other datatypes _can_ be serialized. diff --git a/docs/threads.md b/docs/threads.md deleted file mode 100644 index 3bd2dd0..0000000 --- a/docs/threads.md +++ /dev/null @@ -1,93 +0,0 @@ -# Threads - -Tomo supports POSIX threads (pthreads) through the `Thread` type. The -recommended practice is to have each thread interact with other threads only -through [mutex-guarded datastructures](mutexed.md). - -## Thread Methods - -- [`func cancel(thread: Thread)`](#cancel) -- [`func detach(thread: Thread)`](#detach) -- [`func join(thread: Thread)`](#join) -- [`func new(fn: func(->Void) -> Thread)`](#new) - -### `cancel` -Requests the cancellation of a specified thread. - -```tomo -func cancel(thread: Thread) -``` - -- `thread`: The thread to cancel. - -**Returns:** -Nothing. - -**Example:** -```tomo ->> thread:cancel() -``` - ---- - -### `detach` -Detaches a specified thread, allowing it to run independently. - -```tomo -func detach(thread: Thread) -``` - -- `thread`: The thread to detach. - -**Returns:** -Nothing. - -**Example:** -```tomo ->> thread:detach() -``` -### `join` -Waits for a specified thread to terminate. - -```tomo -func join(thread: Thread) -``` - -- `thread`: The thread to join. - -**Returns:** -Nothing. - -**Example:** -```tomo ->> thread:join() -``` - ---- - -### `new` -Creates a new thread to execute a specified function. - -```tomo -func new(fn: func(->Void) -> Thread) -``` - -- `fn`: The function to be executed by the new thread. - -**Returns:** -A new `Thread` object representing the created thread. - -**Example:** -```tomo ->> jobs := |Int| ->> results := |Int| ->> thread := Thread.new(func(): - repeat: - input := jobs:get() - results:give(input + 10 -) -= Thread<0x12345678> ->> jobs:give(10) ->> results:get() -= 11 -``` diff --git a/examples/threads/threads.tm b/examples/threads/threads.tm deleted file mode 100644 index 124515b..0000000 --- a/examples/threads/threads.tm +++ /dev/null @@ -1,106 +0,0 @@ -use - -struct Mutex(_mutex:@Memory): - func new(->Mutex): - return Mutex( - inline C : @Memory { - pthread_mutex_t *mutex = GC_MALLOC(sizeof(pthread_mutex_t)); - pthread_mutex_init(mutex, NULL); - GC_register_finalizer(mutex, (void*)pthread_mutex_destroy, NULL, NULL, NULL); - mutex - } - ) - - func do_locked(m:Mutex, fn:func(); inline): - inline C { - pthread_mutex_lock((pthread_mutex_t*)_$m._mutex); - } - fn() - inline C { - pthread_mutex_unlock((pthread_mutex_t*)_$m._mutex); - } - -struct ThreadCondition(_cond:@Memory): - func new(->ThreadCondition): - return ThreadCondition( - inline C : @Memory { - pthread_cond_t *cond = GC_MALLOC(sizeof(pthread_cond_t)); - pthread_cond_init(cond, NULL); - GC_register_finalizer(cond, (void*)pthread_cond_destroy, NULL, NULL, NULL); - cond - } - ) - - func wait(c:ThreadCondition, m:Mutex; inline): - inline C { - pthread_cond_wait((pthread_cond_t*)_$c._cond, (pthread_mutex_t*)_$m._mutex); - } - - func signal(c:ThreadCondition; inline): - inline C { - pthread_cond_signal((pthread_cond_t*)_$c._cond); - } - - func broadcast(c:ThreadCondition; inline): - inline C { - pthread_cond_broadcast((pthread_cond_t*)_$c._cond); - } - -struct Guard(mutex=Mutex.new(), cond=ThreadCondition.new()): - func guarded(g:Guard, fn:func(); inline): - g.mutex:do_locked(fn) - g.cond:signal() - - func wait(g:Guard): - g.cond:wait(g.mutex) - -struct PThread(_thread:@Memory): - func new(fn:func() -> PThread): - return PThread( - inline C : @Memory { - pthread_t *thread = GC_MALLOC(sizeof(pthread_t)); - pthread_create(thread, NULL, _$fn.fn, _$fn.userdata); - thread - } - ) - - func join(t:PThread): - inline C { - pthread_join(*(pthread_t*)_$t._thread, NULL); - } - - func cancel(t:PThread): - inline C { - pthread_cancel(*(pthread_t*)_$t._thread); - } - - func detatch(t:PThread): - inline C { - pthread_detach(*(pthread_t*)_$t._thread); - } - -func main(): - g := Guard() - queue := @[10, 20] - - t := PThread.new(func(): - say("In another thread!") - item := @none:Int - while item[] != 30: - g:guarded(func(): - while queue.length == 0: - g:wait() - - item[] = queue[1] - queue:remove_at(1) - ) - say("Processing: $item") - sleep(0.01) - say("All done!") - ) - >> t - >> sleep(1) - >> g:guarded(func(): - queue:insert(30) - ) - >> t:join() diff --git a/src/ast.c b/src/ast.c index 00f03a6..5f4e24f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -116,8 +116,6 @@ CORD ast_to_xml(ast_t *ast) T(Not, "%r", ast_to_xml(data.value)) T(HeapAllocate, "%r", ast_to_xml(data.value)) T(StackReference, "%r", ast_to_xml(data.value)) - T(Mutexed, "%r", ast_to_xml(data.value)) - T(Holding, "%r%r", ast_to_xml(data.mutexed), ast_to_xml(data.body)) T(Min, "%r%r%r", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key)) T(Max, "%r%r%r", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key)) T(Array, "%r%r", optional_tagged_type("item-type", data.item_type), ast_list_to_xml(data.items)) @@ -192,7 +190,6 @@ CORD type_ast_to_xml(type_ast_t *t) T(TableTypeAST, "%r %r", type_ast_to_xml(data.key), type_ast_to_xml(data.value)) T(FunctionTypeAST, "%r %r", arg_list_to_xml(data.args), type_ast_to_xml(data.ret)) T(OptionalTypeAST, "%r", data.type) - T(MutexedTypeAST, "%r", data.type) #undef T default: return CORD_EMPTY; } diff --git a/src/ast.h b/src/ast.h index 2260436..b5b1ad3 100644 --- a/src/ast.h +++ b/src/ast.h @@ -75,7 +75,6 @@ typedef enum { TableTypeAST, FunctionTypeAST, OptionalTypeAST, - MutexedTypeAST, } type_ast_e; typedef struct tag_ast_s { @@ -114,7 +113,7 @@ struct type_ast_s { } FunctionTypeAST; struct { type_ast_t *type; - } OptionalTypeAST, MutexedTypeAST; + } OptionalTypeAST; } __data; }; @@ -126,7 +125,7 @@ typedef enum { Path, Declare, Assign, BinaryOp, UpdateAssign, - Not, Negative, HeapAllocate, StackReference, Mutexed, Holding, + Not, Negative, HeapAllocate, StackReference, Min, Max, Array, Set, Table, TableEntry, Comprehension, FunctionDef, Lambda, ConvertDef, @@ -194,10 +193,7 @@ struct ast_s { } BinaryOp, UpdateAssign; struct { ast_t *value; - } Not, Negative, HeapAllocate, StackReference, Mutexed; - struct { - ast_t *mutexed, *body; - } Holding; + } Not, Negative, HeapAllocate, StackReference; struct { ast_t *lhs, *rhs, *key; } Min, Max; diff --git a/src/compile.c b/src/compile.c index 9073de5..f228148 100644 --- a/src/compile.c +++ b/src/compile.c @@ -39,7 +39,7 @@ static CORD compile_string_literal(CORD literal); CORD promote_to_optional(type_t *t, CORD code) { - if (t == THREAD_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE) { + if (t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE) { return code; } else if (t->tag == IntType) { switch (Match(t, IntType)->bits) { @@ -228,18 +228,13 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, UpdateAssign)->rhs); break; } - case Not: case Negative: case HeapAllocate: case StackReference: case Mutexed: { + case Not: case Negative: case HeapAllocate: case StackReference: { // UNSAFE: ast_t *value = ast->__data.Not.value; // END UNSAFE add_closed_vars(closed_vars, enclosing_scope, env, value); break; } - case Holding: { - add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Holding)->mutexed); - add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Holding)->body); - break; - } case Min: { add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Min)->lhs); add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Min)->rhs); @@ -501,8 +496,7 @@ PUREFUNC CORD compile_unsigned_type(type_t *t) CORD compile_type(type_t *t) { - if (t == THREAD_TYPE) return "Thread_t"; - else if (t == RNG_TYPE) return "RNG_t"; + if (t == RNG_TYPE) return "RNG_t"; else if (t == MATCH_TYPE) return "Match_t"; else if (t == PATH_TYPE) return "Path_t"; else if (t == PATH_TYPE_TYPE) return "PathType_t"; @@ -512,7 +506,6 @@ CORD compile_type(type_t *t) case AbortType: return "void"; case VoidType: return "void"; case MemoryType: return "void"; - case MutexedType: return "MutexedData_t"; case BoolType: return "Bool_t"; case ByteType: return "Byte_t"; case CStringType: return "const char*"; @@ -556,7 +549,7 @@ CORD compile_type(type_t *t) case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; switch (nonnull->tag) { - case CStringType: case FunctionType: case ClosureType: case MutexedType: + case CStringType: case FunctionType: case ClosureType: case PointerType: case EnumType: return compile_type(nonnull); case TextType: @@ -565,8 +558,6 @@ CORD compile_type(type_t *t) case ArrayType: case TableType: case SetType: return CORD_all("Optional", compile_type(nonnull)); case StructType: { - if (nonnull == THREAD_TYPE) - return "Thread_t"; if (nonnull == MATCH_TYPE) return "OptionalMatch_t"; if (nonnull == PATH_TYPE) @@ -689,7 +680,7 @@ CORD optional_into_nonnone(type_t *t, CORD value) case IntType: return CORD_all(value, ".value"); case StructType: - if (t == THREAD_TYPE || t == MATCH_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE) + if (t == MATCH_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE) return value; return CORD_all(value, ".value"); default: @@ -702,8 +693,7 @@ CORD check_none(type_t *t, CORD value) t = Match(t, OptionalType)->type; // NOTE: these use statement expressions ({...;}) because some compilers // complain about excessive parens around equality comparisons - if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType - || t == THREAD_TYPE) + if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType) return CORD_all("({", value, " == NULL;})"); else if (t == MATCH_TYPE) return CORD_all("({(", value, ").index.small == 0;})"); @@ -729,8 +719,6 @@ CORD check_none(type_t *t, CORD value) return CORD_all("(", value, ").is_none"); else if (t->tag == EnumType) return CORD_all("({(", value, ").$tag == 0;})"); - else if (t->tag == MutexedType) - return CORD_all("({", value, " == NULL;})"); print_err("Optional check not implemented for: ", type_to_str(t)); } @@ -1344,30 +1332,6 @@ static CORD _compile_statement(env_t *env, ast_t *ast) loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;"); return loop; } - case Holding: { - ast_t *held = Match(ast, Holding)->mutexed; - type_t *held_type = get_type(env, held); - if (held_type->tag != MutexedType) - code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value"); - CORD code = CORD_all( - "{ // Holding\n", - "MutexedData_t mutexed = ", compile(env, held), ";\n", - "pthread_mutex_lock(&mutexed->mutex);\n"); - - env_t *body_scope = fresh_scope(env); - body_scope->deferred = new(deferral_t, .defer_env=env, - .block=FakeAST(InlineCCode, .code="pthread_mutex_unlock(&mutexed->mutex);"), - .next=body_scope->deferred); - if (held->tag == Var) { - CORD held_var = CORD_all(Match(held, Var)->name, "$held"); - set_binding(body_scope, Match(held, Var)->name, - Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), held_var); - code = CORD_all(code, compile_declaration(Type(PointerType, .pointed=Match(held_type, MutexedType)->type), held_var), - " = (", compile_type(Type(PointerType, .pointed=Match(held_type, MutexedType)->type)), ")mutexed->data;\n"); - } - return CORD_all(code, compile_statement(body_scope, Match(ast, Holding)->body), - "pthread_mutex_unlock(&mutexed->mutex);\n}"); - } case For: { auto for_ = Match(ast, For); @@ -1811,7 +1775,7 @@ CORD expr_as_text(CORD expr, type_t *t, CORD color) case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); case OptionalType: return CORD_asprintf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case StructType: case EnumType: case MutexedType: + case StructType: case EnumType: return CORD_asprintf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t)); } @@ -2199,8 +2163,7 @@ CORD compile_none(type_t *t) if (t->tag == OptionalType) t = Match(t, OptionalType)->type; - if (t == THREAD_TYPE) return "NULL"; - else if (t == PATH_TYPE) return "NONE_PATH"; + if (t == PATH_TYPE) return "NONE_PATH"; else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})"; else if (t == MATCH_TYPE) return "NONE_MATCH"; @@ -2231,7 +2194,6 @@ CORD compile_none(type_t *t) env_t *enum_env = Match(t, EnumType)->env; return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env, enum_env->namespace), "null})"); } - case MutexedType: return "NONE_MUTEXED_DATA"; default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_str(t)); } } @@ -2339,36 +2301,6 @@ CORD compile(env_t *env, ast_t *ast) else return CORD_all("stack(", compile(env, subject), ")"); } - case Mutexed: { - ast_t *mutexed = Match(ast, Mutexed)->value; - return CORD_all("new(struct MutexedData_s, .mutex=PTHREAD_MUTEX_INITIALIZER, .data=", compile(env, WrapAST(mutexed, HeapAllocate, mutexed)), ")"); - } - case Holding: { - ast_t *held = Match(ast, Holding)->mutexed; - type_t *held_type = get_type(env, held); - if (held_type->tag != MutexedType) - code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value"); - CORD code = CORD_all( - "({ // Holding\n", - "MutexedData_t mutexed = ", compile(env, held), ";\n", - "pthread_mutex_lock(&mutexed->mutex);\n"); - - env_t *body_scope = fresh_scope(env); - body_scope->deferred = new(deferral_t, .defer_env=env, - .block=FakeAST(InlineCCode, .code="pthread_mutex_unlock(&mutexed->mutex);"), - .next=body_scope->deferred); - if (held->tag == Var) { - CORD held_var = CORD_all(Match(held, Var)->name, "$held"); - set_binding(body_scope, Match(held, Var)->name, - Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), held_var); - code = CORD_all(code, compile_declaration(Type(PointerType, .pointed=Match(held_type, MutexedType)->type), held_var), - " = (", compile_type(Type(PointerType, .pointed=Match(held_type, MutexedType)->type)), ")mutexed->data;\n"); - } - type_t *body_type = get_type(env, ast); - return CORD_all(code, compile_declaration(body_type, "result"), " = ", compile(body_scope, Match(ast, Holding)->body), ";\n" - "pthread_mutex_unlock(&mutexed->mutex);\n" - "result;\n})"); - } case Optional: { ast_t *value = Match(ast, Optional)->value; CORD value_code = compile(env, value); @@ -3829,8 +3761,7 @@ CORD compile(env_t *env, ast_t *ast) CORD compile_type_info(type_t *t) { - if (t == THREAD_TYPE) return "&Thread$info"; - else if (t == RNG_TYPE) return "&RNG$info"; + if (t == RNG_TYPE) return "&RNG$info"; else if (t == MATCH_TYPE) return "&Match$info"; else if (t == PATH_TYPE) return "&Path$info"; else if (t == PATH_TYPE_TYPE) return "&PathType$info"; @@ -3890,10 +3821,6 @@ CORD compile_type_info(type_t *t) type_t *non_optional = Match(t, OptionalType)->type; return CORD_asprintf("Optional$info(sizeof(%r), __alignof__(%r), %r)", compile_type(non_optional), compile_type(non_optional), compile_type_info(non_optional)); } - case MutexedType: { - type_t *mutexed = Match(t, MutexedType)->type; - return CORD_all("MutexedData$info(", compile_type_info(mutexed), ")"); - } case TypeInfoType: return CORD_all("Type$info(", CORD_quoted(type_to_cord(Match(t, TypeInfoType)->type)), ")"); case MemoryType: return "&Memory$info"; case VoidType: return "&Void$info"; diff --git a/src/environment.c b/src/environment.c index 77f91f1..e2e7e1d 100644 --- a/src/environment.c +++ b/src/environment.c @@ -16,7 +16,6 @@ type_t *TEXT_TYPE = NULL; type_t *MATCH_TYPE = NULL; type_t *RNG_TYPE = NULL; public type_t *PATH_TYPE = NULL; -public type_t *THREAD_TYPE = NULL; public type_t *PATH_TYPE_TYPE = NULL; static type_t *declare_type(env_t *env, const char *def_str) @@ -70,7 +69,6 @@ env_t *global_env(void) PATH_TYPE_TYPE = declare_type(env, "enum PathType(Relative, Absolute, Home)"); MATCH_TYPE = declare_type(env, "struct Match(text:Text, index:Int, captures:[Text])"); PATH_TYPE = declare_type(env, "struct Path(type:PathType, components:[Text])"); - THREAD_TYPE = declare_type(env, "struct Thread(; opaque)"); RNG_TYPE = declare_type(env, "struct RNG(state:@Memory)"); typedef struct { @@ -394,12 +392,6 @@ env_t *global_env(void) {"utf32_codepoints", "Text$utf32_codepoints", "func(text:Text -> [Int32])"}, {"width", "Text$width", "func(text:Text, language='C' -> Int)"}, )}, - {"Thread", THREAD_TYPE, "Thread_t", "Thread", TypedArray(ns_entry_t, - {"new", "Thread$new", "func(fn:func() -> Thread)"}, - {"cancel", "Thread$cancel", "func(thread:Thread)"}, - {"join", "Thread$join", "func(thread:Thread)"}, - {"detach", "Thread$detach", "func(thread:Thread)"}, - )}, }; for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) { @@ -535,7 +527,6 @@ env_t *global_env(void) {"Int$value_as_text", "func(i:Int -> Path)"}); ADD_CONSTRUCTORS("CString", {"Text$as_c_string", "func(text:Text -> CString)"}); ADD_CONSTRUCTORS("RNG", {"RNG$new", "func(-> RNG)"}); - ADD_CONSTRUCTORS("Thread", {"Thread$new", "func(fn:func() -> Thread)"}); #undef ADD_CONSTRUCTORS set_binding(namespace_env(env, "Path"), "from_text", diff --git a/src/environment.h b/src/environment.h index 549df87..95e3c3e 100644 --- a/src/environment.h +++ b/src/environment.h @@ -93,6 +93,5 @@ extern type_t *MATCH_TYPE; extern type_t *RNG_TYPE; extern type_t *PATH_TYPE; extern type_t *PATH_TYPE_TYPE; -extern type_t *THREAD_TYPE; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/parse.c b/src/parse.c index 4ace5a6..14221cc 100644 --- a/src/parse.c +++ b/src/parse.c @@ -63,8 +63,8 @@ int op_tightness[] = { static const char *keywords[] = { "yes", "xor", "while", "when", "use", "unless", "struct", "stop", "skip", "return", - "or", "not", "none", "no", "mutexed", "mod1", "mod", "pass", "lang", "inline", "in", "if", - "holding", "func", "for", "extern", "enum", "else", "do", "deserialize", "defer", "and", + "or", "not", "none", "no", "mod1", "mod", "pass", "lang", "inline", "in", "if", + "func", "for", "extern", "enum", "else", "do", "deserialize", "defer", "and", "_min_", "_max_", NULL, }; @@ -94,7 +94,6 @@ static type_ast_t *parse_array_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos); -static type_ast_t *parse_mutexed_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos); static type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos); @@ -116,13 +115,11 @@ static PARSER(parse_file_body); static PARSER(parse_for); static PARSER(parse_func_def); static PARSER(parse_heap_alloc); -static PARSER(parse_holding); static PARSER(parse_if); static PARSER(parse_inline_c); static PARSER(parse_int); static PARSER(parse_lambda); static PARSER(parse_lang_def); -static PARSER(parse_mutexed); static PARSER(parse_namespace); static PARSER(parse_negative); static PARSER(parse_not); @@ -573,19 +570,6 @@ type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) { return ptr_type; } -type_ast_t *parse_mutexed_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match_word(&pos, "mutexed")) return NULL; - spaces(&pos); - if (!match(&pos, "(")) return NULL; - spaces(&pos); - type_ast_t *mutexed = expect(ctx, start, &pos, parse_type, - "I couldn't parse a mutexed type after this point"); - spaces(&pos); - if (!match(&pos, ")")) return NULL; - return NewTypeAST(ctx->file, start, pos, MutexedTypeAST, .type=mutexed); -} - type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) { const char *start = pos; const char *id = get_id(&pos); @@ -612,7 +596,6 @@ type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) { || (type=parse_set_type(ctx, pos)) || (type=parse_type_name(ctx, pos)) || (type=parse_func_type(ctx, pos)) - || (type=parse_mutexed_type(ctx, pos)) ); if (!success && match(&pos, "(")) { whitespace(&pos); @@ -1190,23 +1173,6 @@ PARSER(parse_stack_reference) { return ast; } -PARSER(parse_mutexed) { - const char *start = pos; - if (!match_word(&pos, "mutexed")) return NULL; - spaces(&pos); - ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this 'mutexed'"); - return NewAST(ctx->file, start, pos, Mutexed, .value=val); -} - -PARSER(parse_holding) { - const char *start = pos; - if (!match_word(&pos, "holding")) return NULL; - spaces(&pos); - ast_t *mutexed = expect(ctx, start, &pos, parse_expr, "I expected an expression for this 'holding'"); - ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a block to be here"); - return NewAST(ctx->file, start, pos, Holding, .mutexed=mutexed, .body=body); -} - PARSER(parse_not) { const char *start = pos; if (!match_word(&pos, "not")) return NULL; @@ -1526,7 +1492,6 @@ PARSER(parse_term_no_suffix) { || (term=parse_stop(ctx, pos)) || (term=parse_return(ctx, pos)) || (term=parse_not(ctx, pos)) - || (term=parse_mutexed(ctx, pos)) || (term=parse_extern(ctx, pos)) || (term=parse_inline_c(ctx, pos)) ); @@ -1858,7 +1823,6 @@ PARSER(parse_extended_expr) { || (expr=optional(ctx, &pos, parse_when)) || (expr=optional(ctx, &pos, parse_repeat)) || (expr=optional(ctx, &pos, parse_do)) - || (expr=optional(ctx, &pos, parse_holding)) ) return expr; diff --git a/src/stdlib/README.md b/src/stdlib/README.md index 1583c16..6591ead 100644 --- a/src/stdlib/README.md +++ b/src/stdlib/README.md @@ -31,5 +31,4 @@ some common functionality. - Pointers: [pointers.h](pointers.h), [pointers.c](pointers.c) - Tables: [tables.h](tables.h), [tables.c](tables.c) - Text: [text.h](text.h), [text.c](text.c) -- Threads: [threads.h](threads.h), [threads.c](threads.c) - Type Infos (for representing types as values): [types.h](types.h), [types.c](types.c) diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index 22cee67..b1265fc 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -3,7 +3,6 @@ // Common datastructures (arrays, tables, closures) #include -#include #include #include #include @@ -111,11 +110,6 @@ typedef struct { typedef struct RNGState_t* RNG_t; -typedef struct MutexedData_s { - pthread_mutex_t mutex; - void *data; -} *MutexedData_t; - #define OptionalBool_t uint8_t #define OptionalArray_t Array_t #define OptionalTable_t Table_t diff --git a/src/stdlib/mutexeddata.c b/src/stdlib/mutexeddata.c deleted file mode 100644 index ead154e..0000000 --- a/src/stdlib/mutexeddata.c +++ /dev/null @@ -1,39 +0,0 @@ -// Mutexed data methods/type info -#include -#include -#include -#include -#include -#include -#include - -#include "bools.h" -#include "metamethods.h" -#include "optionals.h" -#include "text.h" -#include "util.h" - -static Text_t MutexedData$as_text(const void *m, bool colorize, const TypeInfo_t *type) -{ - auto mutexed = type->MutexedDataInfo; - Text_t typename = generic_as_text(NULL, false, mutexed.type); - if (!m) { - return Texts(colorize ? Text("\x1b[34;1mmutexed\x1b[m(") : Text("mutexed("), typename, Text(")")); - } - return Texts(colorize ? Text("\x1b[34;1mmutexed ") : Text("mutexed "), typename, - Text$format(colorize ? "<%p>\x1b[m" : "<%p>", *((MutexedData_t*)m))); -} - -static bool MutexedData$is_none(const void *m, const TypeInfo_t *) -{ - return *((MutexedData_t*)m) == NULL; -} - -public const metamethods_t MutexedData$metamethods = { - .as_text=MutexedData$as_text, - .is_none=MutexedData$is_none, - .serialize=cannot_serialize, - .deserialize=cannot_deserialize, -}; - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/mutexeddata.h b/src/stdlib/mutexeddata.h deleted file mode 100644 index 4768619..0000000 --- a/src/stdlib/mutexeddata.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// Metamethods and type info for mutexed data - -#include "types.h" -#include "optionals.h" -#include "util.h" - -#define NONE_MUTEXED_DATA ((MutexedData_t)NULL) - -extern const metamethods_t MutexedData$metamethods; - -#define MutexedData$info(t) &((TypeInfo_t){.size=sizeof(MutexedData_t), .align=__alignof(MutexedData_t), \ - .tag=MutexedDataInfo, .MutexedDataInfo.type=t, \ - .metamethods=MutexedData$metamethods}) - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c index db2c477..797cb11 100644 --- a/src/stdlib/optionals.c +++ b/src/stdlib/optionals.c @@ -1,7 +1,5 @@ // Optional types -#include - #include "bools.h" #include "bytes.h" #include "datatypes.h" @@ -10,7 +8,6 @@ #include "nums.h" #include "patterns.h" #include "text.h" -#include "threads.h" #include "util.h" public PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type) diff --git a/src/stdlib/threads.c b/src/stdlib/threads.c deleted file mode 100644 index 05f5a94..0000000 --- a/src/stdlib/threads.c +++ /dev/null @@ -1,92 +0,0 @@ -// Logic for the Thread type, representing a pthread - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arrays.h" -#include "datatypes.h" -#include "metamethods.h" -#include "rng.h" -#include "text.h" -#include "threads.h" -#include "types.h" -#include "util.h" - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) -static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { - (void)flags; - arc4random_buf(buf, buflen); - return buflen; -} -#elif defined(__linux__) -// Use getrandom() -# include -#else - #error "Unsupported platform for secure random number generation" -#endif - -static void *run_thread(Closure_t *closure) -{ - uint8_t *random_bytes = GC_MALLOC_ATOMIC(40); - getrandom(random_bytes, 40, 0); - Array_t rng_seed = {.length=40, .data=random_bytes, .stride=1, .atomic=1}; - default_rng = RNG$new(rng_seed); - ((void(*)(void*))closure->fn)(closure->userdata); - return NULL; -} - -public Thread_t Thread$new(Closure_t fn) -{ - Thread_t thread = GC_MALLOC(sizeof(pthread_t)); - Closure_t *closure = new(Closure_t, .fn=fn.fn, .userdata=fn.userdata); - pthread_create(thread, NULL, (void*)run_thread, closure); - return thread; -} - -public void Thread$join(Thread_t thread) -{ - pthread_join(*thread, NULL); -} - -public void Thread$cancel(Thread_t thread) -{ - pthread_cancel(*thread); -} - -public void Thread$detach(Thread_t thread) -{ - pthread_detach(*thread); -} - -Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t*) -{ - if (!thread) { - return colorize ? Text("\x1b[34;1mThread\x1b[m") : Text("Thread"); - } - return Text$format(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *(Thread_t**)thread); -} - -static bool Thread$is_none(const void *obj, const TypeInfo_t*) -{ - return *(Thread_t*)obj == NULL; -} - -public const TypeInfo_t Thread$info = { - .size=sizeof(Thread_t), .align=__alignof(Thread_t), - .metamethods={ - .as_text=Thread$as_text, - .is_none=Thread$is_none, - .serialize=cannot_serialize, - .deserialize=cannot_deserialize, - }, -}; - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/threads.h b/src/stdlib/threads.h deleted file mode 100644 index 9f1c3d3..0000000 --- a/src/stdlib/threads.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -// Logic for the Thread type, representing a pthread - -#include -#include - -#include "datatypes.h" -#include "types.h" -#include "util.h" - -#define Thread_t pthread_t* - -Thread_t Thread$new(Closure_t fn); -void Thread$cancel(Thread_t thread); -void Thread$join(Thread_t thread); -void Thread$detach(Thread_t thread); -Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t *type); - -extern const TypeInfo_t Thread$info; - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/tomo.h b/src/stdlib/tomo.h index 16e5ec5..4aa1253 100644 --- a/src/stdlib/tomo.h +++ b/src/stdlib/tomo.h @@ -17,7 +17,6 @@ #include "integers.h" #include "memory.h" #include "metamethods.h" -#include "mutexeddata.h" #include "nums.h" #include "optionals.h" #include "paths.h" @@ -29,7 +28,6 @@ #include "structs.h" #include "tables.h" #include "text.h" -#include "threads.h" #include "types.h" // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/types.h b/src/stdlib/types.h index c7b938a..786e92d 100644 --- a/src/stdlib/types.h +++ b/src/stdlib/types.h @@ -30,7 +30,7 @@ struct TypeInfo_s { metamethods_t metamethods; struct { // Anonymous tagged union for convenience enum { OpaqueInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo, - OptionalInfo, MutexedDataInfo, TypeInfoInfo } tag; + OptionalInfo, TypeInfoInfo } tag; union { struct {} OpaqueInfo; struct { @@ -54,7 +54,7 @@ struct TypeInfo_s { } TypeInfoInfo; struct { const TypeInfo_t *type; - } OptionalInfo, MutexedDataInfo; + } OptionalInfo; struct { const char *name; int num_tags; diff --git a/src/tomo.c b/src/tomo.c index e6a6bec..b91d45e 100644 --- a/src/tomo.c +++ b/src/tomo.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) #endif #ifdef __OpenBSD__ - ldlibs = Texts(ldlibs, Text(" -lexecinfo -lpthread")); + ldlibs = Texts(ldlibs, Text(" -lexecinfo")); #endif USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO); diff --git a/src/typecheck.c b/src/typecheck.c index 5da8444..0bfe6a0 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -128,13 +128,6 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) code_err(ast, "Nested optional types are not currently supported"); return Type(OptionalType, .type=t); } - case MutexedTypeAST: { - type_ast_t *mutexed = Match(ast, MutexedTypeAST)->type; - type_t *t = parse_type_ast(env, mutexed); - if (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType) - code_err(ast, "Mutexed ", type_to_str(t), " types are not supported."); - return Type(MutexedType, .type=t); - } case UnknownTypeAST: code_err(ast, "I don't know how to get this type"); } #ifdef __GNUC__ @@ -1027,21 +1020,6 @@ type_t *get_type(env_t *env, ast_t *ast) } code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ", type_to_str(t)); } - case Mutexed: { - type_t *item_type = get_type(env, Match(ast, Mutexed)->value); - return Type(MutexedType, .type=item_type); - } - case Holding: { - ast_t *held = Match(ast, Holding)->mutexed; - type_t *held_type = get_type(env, held); - if (held_type->tag != MutexedType) - code_err(held, "This is a ", type_to_str(held_type), ", not a mutexed value"); - if (held->tag == Var) { - env = fresh_scope(env); - set_binding(env, Match(held, Var)->name, Type(PointerType, .pointed=Match(held_type, MutexedType)->type, .is_stack=true), CORD_EMPTY); - } - return get_type(env, Match(ast, Holding)->body); - } case BinaryOp: { auto binop = Match(ast, BinaryOp); type_t *lhs_t = get_type(env, binop->lhs), diff --git a/src/types.c b/src/types.c index 07b6ced..c4155c8 100644 --- a/src/types.c +++ b/src/types.c @@ -84,13 +84,6 @@ CORD type_to_cord(type_t *t) { else return "(Unknown optional type)"; } - case MutexedType: { - type_t *opt = Match(t, MutexedType)->type; - if (opt) - return CORD_all("mutexed ", type_to_cord(opt)); - else - return "(Unknown optional type)"; - } case TypeInfoType: { return CORD_all("Type$info(", Match(t, TypeInfoType)->name, ")"); } @@ -250,7 +243,6 @@ PUREFUNC bool has_heap_memory(type_t *t) case SetType: return true; case PointerType: return true; case OptionalType: return has_heap_memory(Match(t, OptionalType)->type); - case MutexedType: return true; case BigIntType: return true; case StructType: { for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) { @@ -276,7 +268,6 @@ PUREFUNC bool has_stack_memory(type_t *t) switch (t->tag) { case PointerType: return Match(t, PointerType)->is_stack; case OptionalType: return has_stack_memory(Match(t, OptionalType)->type); - case MutexedType: return has_stack_memory(Match(t, MutexedType)->type); default: return false; } } @@ -483,7 +474,6 @@ PUREFUNC size_t unpadded_struct_size(type_t *t) PUREFUNC size_t type_size(type_t *t) { - if (t == THREAD_TYPE) return sizeof(pthread_t*); if (t == PATH_TYPE) return sizeof(Path_t); if (t == PATH_TYPE_TYPE) return sizeof(PathType_t); #ifdef __GNUC__ @@ -514,7 +504,6 @@ PUREFUNC size_t type_size(type_t *t) case FunctionType: return sizeof(void*); case ClosureType: return sizeof(struct {void *fn, *userdata;}); case PointerType: return sizeof(void*); - case MutexedType: return sizeof(MutexedData_t); case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; switch (nonnull->tag) { @@ -575,7 +564,6 @@ PUREFUNC size_t type_size(type_t *t) PUREFUNC size_t type_align(type_t *t) { - if (t == THREAD_TYPE) return __alignof__(pthread_t*); if (t == PATH_TYPE) return __alignof__(Path_t); if (t == PATH_TYPE_TYPE) return __alignof__(PathType_t); #ifdef __GNUC__ @@ -606,7 +594,6 @@ PUREFUNC size_t type_align(type_t *t) case FunctionType: return __alignof__(void*); case ClosureType: return __alignof__(struct {void *fn, *userdata;}); case PointerType: return __alignof__(void*); - case MutexedType: return __alignof__(MutexedData_t); case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; switch (nonnull->tag) { diff --git a/src/types.h b/src/types.h index ae34c21..a5b2ad0 100644 --- a/src/types.h +++ b/src/types.h @@ -57,7 +57,6 @@ struct type_s { EnumType, OptionalType, TypeInfoType, - MutexedType, ModuleType, } tag; @@ -116,7 +115,7 @@ struct type_s { } EnumType; struct { type_t *type; - } OptionalType, MutexedType; + } OptionalType; struct { const char *name; type_t *type; diff --git a/test/optionals.tm b/test/optionals.tm index 58f1b98..0281744 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -61,18 +61,6 @@ func maybe_c_string(should_i:Bool->CString?): else: return none -func maybe_thread(should_i:Bool->Thread?): - if should_i: - return Thread.new(func(): pass) - else: - return none - -func maybe_mutexed(should_i:Bool->mutexed(Bool)?): - if should_i: - return mutexed no - else: - return none - func main(): >> 5? = 5? @@ -244,33 +232,6 @@ func main(): fail("Truthy: $nope") else: !! Falsey: $nope - do: - !! ... - !! Threads: - >> yep := maybe_thread(yes) - # No "=" test here because threads use addresses in the text version - >> nope := maybe_thread(no) - = none : Thread - >> if yep: >> yep - else: fail("Falsey: $yep") - >> if nope: - fail("Truthy: $nope") - else: !! Falsey: $nope - - do: - !! ... - !! Mutexed: - >> yep := maybe_mutexed(yes) - # No "=" test here because threads use addresses in the text version - >> nope := maybe_mutexed(no) - = none : mutexed(Bool) - >> if yep: >> yep - else: fail("Falsey: $yep") - >> if nope: - fail("Truthy: $nope") - else: !! Falsey: $nope - - if yep := maybe_int(yes): >> yep = 123 diff --git a/test/threads.tm b/test/threads.tm deleted file mode 100644 index adf7784..0000000 --- a/test/threads.tm +++ /dev/null @@ -1,70 +0,0 @@ -enum Job(Increment(x:Int), Decrement(x:Int)) - -func main(): - do: - >> nums := mutexed [10, 20, 30] - holding nums: - >> nums[] - = [10, 20, 30] - nums:insert(40) - - holding nums: - >> nums[] - = [10, 20, 30, 40] - - - jobs := mutexed [Job.Increment(5)] - - results := mutexed [:Int] - - >> thread := Thread.new(func(): - !! In another thread! - repeat: - job := holding jobs: (jobs:pop(1) or stop) - when job is Increment(x): - holding results: results:insert(x + 1) - is Decrement(x): - holding results: results:insert(x - 1) - ) - - holding jobs: - jobs:insert(Decrement(100)) - jobs:insert(Decrement(200)) - jobs:insert(Decrement(300)) - jobs:insert(Decrement(400)) - jobs:insert(Decrement(500)) - jobs:insert(Decrement(600)) - jobs:insert(Increment(1000)) - - dequeue_result := func(): - result := none:Int - repeat: - result = (holding results: results:pop(1)) - stop if result - sleep(0.00001) - return result! - - >> dequeue_result() - = 6 - >> dequeue_result() - = 99 - - >> dequeue_result() - = 199 - >> dequeue_result() - = 299 - >> dequeue_result() - = 399 - >> dequeue_result() - = 499 - >> dequeue_result() - = 599 - - >> dequeue_result() - = 1001 - - !! Canceling... - >> thread:cancel() - !! Joining... - >> thread:join() - !! Done!