mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +00:00 
			
		
		
		
	Merge branch 'threads-3' of github.com:janet-lang/janet into threads-3
This commit is contained in:
		
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ INCLUDEDIR?=$(PREFIX)/include | |||||||
| BINDIR?=$(PREFIX)/bin | BINDIR?=$(PREFIX)/bin | ||||||
| LIBDIR?=$(PREFIX)/lib | LIBDIR?=$(PREFIX)/lib | ||||||
| JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\"" | JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1)\"" | ||||||
| CLIBS=-lm | CLIBS=-lm -lpthread | ||||||
| JANET_TARGET=build/janet | JANET_TARGET=build/janet | ||||||
| JANET_LIBRARY=build/libjanet.so | JANET_LIBRARY=build/libjanet.so | ||||||
| JANET_STATIC_LIBRARY=build/libjanet.a | JANET_STATIC_LIBRARY=build/libjanet.a | ||||||
| @@ -106,6 +106,7 @@ JANET_CORE_SOURCES=src/core/abstract.c \ | |||||||
| 				   src/core/struct.c \ | 				   src/core/struct.c \ | ||||||
| 				   src/core/symcache.c \ | 				   src/core/symcache.c \ | ||||||
| 				   src/core/table.c \ | 				   src/core/table.c \ | ||||||
|  | 				   src/core/thread.c \ | ||||||
| 				   src/core/tuple.c \ | 				   src/core/tuple.c \ | ||||||
| 				   src/core/typedarray.c \ | 				   src/core/typedarray.c \ | ||||||
| 				   src/core/util.c \ | 				   src/core/util.c \ | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								auxbin/jpm
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								auxbin/jpm
									
									
									
									
									
								
							| @@ -112,6 +112,12 @@ | |||||||
