Discussion:
[Gc] porting Hans Boehm GC to MacOSX
(too old to reply)
Renaud Blanch
2003-02-09 17:23:33 UTC
Permalink
I'm porting a c++ library using gc to Jaguar.
I use fink's port of the lib (gc-6.1-3 avaible in the unstable branch)
and it works great except for one thing :
The lib is not compiled with pthread support, which I need.

The trouble is that gc relies on pthread's implementation specificic
features.
Since Darwin is based on FreeBSD sources I tried to use
-DGC_FREEBSD_THREADS but SIGRTMIN is then undefined and there's issues
with DATASTART and DATAEND definitions (conflicts between MACOSX and
FREEBSD definitions ?).

So my question is :
Has someone already done that work ?
If not, I'm interessed in doing it but I'm not familar with Darwin
pthread internals so ... can someone interessed help me to contribute a
patch to gc ?
I need advice on
- starting from FreeBSD code a good option ?
- what is SIGRTMIN ?
- ...


Renaud

--
***@lri.fr
http://www.lri.fr/~blanch/
Fergus Henderson
2003-02-10 05:32:13 UTC
Permalink
Post by Renaud Blanch
Has someone already done that work ?
If not, I'm interessed in doing it but I'm not familar with Darwin
pthread internals so ... can someone interessed help me to contribute a
patch to gc ?
I need advice on
- starting from FreeBSD code a good option ?
- what is SIGRTMIN ?
The Boehm collector just needs a signal to use for its own purposes.
"SIGRTMIN" is just a random signal chosen in the hope that it won't
interfere with the application's use of signals. If SIGRTMIN isn't
defined on MacOS X, just pick some other signal to use; preferably
the one that is least likely to be used by the application.
--
Fergus Henderson <***@cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
Boehm, Hans
2003-02-10 18:46:28 UTC
Permalink
The garbage collector currently has two major deficiencies on MacOSX:

1) Lack of dynamic library support. It looks like this requires real work, since MacOSX chose not to use the ELF executable file format. Until someone fixes this, the collector won't see pointers in dynamic library data sections. The fix involves devising a way to enumerate these data sections. (Something like dl_iterate_phdr() in glibc.) Once you have that, the rest is easy.

2) Pthread support.

Both of these have been discussed on the ***@gcc.gnu.org mailing list.

As far as pthread support is concerned, I would like to see the linux_threads.c code turn into generic pthread support. I think it's very close. As the comments say, it relies on pthread internals, but currently only to a small extent. The code currently supports some very different pthread implementations, though admittedly with a few ifdefs here and there. (The Irix support code is different only because I couldn't test the result if I reintegrated it. The Solaris thread support code is currently very different for historical reasons, and the issues there are more complicated. But I believe linux_threads.c could be made to work with modern Solaris versions as well.)

I'm not a Darwin expert, but here's what I gathered from other discussions:
Things appear to be complicated by the fact that at least early releases didn't contain a full pthread implementation. In particular, signals and pthread_kill were not really supported. The collector relies on those. It seemed possible to work around that by reaching into the underlying Mach layer, but documentation for that seemed scarce. I'm not sure if/when that was fixed. It may be acceptable just to ignore that problem for now. If so, the FreeBSD code may be close. If you need to deal with the Mach layer, there's a lot more work to be done.

My suggestion would be:

1) I would start with the most recent GC version, i.e. 6.2alpha3. I think it contains some relevant fixes.

2) Introduce a GC_MACOSX_THREADS macro that's used analogously to the GC_FREEBSD_THREADS macro. Initially handle both in the same way. (But use the existing FREEBSD definitions of DATASTART, etc. Handle MACOSX like FREEBSD, but don't tell the collector that MACOSX is FREEBSD.)

3) Add a suitable definitions of SIG_SUSPEND (in gc_priv.h). (Ideally this should probably be moved to gcconfig.h) It looks like SIG_THR_RESTART is getting defined to SIGXCPU in linux_threads.c. I would guess that's OK.

