diff options
author | Mikael Djurfeldt <djurfeldt@nada.kth.se> | 1998-01-23 20:51:47 +0000 |
---|---|---|
committer | Mikael Djurfeldt <djurfeldt@nada.kth.se> | 1998-01-23 20:51:47 +0000 |
commit | df366c2615effef0b8082cc4f59784f0a41e46c5 (patch) | |
tree | 6da5b1bf4388a5a4ecf3378323b8924038fc87b0 /libguile/coop-threads.c | |
parent | 171422a94adf5d8f95c3e9aae95e2fe7ce740bec (diff) | |
download | guile-df366c2615effef0b8082cc4f59784f0a41e46c5.tar.gz |
* coop-threads.c, threads.h (scm_spawn_thread): New function.
Can spawn a thread from application C code.
Diffstat (limited to 'libguile/coop-threads.c')
-rw-r--r-- | libguile/coop-threads.c | 97 |
1 files changed, 88 insertions, 9 deletions
diff --git a/libguile/coop-threads.c b/libguile/coop-threads.c index b3fad95f4..9e1ad75f9 100644 --- a/libguile/coop-threads.c +++ b/libguile/coop-threads.c @@ -204,14 +204,20 @@ scm_threads_mark_stacks () } } -#ifdef __STDC__ -void -launch_thread (void *p) -#else -void -launch_thread (p) - void *p; -#endif +/* NOTE: There are TWO mechanisms for starting a thread: The first one + is used when spawning a thread from Scheme, while the second one is + used from C. + + It might be argued that the first should be implemented in terms of + the second. The reason it isn't is that that would require an + extra unnecessary malloc (the thread_args structure). By providing + one pair of extra functions (c_launch_thread, scm_spawn_thread) the + Scheme threads are started more efficiently. */ + +/* This is the first thread spawning mechanism: threads from Scheme */ + +static void +scheme_launch_thread (void *p) { /* The thread object will be GC protected by being a member of the list given as argument to launch_thread. It will be marked @@ -274,7 +280,7 @@ scm_call_with_new_thread (argl) SCM_DEFER_INTS; SCM_SETCAR (thread, scm_tc16_thread); argl = scm_cons (thread, argl); - t = coop_create (launch_thread, (void *) argl); + t = coop_create (scheme_launch_thread, (void *) argl); t->data = SCM_ROOT_STATE (root); SCM_SETCDR (thread, t); scm_thread_count++; @@ -291,6 +297,79 @@ scm_call_with_new_thread (argl) return thread; } +/* This is the second thread spawning mechanism: threads from C */ + +struct thread_args { + SCM thread; + scm_catch_body_t body; + void *body_data; + scm_catch_handler_t handler; + void *handler_data; +}; + +static void +c_launch_thread (void *p) +{ + struct thread_args *args = (struct thread_args *) p; + /* The thread object will be GC protected by being on this stack */ + SCM thread = args->thread; + /* We must use the address of `thread', otherwise the compiler will + optimize it away. This is OK since the longest SCM_STACKITEM + also is a long. */ + scm_internal_cwdr (args->body, + args->body_data, + args->handler, + args->handler_data, + &thread); + scm_thread_count--; + scm_must_free ((char *) args); +} + +SCM +scm_spawn_thread (scm_catch_body_t body, void *body_data, + scm_catch_handler_t handler, void *handler_data) +{ + SCM thread; + coop_t *t; + SCM root, old_winds; + struct thread_args *args = + (struct thread_args *) scm_must_malloc (sizeof (*args), + "scm_spawn_thread"); + + /* Unwind wind chain. */ + old_winds = scm_dynwinds; + scm_dowinds (SCM_EOL, scm_ilength (scm_root->dynwinds)); + + /* Allocate thread locals. */ + root = scm_make_root (scm_root->handle); + /* Make thread. */ + SCM_NEWCELL (thread); + SCM_DEFER_INTS; + SCM_SETCAR (thread, scm_tc16_thread); + + args->thread = thread; + args->body = body; + args->body_data = body_data; + args->handler = handler; + args->handler_data = handler_data; + + t = coop_create (c_launch_thread, (void *) args); + + t->data = SCM_ROOT_STATE (root); + SCM_SETCDR (thread, t); + scm_thread_count++; + /* Note that the following statement also could cause coop_yield.*/ + SCM_ALLOW_INTS; + + /* We're now ready for the thread to begin. */ + coop_yield(); + + /* Return to old dynamic context. */ + scm_dowinds (old_winds, - scm_ilength (old_winds)); + + return thread; +} + #ifdef __STDC__ SCM scm_join_thread (SCM t) |