+2011-05-11 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_unregister_my_thread_inner): Don't call
+ GC_remove_specific.
+ * include/private/thread_local_alloc.h (GC_remove_specific):
+ Remove (since it is empty for all targets).
+ * pthread_support.c (GC_record_stack_base): New inline function.
+ * win32_threads.c (GC_record_stack_base): Ditto.
+ * pthread_support.c (GC_register_my_thread_inner): Invoke
+ GC_record_stack_base.
+ * win32_threads.c (GC_register_my_thread_inner): Ditto.
+ * pthread_support.c (GC_register_my_thread): If thread is FINISHED
+ then call GC_record_stack_base, clear FINISHED, initialize
+ thread-local list and return success.
+ * win32_threads.c (GC_register_my_thread): Ditto.
+ * include/gc.h (GC_register_my_thread): Update documentation.
+ * include/private/thread_local_alloc.h (GC_thread_key): Ditto.
+
2011-05-10 Ivan Maidanski <ivmai@mail.ru>
* thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Join
/* always done implicitly. This is normally done implicitly if GC_ */
/* functions are called to create the thread, e.g. by including gc.h */
/* (which redefines some system functions) before calling the system */
- /* thread creation function. */
+ /* thread creation function. Nonetheless, thread cleanup routines */
+ /* (eg., pthread key destructor) typically require manual thread */
+ /* registering (and unregistering) if pointers to GC-allocated */
+ /* objects are manipulated inside. */
/* It is also always done implicitly on some platforms if */
/* GC_use_threads_discovery() is called at start-up. Except for the */
/* latter case, the explicit call is normally required for threads */
# define GC_getspecific pthread_getspecific
# define GC_setspecific pthread_setspecific
# define GC_key_create pthread_key_create
-# define GC_remove_specific(key) /* No need for cleanup on exit. */
typedef pthread_key_t GC_key_t;
# elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
# define GC_getspecific(x) (x)
# define GC_setspecific(key, v) ((key) = (v), 0)
# define GC_key_create(key, d) 0
-# define GC_remove_specific(key) /* No need for cleanup on exit. */
typedef void * GC_key_t;
# elif defined(USE_WIN32_SPECIFIC)
# ifndef WIN32_LEAN_AND_MEAN
# endif
# define GC_key_create(key, d) \
((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
-# define GC_remove_specific(key) /* No need for cleanup on thread exit. */
/* Need TlsFree on process exit/detach ? */
typedef DWORD GC_key_t;
# elif defined(USE_CUSTOM_SPECIFIC)
__declspec(thread)
#endif
GC_key_t GC_thread_key;
-
-/* This is set up by the thread_local_alloc implementation. But the */
-/* thread support layer calls GC_remove_specific(GC_thread_key) */
-/* before a thread exits. */
-/* And the thread support layer makes sure that GC_thread_key is traced,*/
-/* if necessary. */
+/* This is set up by the thread_local_alloc implementation. No need */
+/* for cleanup on thread exit. But the thread support layer makes sure */
+/* that GC_thread_key is traced, if necessary. */
#endif /* THREAD_LOCAL_ALLOC */
} else {
me -> flags |= FINISHED;
}
-# if defined(THREAD_LOCAL_ALLOC)
- GC_remove_specific(GC_thread_key);
-# endif
}
GC_API int GC_CALL GC_unregister_my_thread(void)
GC_INNER GC_bool GC_in_thread_creation = FALSE;
/* Protected by allocation lock. */
+GC_INLINE void GC_record_stack_base(GC_thread me,
+ const struct GC_stack_base *sb)
+{
+# ifndef GC_DARWIN_THREADS
+ me -> stop_info.stack_ptr = sb -> mem_base;
+# endif
+ me -> stack_end = sb -> mem_base;
+ if (me -> stack_end == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+}
+
STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
pthread_t my_pthread)
{
ABORT("Failed to allocate memory for thread registering");
# ifdef GC_DARWIN_THREADS
me -> stop_info.mach_thread = mach_thread_self();
-# else
- me -> stop_info.stack_ptr = sb -> mem_base;
# endif
- me -> stack_end = sb -> mem_base;
- if (me -> stack_end == NULL)
- ABORT("Bad stack base in GC_register_my_thread");
-# ifdef IA64
- me -> backing_store_end = sb -> reg_base;
-# endif /* IA64 */
+ GC_record_stack_base(me, sb);
return me;
}
LOCK();
me = GC_lookup_thread(self);
- if (0 == me) {
- me = GC_register_my_thread_inner(sb, self);
+ if (0 == me || (me -> flags & FINISHED) != 0) {
+ if (me == 0) {
+ me = GC_register_my_thread_inner(sb, self);
+ } else {
+ GC_record_stack_base(me, sb);
+ me -> flags &= ~FINISHED;
+ }
me -> flags |= DETACHED;
/* Treat as detached, since we do not need to worry about */
/* pointer results. */
STATIC GC_bool GC_in_thread_creation = FALSE;
/* Protected by allocation lock. */
+GC_INLINE void GC_record_stack_base(GC_vthread me,
+ const struct GC_stack_base *sb)
+{
+ me -> stack_base = sb -> mem_base;
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+ if (me -> stack_base == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+}
+
/* This may be called from DllMain, and hence operates under unusual */
/* constraints. In particular, it must be lock-free if */
/* GC_win32_dll_threads is set. Always called from the thread being */
}
# endif
me -> last_stack_min = ADDR_LIMIT;
- me -> stack_base = sb -> mem_base;
-# ifdef IA64
- me -> backing_store_end = sb -> reg_base;
-# endif
+ GC_record_stack_base(me, sb);
/* Up until this point, GC_push_all_stacks considers this thread */
/* invalid. */
/* Up until this point, this entry is viewed as reserved but invalid */
# if defined(THREAD_LOCAL_ALLOC)
GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
# endif
- if (me -> stack_base == NULL)
- ABORT("Bad stack base in GC_register_my_thread_inner");
# ifndef GC_NO_THREADS_DISCOVERY
if (GC_win32_dll_threads) {
if (GC_please_stop) {
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
{
+ GC_thread me;
DWORD thread_id = GetCurrentThreadId();
DCL_LOCK_STATE;
/* We lock here, since we want to wait for an ongoing GC. */
LOCK();
- if (0 == GC_lookup_thread_inner(thread_id)) {
+ me = GC_lookup_thread_inner(thread_id);
+ if (me == 0) {
GC_register_my_thread_inner(sb, thread_id);
+# ifdef GC_PTHREADS
+ me -> flags |= DETACHED;
+# endif
UNLOCK();
return GC_SUCCESS;
- } else {
+ } else
+# ifdef GC_PTHREADS
+ /* else */ if ((me -> flags & FINISHED) != 0) {
+ GC_record_stack_base(me, sb);
+ me -> flags = (me -> flags & ~FINISHED) | DETACHED;
+# ifdef THREAD_LOCAL_ALLOC
+ GC_init_thread_local((GC_tlfs)(&me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else
+# endif
+ /* else */ {
UNLOCK();
return GC_DUPLICATE;
}