Hans
-----Original Message-----
Sent: Sunday, February 09, 2003 9:24 AM
Subject: [Gc] porting Hans Boehm GC to MacOSX
I'm porting a c++ library using gc to Jaguar.
I use fink's port of the lib (gc-6.1-3 avaible in the
unstable branch)
The lib is not compiled with pthread support, which I need.
The trouble is that gc relies on pthread's implementation specificic
features.
Since Darwin is based on FreeBSD sources I tried to use
-DGC_FREEBSD_THREADS but SIGRTMIN is then undefined and
there's issues
with DATASTART and DATAEND definitions (conflicts between MACOSX and
FREEBSD definitions ?).
Has someone already done that work ?
If not, I'm interessed in doing it but I'm not familar with Darwin
pthread internals so ... can someone interessed help me to
contribute a
patch to gc ?
I need advice on
- starting from FreeBSD code a good option ?
- what is SIGRTMIN ?
- ...
Renaud
--
http://www.lri.fr/~blanch/
_______________________________________________
Gc mailing list
http://linux.hpl.hp.com/cgi-bin/mailman/listinfo/gc
Jeff Sturm
2003-02-11 04:20:17 UTC
Permalink
Post by Boehm, Hans
2) Pthread support.
I've experimented with a simple patch to compile the threaded collector
for OSX using linux_threads.c. Unfortunately it does not work.

Running gctest:

Immediately reclaimed 0 bytes in heap of size 65536 bytes
0 (atomic) + 0 (composite) collectable bytes in use
Finalize + initiate sweep took 0 + 0 msecs
Adding block map for size 6
About to start new thread from thread 0xA0000DEC
Started thread 0xBA430
sem_wait complete from thread 0xA0000DEC
About to start new thread from thread 0xA0000DEC
Started thread 0x0
sem_wait complete from thread 0xA0000DEC
Thread 2 creation failed 35
Test failed
Abort

pthread_create returns EAGAIN for some reason. I don't know how to debug
this further. If anyone wants to try it I can provide my incomplete port.

Jeff
Jesse Rosenstock
2003-02-13 09:00:56 UTC
Permalink
Based on Jeff Sturm's patches, the gc now passes gctest on OS X. Most
of the credit goes to him, I just noticed a small bug in his code.

Things to note:

The changes to linux_threads.c are kind of ugly, with lots of #ifdefs
to call Mach semaphore_* calls instead of sem_* because sem_init()
and sem_destroy() always return an error. If something else would
be better, introducing GC_sem_* macros, I'll do that instead.

There appears to be no Mach equivalent for sem_getvalue(), so the
GC_retry_signals code is #ifdefed out.

I too experienced problems with MPROTECT_VDB, so that is still not #defined.

I'm also none too sure about the DATASTART and DATAEND
definitions. They use get_etext() and get_end(), whose use is
"very strongly discouraged" according to the man page. See
http://www.hmug.org/man/3/end.html

Shared libraries are still unsupported, so if you use configure,
be sure to pass --disable-shared. Also, I did not re-run autoconf.

Here are the patches. Please review and comment.

diff -ur gc6.2alpha3.orig/Makefile gc6.2alpha3-threads/Makefile
--- gc6.2alpha3.orig/Makefile 2003-01-29 20:12:07.000000000 -0800
+++ gc6.2alpha3-threads/Makefile 2003-02-13 00:14:52.000000000 -0800
@@ -73,6 +73,7 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
+# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
diff -ur gc6.2alpha3.orig/Makefile.direct gc6.2alpha3-threads/Makefile.direct
--- gc6.2alpha3.orig/Makefile.direct 2003-01-27 15:59:50.000000000 -0800
+++ gc6.2alpha3-threads/Makefile.direct 2003-02-12 22:28:27.000000000 -0800
@@ -73,6 +73,7 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
+# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
diff -ur gc6.2alpha3.orig/configure.in gc6.2alpha3-threads/configure.in
--- gc6.2alpha3.orig/configure.in 2002-10-11 06:54:12.000000000 -0700
+++ gc6.2alpha3-threads/configure.in 2003-02-12 22:29:48.000000000 -0800
@@ -136,6 +136,9 @@
*-*-cygwin*)
AC_DEFINE(GC_WIN32_THREADS)
;;
+ *-*-darwin*)
+ AC_DEFINE(GC_MACOSX_THREADS)
+ ;;
*-*-osf*)
AC_DEFINE(GC_OSF1_THREADS)
if test "${enable_parallel_mark}" = yes; then
diff -ur gc6.2alpha3.orig/gc_dlopen.c gc6.2alpha3-threads/gc_dlopen.c
--- gc6.2alpha3.orig/gc_dlopen.c 2003-01-23 14:41:28.000000000 -0800
+++ gc6.2alpha3-threads/gc_dlopen.c 2003-02-12 10:54:22.000000000 -0800
@@ -25,7 +25,8 @@

#include "private/gc_priv.h"

-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
+# if (defined(GC_PTHREADS) && !defined(GC_MACOSX_THREADS)) \
+ || defined(GC_SOLARIS_THREADS)

# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
/* To support various threads pkgs, gc.h interposes on dlopen by */
diff -ur gc6.2alpha3.orig/include/gc.h gc6.2alpha3-threads/include/gc.h
--- gc6.2alpha3.orig/include/gc.h 2003-01-29 09:35:33.000000000 -0800
+++ gc6.2alpha3-threads/include/gc.h 2003-02-11 22:08:30.000000000 -0800
@@ -84,7 +84,7 @@
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
- defined(GC_DGUX386_THREADS) || \
+ defined(GC_DGUX386_THREADS) || defined(GC_MACOSX_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
diff -ur gc6.2alpha3.orig/include/private/gcconfig.h gc6.2alpha3-threads/include/private/gcconfig.h
--- gc6.2alpha3.orig/include/private/gcconfig.h 2003-01-29 09:47:10.000000000 -0800
+++ gc6.2alpha3-threads/include/private/gcconfig.h 2003-02-12 23:57:54.000000000 -0800
@@ -714,13 +714,26 @@
/* There are reasons to suspect this may not be reliable. */
# define ALIGNMENT 4
# define OS_TYPE "MACOSX"
+# ifdef GC_MACOSX_THREADS
+# define SIG_SUSPEND SIGXCPU
+# define SIG_THR_RESTART SIGXFSZ
+# endif
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used */
# define DATASTART ((ptr_t) get_etext())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
-# define DATAEND /* not needed */
+# define DATAEND ((ptr_t) get_end())
/* # define MPROTECT_VDB -- There is some evidence that this breaks
- * on some minor versions of MACOSX. In theory, it should be OK */
+ * on some minor versions of MACOSX, i.e. 10.2.3. In theory,
+ * it should be OK */
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
+# ifdef __GNUC__
+ /* The performance impact of prefetches is untested */
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
+# endif
# endif
# ifdef NETBSD
# define ALIGNMENT 4
diff -ur gc6.2alpha3.orig/linux_threads.c gc6.2alpha3-threads/linux_threads.c
--- gc6.2alpha3.orig/linux_threads.c 2002-10-01 15:36:06.000000000 -0700
+++ gc6.2alpha3-threads/linux_threads.c 2003-02-12 23:33:57.000000000 -0800
@@ -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 @@
# 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 @@
/* 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 @@
# 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 @@
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 @@
# 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 @@
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 @@
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,7 +1720,11 @@
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();
@@ -1701,10 +1750,15 @@
/* 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();
diff -ur gc6.2alpha3.orig/tests/test.c gc6.2alpha3-threads/tests/test.c
--- gc6.2alpha3.orig/tests/test.c 2002-11-06 09:28:14.000000000 -0800
+++ gc6.2alpha3-threads/tests/test.c 2003-02-11 22:00:25.000000000 -0800
@@ -1748,7 +1748,8 @@
}
# endif /* GC_HPUX_THREADS */
pthread_attr_init(&attr);
-# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS)
+# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_MACOSX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
diff -ur gc6.2alpha3.orig/threadlibs.c gc6.2alpha3-threads/threadlibs.c
--- gc6.2alpha3.orig/threadlibs.c 2002-08-01 18:16:21.000000000 -0700
+++ gc6.2alpha3-threads/threadlibs.c 2003-02-11 21:58:30.000000000 -0800
@@ -10,7 +10,8 @@
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
# endif
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS)
+ || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
+ || defined(GC_MACOSX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
Andreas Tobler
2003-02-13 11:04:30 UTC
Permalink
-- Original Message --
Based on Jeff Sturm's patches, the gc now passes gctest on OS X. Most
of the credit goes to him, I just noticed a small bug in his code.
The changes to linux_threads.c are kind of ugly, with lots of #ifdefs
to call Mach semaphore_* calls instead of sem_* because sem_init()
and sem_destroy() always return an error. If something else would
be better, introducing GC_sem_* macros, I'll do that instead.
There appears to be no Mach equivalent for sem_getvalue(), so the
GC_retry_signals code is #ifdefed out.
Not yet applied here.
Shared libraries are still unsupported, so if you use configure,
be sure to pass --disable-shared. Also, I did not re-run autoconf.
Here are the patches. Please review and comment.
Here my first 'real life' feedback.

I applied the version from early this morning (without the retry sig commented)
to the gcc-boehm in gcc-3.3 branch

In the area of libjava I see a failure reduction by at least 6 TC's.

GREAT.
I continue this evening, also I'll apply this patch and test it.

Thank you for work!

Andreas
Jesse Rosenstock
2003-02-13 18:34:37 UTC
Permalink
Here's a new version of the patch. I've introduced a USE_PPC_PREFETCH
#define to guard the prefetch stuff instead of doing it unconditionally,
and switched MACOSX to USE_MMAP, but with USE_MMAP_ANON which I also
added because mapping /dev/zero doesn't seem to work. Everything else
should be the same as before.

diff -ur gc6.2alpha3.orig/Makefile gc6.2alpha3-threads/Makefile
--- gc6.2alpha3.orig/Makefile 2003-01-29 20:12:07.000000000 -0800
+++ gc6.2alpha3-threads/Makefile 2003-02-13 10:15:01.000000000 -0800
@@ -73,6 +73,7 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
+# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
@@ -218,6 +219,9 @@
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
+# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
+# prefetch instructions. No effect except on PowerPC OS X platforms.
+# Performance impact untested.
# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
# causes the collector some system and pthread calls in a more transparent
# fashion than the usual macro-based approach. Requires GNU ld, and
diff -ur gc6.2alpha3.orig/Makefile.direct gc6.2alpha3-threads/Makefile.direct
--- gc6.2alpha3.orig/Makefile.direct 2003-01-27 15:59:50.000000000 -0800
+++ gc6.2alpha3-threads/Makefile.direct 2003-02-13 10:13:00.000000000 -0800
@@ -73,6 +73,7 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
+# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
@@ -218,6 +219,9 @@
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
+# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
+# prefetch instructions. No effect except on PowerPC OS X platforms.
+# Performance impact untested.
# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
# causes the collector some system and pthread calls in a more transparent
# fashion than the usual macro-based approach. Requires GNU ld, and
diff -ur gc6.2alpha3.orig/configure.in gc6.2alpha3-threads/configure.in
--- gc6.2alpha3.orig/configure.in 2002-10-11 06:54:12.000000000 -0700
+++ gc6.2alpha3-threads/configure.in 2003-02-12 22:29:48.000000000 -0800
@@ -136,6 +136,9 @@
*-*-cygwin*)
AC_DEFINE(GC_WIN32_THREADS)
;;
+ *-*-darwin*)
+ AC_DEFINE(GC_MACOSX_THREADS)
+ ;;
*-*-osf*)
AC_DEFINE(GC_OSF1_THREADS)
if test "${enable_parallel_mark}" = yes; then
diff -ur gc6.2alpha3.orig/gc_dlopen.c gc6.2alpha3-threads/gc_dlopen.c
--- gc6.2alpha3.orig/gc_dlopen.c 2003-01-23 14:41:28.000000000 -0800
+++ gc6.2alpha3-threads/gc_dlopen.c 2003-02-12 10:54:22.000000000 -0800
@@ -25,7 +25,8 @@

