Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Unity-Technologies/bdwgc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'linux_threads.c')
-rw-r--r--linux_threads.c152
1 files changed, 111 insertions, 41 deletions
diff --git a/linux_threads.c b/linux_threads.c
index b760ac4a..96943d38 100644
--- a/linux_threads.c
+++ b/linux_threads.c
@@ -107,6 +107,10 @@
# include <sys/stat.h>
# include <fcntl.h>
+#if defined(GC_MACOSX_THREADS)
+# include <sys/sysctl.h>
+#endif /* GC_MACOSX_THREADS */
+
#if defined(GC_DGUX386_THREADS)
# include <sys/dg_sys_info.h>
# include <sys/_int_psem.h>
@@ -511,7 +515,15 @@ GC_PTR GC_local_gcj_malloc(size_t bytes,
# endif
#endif
-sem_t GC_suspend_ack_sem;
+#ifdef GC_MACOSX_THREADS
+# include <mach/task.h>
+# include <mach/mach_init.h>
+# include <mach/semaphore.h>
+
+ semaphore_t GC_suspend_ack_sem;
+#else
+ sem_t GC_suspend_ack_sem;
+#endif
#if 0
/*
@@ -675,7 +687,11 @@ void GC_suspend_handler(int sig)
/* Tell the thread that wants to stop the world that this */
/* thread has been stopped. Note that sem_post() is */
/* the only async-signal-safe primitive in LinuxThreads. */
- sem_post(&GC_suspend_ack_sem);
+# ifdef GC_MACOSX_THREADS
+ semaphore_signal(GC_suspend_ack_sem);
+# else
+ sem_post(&GC_suspend_ack_sem);
+# endif
me -> last_stop_count = my_stop_count;
/* Wait until that thread tells us to restart by sending */
@@ -965,38 +981,47 @@ void GC_stop_world()
# endif /* PARALLEL_MARK */
++GC_stop_count;
n_live_threads = GC_suspend_all();
- if (GC_retry_signals) {
- unsigned long wait_usecs = 0; /* Total wait since retry. */
-# define WAIT_UNIT 3000
-# define RETRY_INTERVAL 100000
- for (;;) {
- int ack_count;
-
- sem_getvalue(&GC_suspend_ack_sem, &ack_count);
- if (ack_count == n_live_threads) break;
- if (wait_usecs > RETRY_INTERVAL) {
- int newly_sent = GC_suspend_all();
-
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Resent %ld signals after timeout\n",
- newly_sent);
- }
-# endif
- sem_getvalue(&GC_suspend_ack_sem, &ack_count);
- if (newly_sent < n_live_threads - ack_count) {
- WARN("Lost some threads during GC_stop_world?!\n",0);
- n_live_threads = ack_count + newly_sent;
- }
- wait_usecs = 0;
- }
- usleep(WAIT_UNIT);
- wait_usecs += WAIT_UNIT;
- }
- }
+ /* sem_getvalue() is not suppored on OS X, and there does not appear */
+ /* to be a mach equivalent, so we disable this code. */
+# ifndef GC_MACOSX_THREADS
+ if (GC_retry_signals) {
+ unsigned long wait_usecs = 0; /* Total wait since retry. */
+# define WAIT_UNIT 3000
+# define RETRY_INTERVAL 100000
+ for (;;) {
+ int ack_count;
+
+ sem_getvalue(&GC_suspend_ack_sem, &ack_count);
+ if (ack_count == n_live_threads) break;
+ if (wait_usecs > RETRY_INTERVAL) {
+ int newly_sent = GC_suspend_all();
+
+# ifdef CONDPRINT
+ if (GC_print_stats) {
+ GC_printf1("Resent %ld signals after timeout\n",
+ newly_sent);
+ }
+# endif
+ sem_getvalue(&GC_suspend_ack_sem, &ack_count);
+ if (newly_sent < n_live_threads - ack_count) {
+ WARN("Lost some threads during GC_stop_world?!\n",0);
+ n_live_threads = ack_count + newly_sent;
+ }
+ wait_usecs = 0;
+ }
+ usleep(WAIT_UNIT);
+ wait_usecs += WAIT_UNIT;
+ }
+ }
+# endif /* GC_MACOSX_THREADS */
for (i = 0; i < n_live_threads; i++) {
- if (0 != sem_wait(&GC_suspend_ack_sem))
- ABORT("sem_wait in handler failed");
+# ifdef GC_MACOSX_THREADS
+ if (KERN_SUCCESS != semaphore_wait(GC_suspend_ack_sem))
+ ABORT("semaphore_wait in handler failed");
+# else
+ if (0 != sem_wait(&GC_suspend_ack_sem))
+ ABORT("sem_wait in handler failed");
+# endif
}
# ifdef PARALLEL_MARK
GC_release_mark_lock();
@@ -1295,8 +1320,14 @@ void GC_thr_init()
if (GC_thr_initialized) return;
GC_thr_initialized = TRUE;
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
- ABORT("sem_init failed");
+# ifdef GC_MACOSX_THREADS
+ if (semaphore_create(mach_task_self(), &GC_suspend_ack_sem,
+ SYNC_POLICY_FIFO, 0) != KERN_SUCCESS)
+ ABORT("semaphore_create failed");
+# else
+ if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
+ ABORT("sem_init failed");
+# endif
act.sa_flags = SA_RESTART;
if (sigfillset(&act.sa_mask) != 0) {
@@ -1361,6 +1392,12 @@ void GC_thr_init()
# if defined(GC_FREEBSD_THREADS)
GC_nprocs = 1;
# endif
+# if defined(GC_MACOSX_THREADS)
+ int ncpus = 1;
+ size_t len = sizeof(ncpus);
+ sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
+ GC_nprocs = ncpus;
+# endif
# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
GC_nprocs = GC_get_nprocs();
# endif
@@ -1500,8 +1537,12 @@ struct start_info {
void *(*start_routine)(void *);
void *arg;
word flags;
+#ifdef GC_MACOSX_THREADS
+ semaphore_t registered;
+#else
sem_t registered; /* 1 ==> in our thread table, but */
/* parent hasn't yet noticed. */
+#endif
};
/* Called at thread exit. */
@@ -1630,7 +1671,11 @@ void * GC_start_routine(void * arg)
GC_printf1("start_routine = 0x%lx\n", start);
# endif
start_arg = si -> arg;
- sem_post(&(si -> registered)); /* Last action on si. */
+# ifdef GC_MACOSX_THREADS
+ semaphore_signal(si->registered);
+# else
+ sem_post(&(si -> registered)); /* Last action on si. */
+# endif
/* OK to deallocate. */
pthread_cleanup_push(GC_thread_exit_proc, 0);
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
@@ -1675,11 +1720,31 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
UNLOCK();
if (!parallel_initialized) GC_init_parallel();
if (0 == si) return(ENOMEM);
- sem_init(&(si -> registered), 0, 0);
+# ifdef GC_MACOSX_THREADS
+ semaphore_create(mach_task_self(), &si->registered, SYNC_POLICY_FIFO, 0);
+# else
+ sem_init(&(si -> registered), 0, 0);
+# endif
si -> start_routine = start_routine;
si -> arg = arg;
LOCK();
if (!GC_thr_initialized) GC_thr_init();
+# ifdef GC_ASSERTIONS
+ {
+ int stack_size;
+ if (NULL == attr) {
+ pthread_attr_t my_attr;
+ pthread_attr_init(&my_attr);
+ pthread_attr_getstacksize(&my_attr, &stack_size);
+ } else {
+ pthread_attr_getstacksize(attr, &stack_size);
+ }
+ GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
+ /* Our threads may need to do some work for the GC. */
+ /* Ridiculously small threads won't work, and they */
+ /* probably wouldn't work anyway. */
+ }
+# endif
if (NULL == attr) {
detachstate = PTHREAD_CREATE_JOINABLE;
} else {
@@ -1701,10 +1766,15 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
/* This also ensures that we hold onto si until the child is done */
/* with it. Thus it doesn't matter whether it is otherwise */
/* visible to the collector. */
- while (0 != sem_wait(&(si -> registered))) {
- if (EINTR != errno) ABORT("sem_wait failed");
- }
- sem_destroy(&(si -> registered));
+# ifdef GC_MACOSX_THREADS
+ semaphore_wait(si->registered);
+ semaphore_destroy(mach_task_self(), si->registered);
+# else
+ while (0 != sem_wait(&(si -> registered))) {
+ if (EINTR != errno) ABORT("sem_wait failed");
+ }
+ sem_destroy(&(si -> registered));
+# endif
LOCK();
GC_INTERNAL_FREE(si);
UNLOCK();