(fix commits
fcfae7f,
38e65ea)
* include/private/specific.h (GC_remove_specific): Define as macro
(calls GC_remove_specific_after_fork).
* include/private/specific.h (GC_remove_specific_after_fork): New
GC_INNER function declaration.
* include/private/thread_local_alloc.h [USE_PTHREAD_SPECIFIC
|| USE_COMPILER_TLS || USE_WIN32_COMPILER_TLS || USE_WIN32_SPECIFIC]
(GC_remove_specific_after_fork): New macro (defined to no-op).
* pthread_support.c [CAN_HANDLE_FORK && THREAD_LOCAL_ALLOC]
(GC_remove_all_threads_but_me): Call GC_remove_specific_after_fork
instead of GC_remove_specific (i.e. delete thread-specific control data
for the given thread instead of the current one).
* win32_threads.c [CAN_HANDLE_FORK && THREAD_LOCAL_ALLOC] Like
* specific.c [USE_CUSTOM_SPECIFIC] (GC_setspecific): Add assertion that
the allocation lock is held; remove the corresponding comment.
* specific.c [USE_CUSTOM_SPECIFIC] (GC_remove_specific): Replace to
GC_remove_specific_after_fork (add t argument); replace self local
variable with t argument; update comment;
* specific.c [USE_CUSTOM_SPECIFIC && CAN_HANDLE_FORK]
(GC_remove_specific_after_fork): Add assertion that the allocation lock
is held; add comment.
#define GC_key_create(key, d) GC_key_create_inner(key)
GC_INNER int GC_key_create_inner(tsd ** key_ptr);
GC_INNER int GC_setspecific(tsd * key, void * value);
-GC_INNER void GC_remove_specific(tsd * key);
+#define GC_remove_specific(key) \
+ GC_remove_specific_after_fork(key, pthread_self())
+GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t);
/* An internal version of getspecific that assumes a cache miss. */
GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
# define GC_remove_specific(key) pthread_setspecific(key, NULL)
/* Explicitly delete the value to stop the TLS */
/* destructor from being called repeatedly. */
+# define GC_remove_specific_after_fork(key, t) (void)0
+ /* Should not need any action. */
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. */
+# define GC_remove_specific_after_fork(key, t) (void)0
typedef void * GC_key_t;
#elif defined(USE_WIN32_SPECIFIC)
# ifndef WIN32_LEAN_AND_MEAN
((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
# define GC_remove_specific(key) /* No need for cleanup on exit. */
/* Need TlsFree on process exit/detach? */
+# define GC_remove_specific_after_fork(key, t) (void)0
typedef DWORD GC_key_t;
#elif defined(USE_CUSTOM_SPECIFIC)
# include "private/specific.h"
# ifdef THREAD_LOCAL_ALLOC
if (!(p -> flags & FINISHED)) {
GC_destroy_thread_local(&(p->tlfs));
- GC_remove_specific(GC_thread_key);
+ GC_remove_specific_after_fork(GC_thread_key, p -> id);
}
# endif
if (p != &first_thread) GC_INTERNAL_FREE(p);
return 0;
}
-/* Called with the lock held. */
GC_INNER int GC_setspecific(tsd * key, void * value)
{
pthread_t self = pthread_self();
int hash_val = HASH(self);
volatile tse * entry;
+ GC_ASSERT(I_HOLD_LOCK());
GC_ASSERT(self != INVALID_THREADID);
GC_dont_gc++; /* disable GC */
entry = (volatile tse *)MALLOC_CLEAR(sizeof(tse));
return 0;
}
-/* Remove thread-specific data for this thread. Should be called on */
-/* thread exit. */
-GC_INNER void GC_remove_specific(tsd * key)
+/* Remove thread-specific data for a given thread. This function is */
+/* called at fork from the child process for all threads except for the */
+/* survived one. GC_remove_specific() should be called on thread exit. */
+GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t)
{
- pthread_t self = pthread_self();
- unsigned hash_val = HASH(self);
+ unsigned hash_val = HASH(t);
tse *entry;
tse **link = &key->hash[hash_val].p;
+# ifdef CAN_HANDLE_FORK
+ /* Both GC_setspecific and GC_remove_specific should be called */
+ /* with the allocation lock held to ensure the consistency of */
+ /* the hash table in the forked child. */
+ GC_ASSERT(I_HOLD_LOCK());
+# endif
pthread_mutex_lock(&(key -> lock));
entry = *link;
- while (entry != NULL && entry -> thread != self) {
+ while (entry != NULL && entry -> thread != t) {
link = &(entry -> next);
entry = *link;
}
# ifdef THREAD_LOCAL_ALLOC
if ((p -> flags & FINISHED) == 0) {
GC_destroy_thread_local(&p->tlfs);
- GC_remove_specific(GC_thread_key);
+ GC_remove_specific_after_fork(GC_thread_key, p -> pthread_id);
}
# endif
if (&first_thread != p)