X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fthread.c;h=2c3367c3f7710d54eea6055083591fb51e5f7934;hb=8e9908b6f79b7bb52a281cfcbf0712d4b914f3cf;hp=6d5ddaa6c0e8fe891175ff3a63ec3bc0aa543cf4;hpb=1600081cf1b71b3d0e2e40de1c1c124a3a4fd40c;p=sbcl.git diff --git a/src/runtime/thread.c b/src/runtime/thread.c index 6d5ddaa..2c3367c 100644 --- a/src/runtime/thread.c +++ b/src/runtime/thread.c @@ -25,6 +25,12 @@ #include #endif +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER +#include +#include +#include +#endif + #include "runtime.h" #include "validate.h" /* for CONTROL_STACK_SIZE etc */ #include "alloc.h" @@ -51,6 +57,11 @@ #define QUEUE_FREEABLE_THREAD_STACKS #endif +#ifdef LISP_FEATURE_FREEBSD +#define CREATE_CLEANUP_THREAD +#define LOCK_CREATE_THREAD +#endif + #define ALIEN_STACK_SIZE (1*1024*1024) /* 1Mb size chosen at random */ struct freeable_stack { @@ -76,6 +87,9 @@ extern struct interrupt_data * global_interrupt_data; #ifdef LISP_FEATURE_SB_THREAD pthread_mutex_t all_threads_lock = PTHREAD_MUTEX_INITIALIZER; +#ifdef LOCK_CREATE_THREAD +static pthread_mutex_t create_thread_lock = PTHREAD_MUTEX_INITIALIZER; +#endif #endif #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) @@ -135,6 +149,7 @@ initial_thread_trampoline(struct thread *th) #ifdef QUEUE_FREEABLE_THREAD_STACKS +static void queue_freeable_thread_stack(struct thread *thread_to_be_cleaned_up) { if (thread_to_be_cleaned_up) { @@ -186,6 +201,45 @@ free_freeable_stacks() { } } +#elif defined(CREATE_CLEANUP_THREAD) +static void * +cleanup_thread(void *arg) +{ + struct freeable_stack *freeable = arg; + pthread_t self = pthread_self(); + + FSHOW((stderr, "/cleaner thread(%p): joining %p\n", + self, freeable->os_thread)); + gc_assert(pthread_join(freeable->os_thread, NULL) == 0); + FSHOW((stderr, "/cleaner thread(%p): free stack %p\n", + self, freeable->stack)); + os_invalidate(freeable->stack, THREAD_STRUCT_SIZE); + free(freeable); + + pthread_detach(self); + + return NULL; +} + +static void +create_cleanup_thread(struct thread *thread_to_be_cleaned_up) +{ + pthread_t thread; + int result; + + if (thread_to_be_cleaned_up) { + struct freeable_stack *freeable = + malloc(sizeof(struct freeable_stack)); + gc_assert(freeable != NULL); + freeable->os_thread = thread_to_be_cleaned_up->os_thread; + freeable->stack = + (os_vm_address_t) thread_to_be_cleaned_up->control_stack_start; + result = pthread_create(&thread, NULL, cleanup_thread, freeable); + gc_assert(result == 0); + sched_yield(); + } +} + #else static void free_thread_stack_later(struct thread *thread_to_be_cleaned_up) @@ -224,6 +278,7 @@ new_thread_trampoline(struct thread *th) { lispobj function; int result, lock_ret; + FSHOW((stderr,"/creating thread %lu\n", thread_self())); function = th->no_tls_value_marker; th->no_tls_value_marker = NO_TLS_VALUE_MARKER_WIDETAG; @@ -245,6 +300,9 @@ new_thread_trampoline(struct thread *th) gc_assert(lock_ret == 0); result = funcall0(function); + + /* Block GC */ + block_blockable_signals(); th->state=STATE_DEAD; /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this @@ -261,8 +319,21 @@ new_thread_trampoline(struct thread *th) os_invalidate((os_vm_address_t)th->interrupt_data, (sizeof (struct interrupt_data))); +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER + FSHOW((stderr, "Deallocating mach port %x\n", THREAD_STRUCT_TO_EXCEPTION_PORT(th))); + mach_port_move_member(mach_task_self(), + THREAD_STRUCT_TO_EXCEPTION_PORT(th), + MACH_PORT_NULL); + mach_port_deallocate(mach_task_self(), + THREAD_STRUCT_TO_EXCEPTION_PORT(th)); + mach_port_destroy(mach_task_self(), + THREAD_STRUCT_TO_EXCEPTION_PORT(th)); +#endif + #ifdef QUEUE_FREEABLE_THREAD_STACKS queue_freeable_thread_stack(th); +#elif defined(CREATE_CLEANUP_THREAD) + create_cleanup_thread(th); #else free_thread_stack_later(th); #endif @@ -297,6 +368,10 @@ create_thread_struct(lispobj initial_function) { int i; #endif +#ifdef CREATE_CLEANUP_THREAD + /* Give a chance for cleanup threads to run. */ + sched_yield(); +#endif /* may as well allocate all the spaces at once: it saves us from * having to decide what to do if only some of the allocations * succeed */ @@ -399,12 +474,25 @@ create_thread_struct(lispobj initial_function) { } th->interrupt_data->pending_handler = 0; th->no_tls_value_marker=initial_function; + + th->stepping = NIL; return th; } +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER +mach_port_t setup_mach_exception_handling_thread(); +kern_return_t mach_thread_init(mach_port_t thread_exception_port); + +#endif + void create_initial_thread(lispobj initial_function) { struct thread *th=create_thread_struct(initial_function); if(th) { +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER + kern_return_t ret; + + setup_mach_exception_handling_thread(); +#endif initial_thread_trampoline(th); /* no return */ } else lose("can't create initial thread\n"); } @@ -427,6 +515,11 @@ boolean create_os_thread(struct thread *th,os_thread_t *kid_tid) FSHOW_SIGNAL((stderr,"/create_os_thread: creating new thread\n")); +#ifdef LOCK_CREATE_THREAD + retcode = pthread_mutex_lock(&create_thread_lock); + gc_assert(retcode == 0); + FSHOW_SIGNAL((stderr,"/create_os_thread: got lock\n")); +#endif sigemptyset(&newset); /* Blocking deferrable signals is enough, no need to block * SIG_STOP_FOR_GC because the child process is not linked onto @@ -456,10 +549,16 @@ boolean create_os_thread(struct thread *th,os_thread_t *kid_tid) } r=0; } + #ifdef QUEUE_FREEABLE_THREAD_STACKS free_freeable_stacks(); #endif thread_sigmask(SIG_SETMASK,&oldset,0); +#ifdef LOCK_CREATE_THREAD + retcode = pthread_mutex_unlock(&create_thread_lock); + gc_assert(retcode == 0); + FSHOW_SIGNAL((stderr,"/create_os_thread: released lock\n")); +#endif return r; } @@ -484,7 +583,8 @@ os_thread_t create_thread(lispobj initial_function) { /* Send the signo to os_thread, retry if the rt signal queue is * full. */ -static int kill_thread_safely(os_thread_t os_thread, int signo) +int +kill_thread_safely(os_thread_t os_thread, int signo) { int r; /* The man page does not mention EAGAIN as a valid return value @@ -529,6 +629,16 @@ void gc_stop_the_world() { struct thread *p,*th=arch_os_get_current_thread(); int status, lock_ret; +#ifdef LOCK_CREATE_THREAD + /* KLUDGE: Stopping the thread during pthread_create() causes deadlock + * on FreeBSD. */ + FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on create_thread_lock, thread=%lu\n", + th->os_thread)); + lock_ret = pthread_mutex_lock(&create_thread_lock); + gc_assert(lock_ret == 0); + FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got create_thread_lock, thread=%lu\n", + th->os_thread)); +#endif FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on lock, thread=%lu\n", th->os_thread)); /* keep threads from starting while the world is stopped. */ @@ -605,6 +715,10 @@ void gc_start_the_world() lock_ret = pthread_mutex_unlock(&all_threads_lock); gc_assert(lock_ret == 0); +#ifdef LOCK_CREATE_THREAD + lock_ret = pthread_mutex_unlock(&create_thread_lock); + gc_assert(lock_ret == 0); +#endif FSHOW_SIGNAL((stderr,"/gc_start_the_world:end\n")); }