summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--otherlibs/systhreads/st_stubs.c116
-rw-r--r--otherlibs/systhreads/threads.h4
2 files changed, 79 insertions, 41 deletions
diff --git a/otherlibs/systhreads/st_stubs.c b/otherlibs/systhreads/st_stubs.c
index 9bcec4a150..06d1a58452 100644
--- a/otherlibs/systhreads/st_stubs.c
+++ b/otherlibs/systhreads/st_stubs.c
@@ -88,6 +88,9 @@ struct caml_thread_struct {
typedef struct caml_thread_struct * caml_thread_t;
+/* The "head" of the circular list of thread descriptors */
+static caml_thread_t all_threads = NULL;
+
/* The descriptor for the currently executing thread */
static caml_thread_t curr_thread = NULL;
@@ -283,15 +286,46 @@ static uintnat caml_thread_stack_usage(void)
return sz;
}
+/* Create and setup a new thread info block.
+ This block has no associated thread descriptor and
+ is not inserted in the list of threads. */
-/* Set up a thread info block and insert it in list of threads. */
+static caml_thread_t caml_thread_new_info(void)
+{
+ caml_thread_t th;
-static caml_thread_t caml_thread_setup_info(value clos)
+ th = (caml_thread_t) malloc(sizeof(struct caml_thread_struct));
+ if (th == NULL) return NULL;
+ th->descr = Val_unit; /* filled later */
+#ifdef NATIVE_CODE
+ th->bottom_of_stack = NULL;
+ th->top_of_stack = NULL;
+ th->last_retaddr = 1;
+ th->exception_pointer = NULL;
+ th->local_roots = NULL;
+ th->exit_buf = NULL;
+#else
+ /* Allocate the stacks */
+ th->stack_low = (value *) stat_alloc(Thread_stack_size);
+ th->stack_high = th->stack_low + Thread_stack_size / sizeof(value);
+ th->stack_threshold = th->stack_low + Stack_threshold / sizeof(value);
+ th->sp = th->stack_high;
+ th->trapsp = th->stack_high;
+ th->local_roots = NULL;
+ th->external_raise = NULL;
+#endif
+ th->backtrace_pos = 0;
+ th->backtrace_buffer = NULL;
+ th->backtrace_last_exn = Val_unit;
+ return th;
+}
+
+/* Allocate a thread descriptor block. */
+
+static value caml_thread_new_descriptor(value clos)
{
value mu = Val_unit;
value descr;
- caml_thread_t th;
-
Begin_roots2 (clos, mu)
/* Create and initialize the termination semaphore */
mu = caml_threadstatus_new();
@@ -301,33 +335,8 @@ static caml_thread_t caml_thread_setup_info(value clos)
Start_closure(descr) = clos;
Terminated(descr) = mu;
thread_next_ident++;
- /* Create an info block for the current thread */
- th = (caml_thread_t) stat_alloc(sizeof(struct caml_thread_struct));
- th->descr = descr;
-#ifdef NATIVE_CODE
- th->bottom_of_stack = NULL;
- th->exception_pointer = NULL;
- th->local_roots = NULL;
-#else
- /* Allocate the stacks */
- th->stack_low = (value *) stat_alloc(Thread_stack_size);
- th->stack_high = th->stack_low + Thread_stack_size / sizeof(value);
- th->stack_threshold = th->stack_low + Stack_threshold / sizeof(value);
- th->sp = th->stack_high;
- th->trapsp = th->stack_high;
- th->local_roots = NULL;
- th->external_raise = NULL;
-#endif
- th->backtrace_pos = 0;
- th->backtrace_buffer = NULL;
- th->backtrace_last_exn = Val_unit;
- /* Add thread info block to the list of threads */
- th->next = curr_thread->next;
- th->prev = curr_thread;
- curr_thread->next->prev = th;
- curr_thread->next = th;
End_roots();
- return th;
+ return descr;
}
/* Remove a thread info block from the list of threads.
@@ -335,6 +344,7 @@ static caml_thread_t caml_thread_setup_info(value clos)
static void caml_thread_remove_info(caml_thread_t th)
{
+ if (th->next == th) all_threads = NULL; /* last Caml thread exiting */
th->next->prev = th->prev;
th->prev->next = th->next;
#ifndef NATIVE_CODE
@@ -361,6 +371,7 @@ static void caml_thread_reinitialize(void)
}
curr_thread->next = curr_thread;
curr_thread->prev = curr_thread;
+ all_threads = curr_thread;
/* Reinitialize the master lock machinery,
just in case the fork happened while other threads were doing
leave_blocking_section */
@@ -411,6 +422,7 @@ CAMLprim value caml_thread_initialize(value unit) /* ML */
curr_thread->descr = descr;
curr_thread->next = curr_thread;
curr_thread->prev = curr_thread;
+ all_threads = curr_thread;
curr_thread->backtrace_last_exn = Val_unit;
#ifdef NATIVE_CODE
curr_thread->exit_buf = &caml_termination_jmpbuf;
@@ -502,8 +514,16 @@ CAMLprim value caml_thread_new(value clos) /* ML */
caml_thread_t th;
st_retcode err;
- /* Set up and register a thread info block */
- th = caml_thread_setup_info(clos);
+ /* Create a thread info block */
+ th = caml_thread_new_info();
+ if (th == NULL) caml_raise_out_of_memory();
+ /* Equip it with a thread descriptor */
+ th->descr = caml_thread_new_descriptor(clos);
+ /* Add thread info block to the list of threads */
+ th->next = curr_thread->next;
+ th->prev = curr_thread;
+ curr_thread->next->prev = th;
+ curr_thread->next = th;
/* Create the new thread */
err = st_thread_create(NULL, caml_thread_start, (void *) th);
if (err != 0) {
@@ -531,23 +551,39 @@ CAMLexport int caml_c_thread_register(void)
/* Already registered? */
if (st_tls_get(thread_descriptor_key) != NULL) return 0;
- /* Wait until the runtime is available */
- st_masterlock_acquire(&caml_master_lock);
- /* Set up and register thread info block */
- th = caml_thread_setup_info(Val_unit /*no closure*/);
+ /* Create a thread info block */
+ th = caml_thread_new_info();
+ if (th == NULL) return 0;
#ifdef NATIVE_CODE
- th->exit_buf = NULL;
th->top_of_stack = (char *) &err;
#endif
+ /* Take master lock to protect access to the chaining of threads */
+ st_masterlock_acquire(&caml_master_lock);
+ /* Add thread info block to the list of threads */
+ if (all_threads == NULL) {
+ th->next = th;
+ th->prev = th;
+ all_threads = th;
+ } else {
+ th->next = all_threads->next;
+ th->prev = all_threads;
+ all_threads->next->prev = th;
+ all_threads->next = th;
+ }
/* Associate the thread descriptor with the thread */
st_tls_set(thread_descriptor_key, (void *) th);
+ /* Release the master lock */
+ st_masterlock_release(&caml_master_lock);
+ /* Now we can re-enter the run-time system and heap-allocate the descriptor */
+ leave_blocking_section();
+ th->descr = caml_thread_new_descriptor(Val_unit); /* no closure */
/* Create the tick thread if not already done. */
if (! caml_tick_thread_running) {
err = st_thread_create(&caml_tick_thread_id, caml_thread_tick, NULL);
if (err == 0) caml_tick_thread_running = 1;
}
- /* Release the runtime */
- st_masterlock_release(&caml_master_lock);
+ /* Exit the run-time system */
+ enter_blocking_section();
return 1;
}
@@ -561,6 +597,8 @@ CAMLexport int caml_c_thread_unregister(void)
if (th == NULL) return 0;
/* Wait until the runtime is available */
st_masterlock_acquire(&caml_master_lock);
+ /* Forget the thread descriptor */
+ st_tls_set(thread_descriptor_key, NULL);
/* Remove thread info block from list of threads, and free it */
caml_thread_remove_info(th);
/* Release the runtime */
diff --git a/otherlibs/systhreads/threads.h b/otherlibs/systhreads/threads.h
index 9b3bd1d67c..746624256a 100644
--- a/otherlibs/systhreads/threads.h
+++ b/otherlibs/systhreads/threads.h
@@ -18,8 +18,8 @@
CAMLextern void caml_enter_blocking_section (void);
CAMLextern void caml_leave_blocking_section (void);
-#define caml_release_runtime_system caml_leave_blocking_section
-#define caml_acquire_runtime_system caml_enter_blocking_section
+#define caml_acquire_runtime_system caml_leave_blocking_section
+#define caml_release_runtime_system caml_enter_blocking_section
/* Manage the master lock around the Caml run-time system.
Only one thread at a time can execute Caml compiled code or