#include "private/gc_priv.h"

-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
+# if (defined(GC_PTHREADS) && !defined(GC_MACOSX_THREADS)) \
+ || defined(GC_SOLARIS_THREADS)

# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
/* To support various threads pkgs, gc.h interposes on dlopen by */
diff -ur gc6.2alpha3.orig/include/gc.h gc6.2alpha3-threads/include/gc.h
--- gc6.2alpha3.orig/include/gc.h 2003-01-29 09:35:33.000000000 -0800
+++ gc6.2alpha3-threads/include/gc.h 2003-02-11 22:08:30.000000000 -0800
@@ -84,7 +84,7 @@
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
- defined(GC_DGUX386_THREADS) || \
+ defined(GC_DGUX386_THREADS) || defined(GC_MACOSX_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
diff -ur gc6.2alpha3.orig/include/private/gcconfig.h gc6.2alpha3-threads/include/private/gcconfig.h
--- gc6.2alpha3.orig/include/private/gcconfig.h 2003-01-29 09:47:10.000000000 -0800
+++ gc6.2alpha3-threads/include/private/gcconfig.h 2003-02-13 10:19:25.000000000 -0800
@@ -714,13 +714,28 @@
/* There are reasons to suspect this may not be reliable. */
# define ALIGNMENT 4
# define OS_TYPE "MACOSX"
+# ifdef GC_MACOSX_THREADS
+# define SIG_SUSPEND SIGXCPU
+# define SIG_THR_RESTART SIGXFSZ
+# endif
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used */
# define DATASTART ((ptr_t) get_etext())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
-# define DATAEND /* not needed */
+# define DATAEND ((ptr_t) get_end())
+# define USE_MMAP
+# define USE_MMAP_ANON
/* # define MPROTECT_VDB -- There is some evidence that this breaks
- * on some minor versions of MACOSX. In theory, it should be OK */
+ * on some minor versions of MACOSX, i.e. 10.2.3. In theory,
+ * it should be OK */
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
+# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
+ /* The performance impact of prefetches is untested */
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
+# endif
# endif
# ifdef NETBSD
# define ALIGNMENT 4
@@ -2015,7 +2030,7 @@
+ GC_page_size) \
+ GC_page_size-1)
# else
-# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \
+# if defined(NEXT) || defined(DOS4GW) || \
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
(defined(SUNOS5) && !defined(USE_MMAP))
# define GET_MEM(bytes) HBLKPTR((size_t) \
diff -ur gc6.2alpha3.orig/linux_threads.c gc6.2alpha3-threads/linux_threads.c
--- gc6.2alpha3.orig/linux_threads.c 2002-10-01 15:36:06.000000000 -0700
+++ gc6.2alpha3-threads/linux_threads.c 2003-02-12 23:33:57.000000000 -0800
@@ -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 @@
# 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 @@
/* 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 @@
# 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 @@
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 @@
# 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 @@
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 @@
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,7 +1720,11 @@
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();
@@ -1701,10 +1750,15 @@
/* 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();
diff -ur gc6.2alpha3.orig/os_dep.c gc6.2alpha3-threads/os_dep.c
--- gc6.2alpha3.orig/os_dep.c 2003-01-29 19:56:03.000000000 -0800
+++ gc6.2alpha3-threads/os_dep.c 2003-02-13 10:09:22.000000000 -0800
@@ -1329,19 +1329,28 @@
ptr_t GC_unix_get_mem(bytes)
word bytes;
{
- static GC_bool initialized = FALSE;
- static int fd;
void *result;
static ptr_t last_addr = HEAP_START;

- if (!initialized) {
- fd = open("/dev/zero", O_RDONLY);
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- initialized = TRUE;
- }
+# ifndef USE_MMAP_ANON
+ static GC_bool initialized = FALSE;
+ static int fd;
+
+ if (!initialized) {
+ fd = open("/dev/zero", O_RDONLY);
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ initialized = TRUE;
+ }
+# endif
+
if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
- result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
- GC_MMAP_FLAGS, fd, 0/* offset */);
+# ifdef USE_MMAP_ANON
+ result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
+ GC_MMAP_FLAGS | MAP_ANON, -1, 0/* offset */);
+# else
+ result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
+ GC_MMAP_FLAGS, fd, 0/* offset */);
+# endif
if (result == MAP_FAILED) return(0);
last_addr = (ptr_t)result + bytes + GC_page_size - 1;
last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
diff -ur gc6.2alpha3.orig/tests/test.c gc6.2alpha3-threads/tests/test.c
--- gc6.2alpha3.orig/tests/test.c 2002-11-06 09:28:14.000000000 -0800
+++ gc6.2alpha3-threads/tests/test.c 2003-02-11 22:00:25.000000000 -0800
@@ -1748,7 +1748,8 @@
}
# endif /* GC_HPUX_THREADS */
pthread_attr_init(&attr);
-# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS)
+# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_MACOSX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
diff -ur gc6.2alpha3.orig/threadlibs.c gc6.2alpha3-threads/threadlibs.c
--- gc6.2alpha3.orig/threadlibs.c 2002-08-01 18:16:21.000000000 -0700
+++ gc6.2alpha3-threads/threadlibs.c 2003-02-11 21:58:30.000000000 -0800
@@ -10,7 +10,8 @@
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
# endif
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS)
+ || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
+ || defined(GC_MACOSX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
Renaud Blanch
2003-02-14 15:00:48 UTC
Permalink
Post by Jesse Rosenstock
Here's a new version of the patch. I've introduced a USE_PPC_PREFETCH
#define to guard the prefetch stuff instead of doing it
unconditionally,
and switched MACOSX to USE_MMAP, but with USE_MMAP_ANON which I also
added because mapping /dev/zero doesn't seem to work. Everything else
should be the same as before.
The patch works great for me.
I have'nt tested it extensively but my multithreaded application works
fine.
Thank you very much !

Can I (or you) post your patch to the maintainer of gc fink's package ?
Or is it better to wait for it's inclusion into GC source ?

thanks again

Renaud
--
Renaud BLANCH
LRI - Bâtiment 490 email : ***@lri.fr
Université Paris-Sud web : http://www.lri.fr/~blanch
91 405 ORSAY Cedex tel : 01.69.15.66.25
Continue reading on narkive:
Loading...