diff options
Diffstat (limited to 'libgc')
-rw-r--r-- | libgc/include/gc.h | 12 | ||||
-rw-r--r-- | libgc/pthread_support.c | 2 | ||||
-rw-r--r-- | libgc/win32_threads.c | 48 |
3 files changed, 59 insertions, 3 deletions
diff --git a/libgc/include/gc.h b/libgc/include/gc.h index e7929918ad0..c9c20e65a6c 100644 --- a/libgc/include/gc.h +++ b/libgc/include/gc.h @@ -835,6 +835,18 @@ typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data)); GC_API GC_PTR GC_call_with_alloc_lock GC_PROTO((GC_fn_type fn, GC_PTR client_data)); +/* + * These are similar to GC_do_blocking () in upstream bdwgc. The design is + * simpler in that there is no distinction between active and inactive stack + * frames; instead, while a thread is in blocking state, it promises to not + * interact with the GC at all, and to not keep any pointers to GC memory + * around from before entering blocking state. Additionally, these can be + * called unbalanced (they simply set a flag internally). + */ +GC_API void GC_start_blocking GC_PROTO((void)); + +GC_API void GC_end_blocking GC_PROTO((void)); + /* The following routines are primarily intended for use with a */ /* preprocessor which inserts calls to check C pointer arithmetic. */ /* They indicate failure by invoking the corresponding _print_proc. */ diff --git a/libgc/pthread_support.c b/libgc/pthread_support.c index 6d240f65f0e..3ff89b29222 100644 --- a/libgc/pthread_support.c +++ b/libgc/pthread_support.c @@ -1245,7 +1245,6 @@ void GC_start_blocking(void) { GC_thread me; LOCK(); me = GC_lookup_thread(pthread_self()); - GC_ASSERT(!(me -> thread_blocked)); # ifdef SPARC me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack(); # else @@ -1273,7 +1272,6 @@ void GC_end_blocking(void) { GC_thread me; LOCK(); /* This will block if the world is stopped. */ me = GC_lookup_thread(pthread_self()); - GC_ASSERT(me -> thread_blocked); me -> thread_blocked = FALSE; UNLOCK(); } diff --git a/libgc/win32_threads.c b/libgc/win32_threads.c index 5533b8f2e25..425d41a9892 100644 --- a/libgc/win32_threads.c +++ b/libgc/win32_threads.c @@ -48,6 +48,7 @@ struct GC_thread_Rep { /* 0 ==> entry not valid. */ /* !in_use ==> stack_base == 0 */ GC_bool suspended; + GC_bool thread_blocked; # ifdef CYGWIN32 void *status; /* hold exit value until join in case it's a pointer */ @@ -174,6 +175,7 @@ static GC_thread GC_new_thread(void) { /* the world, wait here. Hopefully this can't happen on any */ /* systems that don't allow us to block here. */ while (GC_please_stop) Sleep(20); + GC_ASSERT(!thread_table[i]->thread_blocked); return thread_table + i; } @@ -223,7 +225,6 @@ static void GC_delete_thread(DWORD thread_id) { } } - #ifdef CYGWIN32 /* Return a GC_thread corresponding to a given pthread_t. */ @@ -245,6 +246,20 @@ static GC_thread GC_lookup_thread(pthread_t id) return thread_table + i; } +#else + +static GC_thread GC_lookup_thread(DWORD id) +{ + int i; + LONG max = GC_get_max_thread_index(); + + for (i = 0; i <= max; i++) + if (thread_table[i].in_use && thread_table[i].id == id) + return &thread_table[i]; + + return NULL; +} + #endif /* CYGWIN32 */ void GC_push_thread_structures GC_PROTO((void)) @@ -264,6 +279,35 @@ void GC_push_thread_structures GC_PROTO((void)) # endif } +/* Wrappers for functions that are likely to block for an appreciable */ +/* length of time. Must be called in pairs, if at all. */ +/* Nothing much beyond the system call itself should be executed */ +/* between these. */ + +void GC_start_blocking(void) { + GC_thread me; + LOCK(); +#ifdef CYGWIN32 + me = GC_lookup_thread(pthread_self()); +#else + me = GC_lookup_thread(GetCurrentThreadId()); +#endif + me->thread_blocked = TRUE; + UNLOCK(); +} + +void GC_end_blocking(void) { + GC_thread me; + LOCK(); /* This will block if the world is stopped. */ +#ifdef CYGWIN32 + me = GC_lookup_thread(pthread_self()); +#else + me = GC_lookup_thread(GetCurrentThreadId()); +#endif + me->thread_blocked = FALSE; + UNLOCK(); +} + /* Defined in misc.c */ extern CRITICAL_SECTION GC_write_cs; @@ -281,6 +325,8 @@ void GC_stop_world() for (i = 0; i <= GC_get_max_thread_index(); i++) if (thread_table[i].stack_base != 0 && thread_table[i].id != thread_id) { + if (thread_table [i].thread_blocked) + continue; # ifdef MSWINCE /* SuspendThread will fail if thread is running kernel code */ while (SuspendThread(thread_table[i].handle) == (DWORD)-1) |