# define GC_NO_PTHREAD_SIGMASK
#endif
-#if defined(__native_client__) && !defined(GC_PTHREAD_CREATE_CONST)
+#if defined(__native_client__)
/* At present, NaCl pthread_create() prototype does not have "const" */
- /* for "attr" argument. */
-# define GC_PTHREAD_CREATE_CONST /* empty */
+ /* for its "attr" argument; also, NaCl pthread_exit() one does not */
+ /* have "noreturn" attribute. */
+# ifndef GC_PTHREAD_CREATE_CONST
+# define GC_PTHREAD_CREATE_CONST /* empty */
+# endif
+# ifndef GC_PTHREAD_EXIT_ATTRIBUTE
+# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
+# endif
#endif
#ifndef GC_NO_DLOPEN
#if !defined(GC_PTHREAD_EXIT_ATTRIBUTE) && !defined(PLATFORM_ANDROID) \
&& (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
- /* Intercept pthread_cancel and pthread_exit on Linux and Solaris. */
+ /* Intercept pthread_exit on Linux and Solaris. */
# if defined(__GNUC__) /* since GCC v2.7 */
# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
# elif defined(__NORETURN) /* used in Solaris */
# endif
#endif
+#if (!defined(GC_PTHREAD_EXIT_ATTRIBUTE) || defined(__native_client__)) \
+ && !defined(GC_NO_PTHREAD_CANCEL)
+ /* Either there is no pthread_cancel() or no need to intercept it. */
+# define GC_NO_PTHREAD_CANCEL
+#endif
+
+#ifndef GC_NO_PTHREAD_CANCEL
+ GC_API int GC_pthread_cancel(pthread_t);
+#endif
+
#ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# if !defined(__native_client__)
- GC_API int GC_pthread_cancel(pthread_t);
-# endif
GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
#endif
# undef pthread_create
# undef pthread_join
# undef pthread_detach
-
# define pthread_create GC_pthread_create
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
# undef pthread_sigmask
# define pthread_sigmask GC_pthread_sigmask
# endif
-
# ifndef GC_NO_DLOPEN
# undef dlopen
# define dlopen GC_dlopen
# endif
-
+# ifndef GC_NO_PTHREAD_CANCEL
+# undef pthread_cancel
+# define pthread_cancel GC_pthread_cancel
+# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# if !defined(__native_client__)
-# undef pthread_cancel
-# define pthread_cancel GC_pthread_cancel
-# endif
# undef pthread_exit
# define pthread_exit GC_pthread_exit
# endif
# ifndef GC_NO_PTHREAD_SIGMASK
# undef pthread_sigmask
# endif
+# ifndef GC_NO_PTHREAD_CANCEL
+# undef pthread_cancel
+# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
-# undef pthread_cancel
-# endif
# undef pthread_exit
# endif
# undef pthread_join
# define pthread_create __pthread_create
# define pthread_join __pthread_join
# define pthread_detach __pthread_detach
+# ifndef GC_NO_PTHREAD_CANCEL
+# define pthread_cancel __pthread_cancel
+# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
-# define pthread_cancel __pthread_cancel
-# endif
# define pthread_exit __pthread_exit
# endif
# endif
# ifndef GC_NO_PTHREAD_SIGMASK
int REAL_FUNC(pthread_sigmask)(int, const sigset_t *, sigset_t *);
# endif
+# ifndef GC_NO_PTHREAD_CANCEL
+ int REAL_FUNC(pthread_cancel)(pthread_t);
+# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
- int REAL_FUNC(pthread_cancel)(pthread_t);
-# endif
void REAL_FUNC(pthread_exit)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
# endif
#else
static GC_pthread_join_t REAL_FUNC(pthread_join);
typedef int (* GC_pthread_detach_t)(pthread_t);
static GC_pthread_detach_t REAL_FUNC(pthread_detach);
+# ifndef GC_NO_PTHREAD_CANCEL
+ typedef int (* GC_pthread_cancel_t)(pthread_t);
+ static GC_pthread_cancel_t REAL_FUNC(pthread_cancel);
+# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
- typedef int (* GC_pthread_cancel_t)(pthread_t);
- static GC_pthread_cancel_t REAL_FUNC(pthread_cancel);
-# endif
typedef void (* GC_pthread_exit_t)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
static GC_pthread_exit_t REAL_FUNC(pthread_exit);
# endif
/* Define GC_ functions as aliases for the plain ones, which will */
/* be intercepted. This allows files which include gc.h, and hence */
/* generate references to the GC_ symbols, to see the right symbols. */
- GC_API int GC_pthread_create(pthread_t * t,
- GC_PTHREAD_CREATE_CONST pthread_attr_t *a,
- void * (* fn)(void *), void * arg)
- {
- return pthread_create(t, a, fn, arg);
- }
+ GC_API int GC_pthread_create(pthread_t * t,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *a,
+ void * (* fn)(void *), void * arg)
+ {
+ return pthread_create(t, a, fn, arg);
+ }
-# ifndef GC_NO_PTHREAD_SIGMASK
- GC_API int GC_pthread_sigmask(int how, const sigset_t *mask,
- sigset_t *old)
- {
- return pthread_sigmask(how, mask, old);
- }
-# endif /* !GC_NO_PTHREAD_SIGMASK */
+# ifndef GC_NO_PTHREAD_SIGMASK
+ GC_API int GC_pthread_sigmask(int how, const sigset_t *mask,
+ sigset_t *old)
+ {
+ return pthread_sigmask(how, mask, old);
+ }
+# endif /* !GC_NO_PTHREAD_SIGMASK */
- GC_API int GC_pthread_join(pthread_t t, void **res)
- {
- return pthread_join(t, res);
- }
+ GC_API int GC_pthread_join(pthread_t t, void **res)
+ {
+ return pthread_join(t, res);
+ }
- GC_API int GC_pthread_detach(pthread_t t)
- {
- return pthread_detach(t);
- }
+ GC_API int GC_pthread_detach(pthread_t t)
+ {
+ return pthread_detach(t);
+ }
-# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
- GC_API int GC_pthread_cancel(pthread_t t)
- {
- return pthread_cancel(t);
- }
-# endif /* !NACL */
+# ifndef GC_NO_PTHREAD_CANCEL
+ GC_API int GC_pthread_cancel(pthread_t t)
+ {
+ return pthread_cancel(t);
+ }
+# endif /* !GC_NO_PTHREAD_CANCEL */
- GC_API GC_PTHREAD_EXIT_ATTRIBUTE void GC_pthread_exit(void *retval)
- {
- pthread_exit(retval);
- }
-# endif /* GC_PTHREAD_EXIT_ATTRIBUTE */
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ GC_API GC_PTHREAD_EXIT_ATTRIBUTE void GC_pthread_exit(void *retval)
+ {
+ pthread_exit(retval);
+ }
+# endif /* GC_PTHREAD_EXIT_ATTRIBUTE */
#endif /* Linker-based interception. */
#ifdef GC_USE_DLOPEN_WRAP
REAL_FUNC(pthread_join) = (GC_pthread_join_t)
dlsym(dl_handle, "pthread_join");
REAL_FUNC(pthread_detach) = (GC_pthread_detach_t)
- dlsym(dl_handle, "pthread_detach");
-# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
-# ifndef NACL
- REAL_FUNC(pthread_cancel) = (GC_pthread_cancel_t)
+ dlsym(dl_handle, "pthread_detach");
+# ifndef GC_NO_PTHREAD_CANCEL
+ REAL_FUNC(pthread_cancel) = (GC_pthread_cancel_t)
dlsym(dl_handle, "pthread_cancel");
-# endif
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
REAL_FUNC(pthread_exit) = (GC_pthread_exit_t)
dlsym(dl_handle, "pthread_exit");
# endif
# if defined(THREAD_LOCAL_ALLOC)
GC_destroy_thread_local(&(me->tlfs));
# endif
-# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+# if defined(GC_PTHREAD_EXIT_ATTRIBUTE) || !defined(GC_NO_PTHREAD_CANCEL)
/* Handle DISABLED_GC flag which is set by the */
/* intercepted pthread_cancel or pthread_exit. */
if ((me -> flags & DISABLED_GC) != 0) {
return result;
}
-#ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+#ifndef GC_NO_PTHREAD_CANCEL
/* We should deal with the fact that apparently on Solaris and, */
/* probably, on some Linux we can't collect while a thread is */
/* exiting, since signals aren't handled properly. This currently */
/* risk growing the heap unnecessarily. But it seems that we don't */
/* really have an option in that the process is not in a fully */
/* functional state while a thread is exiting. */
+ GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
+ {
+# ifdef CANCEL_SAFE
+ GC_thread thread_gc_id;
+ DCL_LOCK_STATE;
+# endif
-# ifndef NACL
- GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
- {
-# ifdef CANCEL_SAFE
- GC_thread thread_gc_id;
- DCL_LOCK_STATE;
-# endif
-
- INIT_REAL_SYMS();
-# ifdef CANCEL_SAFE
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- /* We test DISABLED_GC because pthread_exit could be called at */
- /* the same time. (If thread_gc_id is NULL then pthread_cancel */
- /* should return ESRCH.) */
- if (thread_gc_id != 0
- && (thread_gc_id -> flags & DISABLED_GC) == 0) {
- thread_gc_id -> flags |= DISABLED_GC;
- GC_dont_gc++;
- }
- UNLOCK();
-# endif
- return REAL_FUNC(pthread_cancel)(thread);
- }
-# endif /* !NACL */
+ INIT_REAL_SYMS();
+# ifdef CANCEL_SAFE
+ LOCK();
+ thread_gc_id = GC_lookup_thread(thread);
+ /* We test DISABLED_GC because pthread_exit could be called at */
+ /* the same time. (If thread_gc_id is NULL then pthread_cancel */
+ /* should return ESRCH.) */
+ if (thread_gc_id != 0
+ && (thread_gc_id -> flags & DISABLED_GC) == 0) {
+ thread_gc_id -> flags |= DISABLED_GC;
+ GC_dont_gc++;
+ }
+ UNLOCK();
+# endif
+ return REAL_FUNC(pthread_cancel)(thread);
+ }
+#endif /* !GC_NO_PTHREAD_CANCEL */
+#ifdef GC_PTHREAD_EXIT_ATTRIBUTE
GC_API GC_PTHREAD_EXIT_ATTRIBUTE void WRAP_FUNC(pthread_exit)(void *retval)
{
GC_thread me;