| (def default-linker (if is-win "link" "cc")) | (def default-linker (if is-win "link" "cc")) | ||||||
| (def default-archiver (if is-win "lib" "ar")) | (def default-archiver (if is-win "lib" "ar")) | ||||||
|  |  | ||||||
|  | # Detect threads | ||||||
|  | (def env (fiber/getenv (fiber/current))) | ||||||
|  | (def threads? (not (not (env 'thread/from-image)))) | ||||||
|  |  | ||||||
|  | (print "threads " threads?) | ||||||
|  |  | ||||||
| # Default flags for natives, but not required | # Default flags for natives, but not required | ||||||
| (def default-lflags (if is-win ["/nologo"] [])) | (def default-lflags (if is-win ["/nologo"] [])) | ||||||
| (def default-cflags | (def default-cflags | ||||||
| @@ -119,6 +125,10 @@ | |||||||
|     ["/nologo" "/MD"] |     ["/nologo" "/MD"] | ||||||
|     ["-std=c99" "-Wall" "-Wextra"])) |     ["-std=c99" "-Wall" "-Wextra"])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Link to pthreads | ||||||
|  | (def- thread-flags (if is-win [] (if threads? ["-lpthread"] []))) | ||||||
|  |  | ||||||
| # Required flags for dynamic libraries. These | # Required flags for dynamic libraries. These | ||||||
| # are used no matter what for dynamic libraries. | # are used no matter what for dynamic libraries. | ||||||
| (def- dynamic-cflags | (def- dynamic-cflags | ||||||
| @@ -127,10 +137,10 @@ | |||||||
|     ["-fPIC"])) |     ["-fPIC"])) | ||||||
| (def- dynamic-lflags | (def- dynamic-lflags | ||||||
|     (if is-win |     (if is-win | ||||||
|       ["/DLL"] |       ["/DLL" ;thread-flags] | ||||||
|       (if is-mac |       (if is-mac | ||||||
|         ["-shared" "-undefined" "dynamic_lookup"] |         ["-shared" "-undefined" "dynamic_lookup" ;thread-flags] | ||||||
|         ["-shared"]))) |         ["-shared" ;thread-flags]))) | ||||||
|  |  | ||||||
| (defn- opt | (defn- opt | ||||||
|   "Get an option, allowing overrides via dynamic bindings AND some |   "Get an option, allowing overrides via dynamic bindings AND some | ||||||
| @@ -497,11 +507,11 @@ int main(int argc, const char **argv) { | |||||||
| # Compile and link final exectable | # Compile and link final exectable | ||||||
| (do | (do | ||||||
|   (def extra-lflags (case (os/which) |   (def extra-lflags (case (os/which) | ||||||
|                       :macos ["-ldl" "-lm"] |                       :macos ["-ldl" "-lm" ;thread-flags] | ||||||
|                       :windows [] |                       :windows [;thread-flags] | ||||||
|                       :linux ["-lm" "-ldl" "-lrt"] |                       :linux ["-lm" "-ldl" "-lrt" ;thread-flags] | ||||||
|                       #default |                       #default | ||||||
|                       ["-lm"])) |                       ["-lm" ;thread-flags])) | ||||||
|   (def cc (opt opts :compiler default-compiler)) |   (def cc (opt opts :compiler default-compiler)) | ||||||
|   (def lflags [;dep-lflags ;(opt opts :lflags default-lflags) ;extra-lflags]) |   (def lflags [;dep-lflags ;(opt opts :lflags default-lflags) ;extra-lflags]) | ||||||
|   (def cflags (getcflags opts)) |   (def cflags (getcflags opts)) | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								meson.build
									
									
									
									
									
								
							| @@ -30,6 +30,7 @@ header_path = join_paths(get_option('prefix'), get_option('includedir'), 'janet' | |||||||
| cc = meson.get_compiler('c') | cc = meson.get_compiler('c') | ||||||
| m_dep = cc.find_library('m', required : false) | m_dep = cc.find_library('m', required : false) | ||||||
| dl_dep = cc.find_library('dl', required : false) | dl_dep = cc.find_library('dl', required : false) | ||||||
|  | thread_dep = dependency('threads') | ||||||
|  |  | ||||||
| # Link options | # Link options | ||||||
| if build_machine.system() != 'windows' | if build_machine.system() != 'windows' | ||||||
| @@ -128,6 +129,7 @@ core_src = [ | |||||||
|   'src/core/struct.c', |   'src/core/struct.c', | ||||||
|   'src/core/symcache.c', |   'src/core/symcache.c', | ||||||
|   'src/core/table.c', |   'src/core/table.c', | ||||||
|  |   'src/core/thread.c', | ||||||
|   'src/core/tuple.c', |   'src/core/tuple.c', | ||||||
|   'src/core/typedarray.c', |   'src/core/typedarray.c', | ||||||
|   'src/core/util.c', |   'src/core/util.c', | ||||||
| @@ -155,7 +157,7 @@ mainclient_src = [ | |||||||
| janet_boot = executable('janet-boot', core_src, boot_src, boot_gen, | janet_boot = executable('janet-boot', core_src, boot_src, boot_gen, | ||||||
|   include_directories : incdir, |   include_directories : incdir, | ||||||
|   c_args : '-DJANET_BOOTSTRAP', |   c_args : '-DJANET_BOOTSTRAP', | ||||||
|   dependencies : [m_dep, dl_dep], |   dependencies : [m_dep, dl_dep, thread_dep], | ||||||
|   native : true) |   native : true) | ||||||
|  |  | ||||||
| # Build core image | # Build core image | ||||||
| @@ -166,7 +168,7 @@ core_image = custom_target('core_image', | |||||||
|  |  | ||||||
| libjanet = library('janet', core_src, core_image, | libjanet = library('janet', core_src, core_image, | ||||||
|   include_directories : incdir, |   include_directories : incdir, | ||||||
|   dependencies : [m_dep, dl_dep], |   dependencies : [m_dep, dl_dep, thread_dep], | ||||||
|   install : true) |   install : true) | ||||||
|  |  | ||||||
| # Extra c flags - adding -fvisibility=hidden matches the Makefile and | # Extra c flags - adding -fvisibility=hidden matches the Makefile and | ||||||
| @@ -186,14 +188,14 @@ endif | |||||||
|  |  | ||||||
| janet_mainclient = executable('janet', core_src, core_image, mainclient_src, | janet_mainclient = executable('janet', core_src, core_image, mainclient_src, | ||||||
|   include_directories : incdir, |   include_directories : incdir, | ||||||
|   dependencies : [m_dep, dl_dep], |   dependencies : [m_dep, dl_dep, thread_dep], | ||||||
|   c_args : extra_native_cflags, |   c_args : extra_native_cflags, | ||||||
|   install : true) |   install : true) | ||||||
|  |  | ||||||
| if meson.is_cross_build() | if meson.is_cross_build() | ||||||
|   janet_nativeclient = executable('janet-native', core_src, core_image, mainclient_src, |   janet_nativeclient = executable('janet-native', core_src, core_image, mainclient_src, | ||||||
|     include_directories : incdir, |     include_directories : incdir, | ||||||
|     dependencies : [m_dep, dl_dep], |     dependencies : [m_dep, dl_dep, thread_dep], | ||||||
|     c_args : extra_cross_cflags, |     c_args : extra_cross_cflags, | ||||||
|     native : true) |     native : true) | ||||||
| else | else | ||||||
| @@ -223,7 +225,7 @@ amalg_shell = custom_target('amalg-shell', | |||||||
| # Amalgamated client | # Amalgamated client | ||||||
| janet_amalgclient = executable('janet-amalg', amalg, amalg_shell, | janet_amalgclient = executable('janet-amalg', amalg, amalg_shell, | ||||||
|   include_directories : incdir, |   include_directories : incdir, | ||||||
|   dependencies : [m_dep, dl_dep], |   dependencies : [m_dep, dl_dep, thread_dep], | ||||||
|   build_by_default : false) |   build_by_default : false) | ||||||
|  |  | ||||||
| # Tests | # Tests | ||||||
|   | |||||||
| @@ -1843,16 +1843,27 @@ | |||||||
|     (res) |     (res) | ||||||
|     (error (res :error)))) |     (error (res :error)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (def make-image-dict | ||||||
|  |   "A table used in combination with marshal to marshal code (images), such that | ||||||
|  |   (make-image x) is the same as (marshal x make-image-dict)." | ||||||
|  |   @{}) | ||||||
|  |  | ||||||
|  | (def load-image-dict | ||||||
|  |   "A table used in combination with unmarshal to unmarshal byte sequences created | ||||||
|  |   by make-image, such that (load-image bytes) is the same as (unmarshal bytes load-images-dict)." | ||||||
|  |   @{}) | ||||||
|  |  | ||||||
| (defn make-image | (defn make-image | ||||||
|   "Create an image from an environment returned by require. |   "Create an image from an environment returned by require. | ||||||
|   Returns the image source as a string." |   Returns the image source as a string." | ||||||
|   [env] |   [env] | ||||||
|   (marshal env (invert (env-lookup _env)))) |   (marshal env make-image-dict)) | ||||||
|  |  | ||||||
| (defn load-image | (defn load-image | ||||||
|   "The inverse operation to make-image. Returns an environment." |   "The inverse operation to make-image. Returns an environment." | ||||||
|   [image] |   [image] | ||||||
|   (unmarshal image (env-lookup _env))) |   (unmarshal image load-image-dict)) | ||||||
|  |  | ||||||
| (def- nati (if (= :windows (os/which)) ".dll" ".so")) | (def- nati (if (= :windows (os/which)) ".dll" ".so")) | ||||||
| (defn- check-. [x] (if (string/has-prefix? "." x) x)) | (defn- check-. [x] (if (string/has-prefix? "." x) x)) | ||||||
| @@ -2108,9 +2119,16 @@ | |||||||
|                 :on-status (or onsignal (make-onsignal env 1)) |                 :on-status (or onsignal (make-onsignal env 1)) | ||||||
|                 :source "repl"})) |                 :source "repl"})) | ||||||
|  |  | ||||||
| # Clean up some extra defs | ### | ||||||
| (put _env 'boot/opts nil) | ### | ||||||
| (put _env '_env nil) | ### Thread Extras | ||||||
|  | ### | ||||||
|  | ### | ||||||
|  |  | ||||||
|  | (defn thread/new | ||||||
|  |   "Create a new thread from a closure." | ||||||
|  |   [f] | ||||||
|  |   (thread/from-image (make-image f))) | ||||||
|  |  | ||||||
| ### | ### | ||||||
| ### | ### | ||||||
| @@ -2232,6 +2250,19 @@ | |||||||
|     (setdyn :err-color (if *colorize* true)) |     (setdyn :err-color (if *colorize* true)) | ||||||
|     (repl getchunk onsig))) |     (repl getchunk onsig))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### | ||||||
|  | ### | ||||||
|  | ### Clean up | ||||||
|  | ### | ||||||
|  | ### | ||||||
|  |  | ||||||
|  | (do | ||||||
|  |   (put _env 'boot/opts nil) | ||||||
|  |   (put _env '_env nil) | ||||||
|  |   (merge-into load-image-dict (env-lookup _env)) | ||||||
|  |   (merge-into make-image-dict (invert load-image-dict))) | ||||||
|  |  | ||||||
| ### | ### | ||||||
| ### | ### | ||||||
| ### Bootstrap | ### Bootstrap | ||||||
|   | |||||||
| @@ -987,13 +987,54 @@ static const uint32_t propagate_asm[] = { | |||||||
|     JOP_PROPAGATE | (1 << 24), |     JOP_PROPAGATE | (1 << 24), | ||||||
|     JOP_RETURN |     JOP_RETURN | ||||||
| }; | }; | ||||||
| #endif /* ifndef JANET_NO_BOOTSTRAP */ | #endif /* ifdef JANET_BOOTSTRAP */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Setup Environment | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | static void janet_load_libs(JanetTable *env) { | ||||||
|  |     janet_core_cfuns(env, NULL, corelib_cfuns); | ||||||
|  |     janet_lib_io(env); | ||||||
|  |     janet_lib_math(env); | ||||||
|  |     janet_lib_array(env); | ||||||
|  |     janet_lib_tuple(env); | ||||||
|  |     janet_lib_buffer(env); | ||||||
|  |     janet_lib_table(env); | ||||||
|  |     janet_lib_fiber(env); | ||||||
|  |     janet_lib_os(env); | ||||||
|  |     janet_lib_parse(env); | ||||||
|  |     janet_lib_compile(env); | ||||||
|  |     janet_lib_debug(env); | ||||||
|  |     janet_lib_string(env); | ||||||
|  |     janet_lib_marsh(env); | ||||||
|  | #ifdef JANET_PEG | ||||||
|  |     janet_lib_peg(env); | ||||||
|  | #endif | ||||||
|  | #ifdef JANET_ASSEMBLER | ||||||
|  |     janet_lib_asm(env); | ||||||
|  | #endif | ||||||
|  | #ifdef JANET_TYPED_ARRAY | ||||||
|  |     janet_lib_typed_array(env); | ||||||
|  | #endif | ||||||
|  | #ifdef JANET_INT_TYPES | ||||||
|  |     janet_lib_inttypes(env); | ||||||
|  | #endif | ||||||
|  | #ifdef JANET_THREADS | ||||||
|  |     janet_lib_thread(env); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef JANET_BOOTSTRAP | ||||||
|  |  | ||||||
|  | JanetTable *janet_core_dictionary(JanetTable *replacements) { | ||||||
|  |     (void) replacements; | ||||||
|  |     janet_panic("not defined in bootstrap"); | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
| JanetTable *janet_core_env(JanetTable *replacements) { | JanetTable *janet_core_env(JanetTable *replacements) { | ||||||
|     JanetTable *env = (NULL != replacements) ? replacements : janet_table(0); |     JanetTable *env = (NULL != replacements) ? replacements : janet_table(0); | ||||||
|     janet_core_cfuns(env, NULL, corelib_cfuns); |  | ||||||
|  |  | ||||||
| #ifdef JANET_BOOTSTRAP |  | ||||||
|     janet_quick_asm(env, JANET_FUN_PROP, |     janet_quick_asm(env, JANET_FUN_PROP, | ||||||
|                     "propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm), |                     "propagate", 2, 2, 2, 2, propagate_asm, sizeof(propagate_asm), | ||||||
|                     JDOC("(propagate x fiber)\n\n" |                     JDOC("(propagate x fiber)\n\n" | ||||||
| @@ -1145,48 +1186,29 @@ JanetTable *janet_core_env(JanetTable *replacements) { | |||||||
|     /* Allow references to the environment */ |     /* Allow references to the environment */ | ||||||
|     janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope.")); |     janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope.")); | ||||||
|  |  | ||||||
|     /* Set as gc root */ |     janet_load_libs(env); | ||||||
|     janet_gcroot(janet_wrap_table(env)); |     janet_gcroot(janet_wrap_table(env)); | ||||||
| #endif |     return env; | ||||||
|  | } | ||||||
|  |  | ||||||
|     /* Load auxiliary envs */ | #else | ||||||
|     janet_lib_io(env); |  | ||||||
|     janet_lib_math(env); |  | ||||||
|     janet_lib_array(env); |  | ||||||
|     janet_lib_tuple(env); |  | ||||||
|     janet_lib_buffer(env); |  | ||||||
|     janet_lib_table(env); |  | ||||||
|     janet_lib_fiber(env); |  | ||||||
|     janet_lib_os(env); |  | ||||||
|     janet_lib_parse(env); |  | ||||||
|     janet_lib_compile(env); |  | ||||||
|     janet_lib_debug(env); |  | ||||||
|     janet_lib_string(env); |  | ||||||
|     janet_lib_marsh(env); |  | ||||||
| #ifdef JANET_PEG |  | ||||||
|     janet_lib_peg(env); |  | ||||||
| #endif |  | ||||||
| #ifdef JANET_ASSEMBLER |  | ||||||
|     janet_lib_asm(env); |  | ||||||
| #endif |  | ||||||
| #ifdef JANET_TYPED_ARRAY |  | ||||||
|     janet_lib_typed_array(env); |  | ||||||
| #endif |  | ||||||
| #ifdef JANET_INT_TYPES |  | ||||||
|     janet_lib_inttypes(env); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef JANET_BOOTSTRAP | JanetTable *janet_core_dictionary(JanetTable *replacements) { | ||||||
|     /* Unmarshal from core image */ |     JanetTable *dict = (NULL != replacements) ? replacements : janet_table(0); | ||||||
|  |     janet_load_libs(dict); | ||||||
|  |     return dict; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | JanetTable *janet_core_env(JanetTable *replacements) { | ||||||
|  |     JanetTable *dict = janet_core_dictionary(replacements); | ||||||
|     Janet marsh_out = janet_unmarshal( |     Janet marsh_out = janet_unmarshal( | ||||||
|                           janet_core_image, |                           janet_core_image, | ||||||
|                           janet_core_image_size, |                           janet_core_image_size, | ||||||
|                           0, |                           0, | ||||||
|                           env, |                           dict, | ||||||
|                           NULL); |                           NULL); | ||||||
|     janet_gcroot(marsh_out); |     janet_gcroot(marsh_out); | ||||||
|     env = janet_unwrap_table(marsh_out); |     return janet_unwrap_table(marsh_out); | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     return env; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										163
									
								
								src/core/thread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/core/thread.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2019 Calvin Rose | ||||||
|  | * | ||||||
|  | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | * of this software and associated documentation files (the "Software"), to | ||||||
|  | * deal in the Software without restriction, including without limitation the | ||||||
|  | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||||
|  | * sell copies of the Software, and to permit persons to whom the Software is | ||||||
|  | * furnished to do so, subject to the following conditions: | ||||||
|  | * | ||||||
|  | * The above copyright notice and this permission notice shall be included in | ||||||
|  | * all copies or substantial portions of the Software. | ||||||
|  | * | ||||||
|  | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|  | * IN THE SOFTWARE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef JANET_AMALG | ||||||
|  | #include <janet.h> | ||||||
|  | #include "gc.h" | ||||||
|  | #include "util.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef JANET_THREADS | ||||||
|  |  | ||||||
|  | #include <pthread.h> | ||||||
|  |  | ||||||
|  | static void shared_cleanup(JanetThreadShared *shared) { | ||||||
|  |     pthread_mutex_destroy(&shared->refCountLock); | ||||||
|  |     pthread_mutex_destroy(&shared->memoryLock); | ||||||
|  |     free(shared->memory); | ||||||
|  |     free(shared); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int thread_gc(void *p, size_t size) { | ||||||
|  |     JanetThread *thread = (JanetThread *)p; | ||||||
|  |     JanetThreadShared *shared = thread->shared; | ||||||
|  |     if (NULL == shared) return 0; | ||||||
|  |     (void) size; | ||||||
|  |     pthread_mutex_lock(&shared->refCountLock); | ||||||
|  |     int refcount = --shared->refCount; | ||||||
|  |     if (refcount == 0) { | ||||||
|  |         shared_cleanup(shared); | ||||||
|  |     } else { | ||||||
|  |         pthread_mutex_unlock(&shared->refCountLock); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static JanetAbstractType Thread_AT = { | ||||||
|  |     "core/thread", | ||||||
|  |     thread_gc, | ||||||
|  |     NULL, | ||||||
|  |     NULL, | ||||||
|  |     NULL, | ||||||
|  |     NULL, | ||||||
|  |     NULL, | ||||||
|  |     NULL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | JanetThread *janet_getthread(Janet *argv, int32_t n) { | ||||||
|  |     return (JanetThread *) janet_getabstract(argv, n, &Thread_AT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Runs in new thread */ | ||||||
|  | static int thread_worker(JanetThreadShared *shared) { | ||||||
|  |     /* Init VM */ | ||||||
|  |     janet_init(); | ||||||
|  |  | ||||||
|  |     JanetTable *dict = janet_core_dictionary(NULL); | ||||||
|  |     const uint8_t *next = NULL; | ||||||
|  |  | ||||||
|  |     /* Unmarshal the function */ | ||||||
|  |     Janet funcv = janet_unmarshal(shared->memory, shared->memorySize, 0, dict, &next); | ||||||
|  |     if (next == shared->memory) goto error; | ||||||
|  |     if (!janet_checktype(funcv, JANET_FUNCTION)) goto error; | ||||||
|  |     JanetFunction *func = janet_unwrap_function(funcv); | ||||||
|  |  | ||||||
|  |     /* Create self thread */ | ||||||
|  |     JanetThread *thread = janet_abstract(&Thread_AT, sizeof(JanetThread)); | ||||||
|  |     thread->shared = shared; | ||||||
|  |     thread->handle = pthread_self(); | ||||||
|  |  | ||||||
|  |     /* Clean up thread when done, do not wait for a join. For | ||||||
|  |      * communicating with other threads, we will rely on the | ||||||
|  |      * JanetThreadShared structure. */ | ||||||
|  |     pthread_detach(thread->handle); | ||||||
|  |  | ||||||
|  |     /* Call function */ | ||||||
|  |     JanetFiber *fiber = janet_fiber(func, 64, 0, NULL); | ||||||
|  |     fiber->env = janet_table(0); | ||||||
|  |     janet_table_put(fiber->env, janet_ckeywordv("worker"), janet_wrap_abstract(thread)); | ||||||
|  |     Janet out; | ||||||
|  |     janet_continue(fiber, janet_wrap_nil(), &out); | ||||||
|  |  | ||||||
|  |     /* TODO - marshal 'out' into sharedMemory */ | ||||||
|  |  | ||||||
|  |     /* Success */ | ||||||
|  |     janet_deinit(); | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |     /* Fail */ | ||||||
|  | error: | ||||||
|  |     janet_deinit(); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *janet_pthread_wrapper(void *param) { | ||||||
|  |     thread_worker((JanetThreadShared *)param); | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static Janet cfun_from_image(int32_t argc, Janet *argv) { | ||||||
|  |     janet_fixarity(argc, 1); | ||||||
|  |     JanetByteView bytes = janet_getbytes(argv, 0); | ||||||
|  |  | ||||||
|  |     /* Create Shared memory chunk of thread object */ | ||||||
|  |     JanetThreadShared *shared = malloc(sizeof(JanetThreadShared)); | ||||||
|  |     uint8_t *mem = malloc(bytes.len); | ||||||
|  |     if (NULL == shared || NULL == mem) { | ||||||
|  |         janet_panicf("could not allocate memory for thread"); | ||||||
|  |     } | ||||||
|  |     shared->memory = mem; | ||||||
|  |     shared->memorySize = bytes.len; | ||||||
|  |     memcpy(mem, bytes.bytes, bytes.len); | ||||||
|  |     shared->refCount = 2; | ||||||
|  |     pthread_mutex_init(&shared->refCountLock, NULL); | ||||||
|  |     pthread_mutex_init(&shared->memoryLock, NULL); | ||||||
|  |  | ||||||
|  |     /* Create thread abstract */ | ||||||
|  |     JanetThread *thread = janet_abstract(&Thread_AT, sizeof(JanetThread)); | ||||||
|  |     thread->shared = shared; | ||||||
|  |  | ||||||
|  |     /* Run thread */ | ||||||
|  |     int error = pthread_create(&thread->handle, NULL, janet_pthread_wrapper, shared); | ||||||
|  |     if (error) { | ||||||
|  |         thread->shared = NULL; /* Prevent GC from trying to mess with shared memory here */ | ||||||
|  |         shared_cleanup(shared); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return janet_wrap_abstract(thread); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const JanetReg threadlib_cfuns[] = { | ||||||
|  |     { | ||||||
|  |         "thread/from-image", cfun_from_image, | ||||||
|  |         JDOC("(thread/from-image image)\n\n" | ||||||
|  |              "Start a new thread. image is a byte sequence, containing a marshalled function.") | ||||||
|  |     }, | ||||||
|  |     {NULL, NULL, NULL} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* Module entry point */ | ||||||
|  | void janet_lib_thread(JanetTable *env) { | ||||||
|  |     janet_core_cfuns(env, NULL, threadlib_cfuns); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -120,5 +120,8 @@ void janet_lib_typed_array(JanetTable *env); | |||||||
| #ifdef JANET_INT_TYPES | #ifdef JANET_INT_TYPES | ||||||
| void janet_lib_inttypes(JanetTable *env); | void janet_lib_inttypes(JanetTable *env); | ||||||
| #endif | #endif | ||||||
|  | #ifdef JANET_THREADS | ||||||
|  | void janet_lib_thread(JanetTable *env); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -143,6 +143,11 @@ extern "C" { | |||||||
| #define JANET_INT_TYPES | #define JANET_INT_TYPES | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | /* Enable or disable threads */ | ||||||
|  | #ifndef JANET_NO_THREADS | ||||||
|  | #define JANET_THREADS | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* How to export symbols */ | /* How to export symbols */ | ||||||
| #ifndef JANET_API | #ifndef JANET_API | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
| @@ -319,6 +324,24 @@ typedef struct JanetRange JanetRange; | |||||||
| typedef struct JanetRNG JanetRNG; | typedef struct JanetRNG JanetRNG; | ||||||
| typedef Janet(*JanetCFunction)(int32_t argc, Janet *argv); | typedef Janet(*JanetCFunction)(int32_t argc, Janet *argv); | ||||||
|  |  | ||||||
|  | /* Thread types */ | ||||||
|  | #ifdef JANET_THREADS | ||||||
|  | #include <pthread.h> | ||||||
|  | typedef struct JanetThread JanetThread; | ||||||
|  | typedef struct JanetThreadShared JanetThreadShared; | ||||||
|  | struct JanetThreadShared { | ||||||
|  |     pthread_mutex_t memoryLock; | ||||||
|  |     pthread_mutex_t refCountLock; | ||||||
|  |     uint8_t *memory; | ||||||
|  |     size_t memorySize; | ||||||
|  |     int refCount; | ||||||
|  | }; | ||||||
|  | struct JanetThread { | ||||||
|  |     pthread_t handle; | ||||||
|  |     JanetThreadShared *shared; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* Basic types for all Janet Values */ | /* Basic types for all Janet Values */ | ||||||
| typedef enum JanetType { | typedef enum JanetType { | ||||||
|     JANET_NUMBER, |     JANET_NUMBER, | ||||||
| @@ -1092,6 +1115,7 @@ struct JanetCompileResult { | |||||||
| JANET_API JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where); | JANET_API JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where); | ||||||
|  |  | ||||||
| /* Get the default environment for janet */ | /* Get the default environment for janet */ | ||||||
|  | JANET_API JanetTable *janet_core_dictionary(JanetTable *replacements); /* Used for unmarshaling images */ | ||||||
| JANET_API JanetTable *janet_core_env(JanetTable *replacements); | JANET_API JanetTable *janet_core_env(JanetTable *replacements); | ||||||
|  |  | ||||||
| JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out); | JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out); | ||||||
|   | |||||||
| @@ -89,18 +89,18 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c | |||||||
| /* static state */ | /* static state */ | ||||||
| #define JANET_LINE_MAX 1024 | #define JANET_LINE_MAX 1024 | ||||||
| #define JANET_HISTORY_MAX 100 | #define JANET_HISTORY_MAX 100 | ||||||
| static int gbl_israwmode = 0; | static JANET_THREAD_LOCAL int gbl_israwmode = 0; | ||||||
| static const char *gbl_prompt = "> "; | static JANET_THREAD_LOCAL const char *gbl_prompt = "> "; | ||||||
| static int gbl_plen = 2; | static JANET_THREAD_LOCAL int gbl_plen = 2; | ||||||
| static char gbl_buf[JANET_LINE_MAX]; | static JANET_THREAD_LOCAL char gbl_buf[JANET_LINE_MAX]; | ||||||
| static int gbl_len = 0; | static JANET_THREAD_LOCAL int gbl_len = 0; | ||||||
| static int gbl_pos = 0; | static JANET_THREAD_LOCAL int gbl_pos = 0; | ||||||
| static int gbl_cols = 80; | static JANET_THREAD_LOCAL int gbl_cols = 80; | ||||||
| static char *gbl_history[JANET_HISTORY_MAX]; | static JANET_THREAD_LOCAL char *gbl_history[JANET_HISTORY_MAX]; | ||||||
| static int gbl_history_count = 0; | static JANET_THREAD_LOCAL int gbl_history_count = 0; | ||||||
| static int gbl_historyi = 0; | static JANET_THREAD_LOCAL int gbl_historyi = 0; | ||||||
| static int gbl_sigint_flag = 0; | static JANET_THREAD_LOCAL int gbl_sigint_flag = 0; | ||||||
| static struct termios gbl_termios_start; | static JANET_THREAD_LOCAL struct termios gbl_termios_start; | ||||||
|  |  | ||||||
| /* Unsupported terminal list from linenoise */ | /* Unsupported terminal list from linenoise */ | ||||||
| static const char *badterms[] = { | static const char *badterms[] = { | ||||||
| @@ -126,7 +126,6 @@ static int rawmode() { | |||||||
|     if (tcgetattr(STDIN_FILENO, &gbl_termios_start) == -1) goto fatal; |     if (tcgetattr(STDIN_FILENO, &gbl_termios_start) == -1) goto fatal; | ||||||
|     t = gbl_termios_start; |     t = gbl_termios_start; | ||||||
|     t.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); |     t.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); | ||||||
|     t.c_oflag &= ~(OPOST); |  | ||||||
|     t.c_cflag |= (CS8); |     t.c_cflag |= (CS8); | ||||||
|     t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); |     t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); | ||||||
|     t.c_cc[VMIN] = 1; |     t.c_cc[VMIN] = 1; | ||||||
| @@ -490,6 +489,7 @@ void janet_line_get(const char *p, JanetBuffer *buffer) { | |||||||
|         } |         } | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |     fflush(stdin); | ||||||
|     norawmode(); |     norawmode(); | ||||||
|     fputc('\n', out); |     fputc('\n', out); | ||||||
|     janet_buffer_ensure(buffer, gbl_len + 1, 2); |     janet_buffer_ensure(buffer, gbl_len + 1, 2); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose