[Gc] GC + dylibs on Darwin/OS X

Jesse Rosenstock jmr@ugcs.caltech.edu
Mon, 10 Mar 2003 21:43:23 -0800


Your message dated: Wed, 05 Mar 2003 16:05:10 EST
>There still seem to be some problems with the threading code (from  
>Jesse Rosenstock's patch). It seems like it randomly hangs every once  
>and a while. To make things even more interesting, it makes gdb very  
>upset.

Because of what you said about the semaphore_* calls, I rewrote it to
use sem_open.  I still don't think it's right because if I always use
the same semaphore names in different processes and take out the
exponential backoff for retrying, it still crashes.  Try removing them 
if you want to look at it.

I don't like the bit about retrying until a semaphore name that doesn't
exist is found at all.  Please, someone figure out a better way.

Why couldn't Apple have implemented sem_init?  It looks like it would be
very simple.  I'd do it and send them the patch, but the when I tried
compiling an (unmodified) kernel, it didn't boot.  Does anyone have an
ideas there?

The diff is against the sources resulting from the previous set of
patches.

--- gc6.2alpha3-threads.save2/linux_threads.c	2003-03-06 21:56:00.000000000 -0800
+++ gc6.2alpha3-threads/linux_threads.c	2003-03-10 21:35:45.000000000 -0800
@@ -108,6 +108,8 @@
 # include <fcntl.h>
 
 #if defined(GC_MACOSX_THREADS)
+# include <stdio.h>
+# include <sys/stat.h>
 # include <sys/sysctl.h>
 #endif /* GC_MACOSX_THREADS */
 
@@ -516,11 +518,7 @@
 #endif
 
 #ifdef GC_MACOSX_THREADS
-#  include <mach/task.h>
-#  include <mach/mach_init.h>
-#  include <mach/semaphore.h>
-
-   semaphore_t GC_suspend_ack_sem;
+   sem_t *GC_suspend_ack_sem;
 #else
    sem_t GC_suspend_ack_sem;
 #endif
@@ -688,7 +686,7 @@
     /* thread has been stopped.  Note that sem_post() is  	*/
     /* the only async-signal-safe primitive in LinuxThreads.    */
 #   ifdef GC_MACOSX_THREADS
-      semaphore_signal(GC_suspend_ack_sem);
+      sem_post(GC_suspend_ack_sem);
 #   else
       sem_post(&GC_suspend_ack_sem);
 #   endif
@@ -1016,8 +1014,8 @@
 #   endif /* GC_MACOSX_THREADS */
     for (i = 0; i < n_live_threads; i++) {
 #	ifdef GC_MACOSX_THREADS
-	  if (KERN_SUCCESS != semaphore_wait(GC_suspend_ack_sem))
-	      ABORT("semaphore_wait in handler failed");
+	  if (0 != sem_wait(GC_suspend_ack_sem))
+	      ABORT("sem_wait in handler failed");
 #	else
 	  if (0 != sem_wait(&GC_suspend_ack_sem))
 	      ABORT("sem_wait in handler failed");
@@ -1316,14 +1314,34 @@
     int dummy;
     GC_thread t;
     struct sigaction act;
+#   ifdef GC_MACOSX_THREADS
+      struct timespec ts = { 0, 0 };
+      int i;
+#   endif
 
     if (GC_thr_initialized) return;
     GC_thr_initialized = TRUE;
 
 #   ifdef GC_MACOSX_THREADS
-      if (semaphore_create(mach_task_self(), &GC_suspend_ack_sem,
-			   SYNC_POLICY_FIFO, 0) != KERN_SUCCESS)
-	  ABORT("semaphore_create failed");
+      for (i = 0; ; i++) {
+	  /* char sem_name[SEM_NAME_LEN + 1]; */
+	  /* SEM_NAME_LEN isn't defined on OS X 10.2.4 */
+	  char sem_name[31 + 1];
+	  snprintf(sem_name, sizeof(sem_name), "/gc_suspend_ack_sem_%u",
+		   (unsigned) (getpid() ^ time(NULL)));
+	  GC_suspend_ack_sem = sem_open(sem_name, O_CREAT | O_EXCL,
+					S_IRUSR | S_IWUSR, 0);
+	  if (GC_suspend_ack_sem != (sem_t *) SEM_FAILED) {
+	      sem_unlink(sem_name);
+	      break;
+	  }
+	  if (errno != EEXIST)
+	      ABORT("sem_open failed");
+	  if (i > 24)
+	      i = 24;
+	  ts.tv_nsec = 1 << i;
+	  nanosleep(&ts, NULL);
+      }
 #   else
       if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
 	  ABORT("sem_init failed");
@@ -1538,7 +1556,7 @@
     void *arg;
     word flags;
 #ifdef GC_MACOSX_THREADS
-    semaphore_t registered;
+    sem_t *registered;
 #else
     sem_t registered;   	/* 1 ==> in our thread table, but 	*/
 				/* parent hasn't yet noticed.		*/
@@ -1672,7 +1690,7 @@
 #   endif
     start_arg = si -> arg;
 #   ifdef GC_MACOSX_THREADS
-      semaphore_signal(si->registered);
+      sem_post(si->registered);
 #   else
       sem_post(&(si -> registered));	/* Last action on si.	*/
 #   endif
@@ -1709,6 +1727,10 @@
     struct start_info * si; 
 	/* This is otherwise saved only in an area mmapped by the thread */
 	/* library, which isn't visible to the collector.		 */
+#   ifdef GC_MACOSX_THREADS
+      struct timespec ts = { 0, 0 };
+      int i;
+#   endif
  
     /* We resist the temptation to muck with the stack size here,	*/
     /* even if the default is unreasonably small.  That's the client's	*/
@@ -1721,7 +1743,25 @@
     if (!parallel_initialized) GC_init_parallel();
     if (0 == si) return(ENOMEM);
 #   ifdef GC_MACOSX_THREADS
-      semaphore_create(mach_task_self(), &si->registered, SYNC_POLICY_FIFO, 0);
+      for (i = 0; ; i++) {
+          /* char sem_name[SEM_NAME_LEN + 1]; */
+          /* SEM_NAME_LEN isn't defined on OS X 10.2.4 */
+          char sem_name[31 + 1];
+          snprintf(sem_name, sizeof(sem_name), "/gc_registered_sem_%u",
+		   (unsigned) (getpid() ^ time(NULL)));
+	  si->registered = sem_open(sem_name, O_CREAT | O_EXCL,
+				    S_IRUSR | S_IWUSR, 0);
+	  if (si->registered != (sem_t *) SEM_FAILED) {
+	      sem_unlink(sem_name);
+	      break;
+	  }
+	  if (errno != EEXIST)
+	      ABORT("sem_open failed");
+	  if (i > 24)
+	      i = 24;
+	  ts.tv_nsec = 1 << i;
+	  nanosleep(&ts, NULL);
+      }
 #   else
       sem_init(&(si -> registered), 0, 0);
 #   endif
@@ -1751,8 +1791,10 @@
     /* with it.  Thus it doesn't matter whether it is otherwise		*/
     /* visible to the collector.					*/
 #	ifdef GC_MACOSX_THREADS
-	    semaphore_wait(si->registered);
-	    semaphore_destroy(mach_task_self(), si->registered);
+	    while (0 != sem_wait(si->registered)) {
+		if (EINTR != errno) ABORT("sem_wait failed");
+	    }
+	    sem_close(si->registered);
 #	else
 	    while (0 != sem_wait(&(si -> registered))) {
 		if (EINTR != errno) ABORT("sem_wait failed");