diff --git a/internal/gc/gcx.d b/internal/gc/gcx.d index ee47a1e61..6cc39e344 100644 --- a/internal/gc/gcx.d +++ b/internal/gc/gcx.d @@ -63,6 +63,11 @@ version (Win32) import std.c.windows.windows; } +version (OSX) +{ + import std.c.osx.osx; +} + version (Posix) { import gclinux; @@ -1898,6 +1903,23 @@ struct Gcx mark(cast(void *)context.Esp, t.stackBottom); mark(&context.Edi, &context.Eip); } + version (OSX) + { + x86_thread_state32_t state; + mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT; + + if (thread_get_state(t.machid, + x86_THREAD_STATE32, + &state, + &count) != KERN_SUCCESS) + { + assert(0); + } + debug (PRINTF) printf("mt scan stack bot = %x, top = %x\n", state.esp, t.stackBottom); + + mark(cast(void *)state.esp, t.stackBottom); + mark(&state.eax, &state.esp); + } version (Posix) { // The registers are already stored in the stack diff --git a/internal/gc/osx.mak b/internal/gc/osx.mak index e4608a75e..88caff8ab 100644 --- a/internal/gc/osx.mak +++ b/internal/gc/osx.mak @@ -20,7 +20,8 @@ SRC= gc.d gcx.d gcbits.d win32.d gclinux.d gcosxc.c gcold.d testgc.d \ .d.o: $(DMD) -c $(DFLAGS) $* -targets : testgc dmgc.a +#targets : testgc dmgc.a +targets : dmgc.a testgc : testgc.o $(OBJS) linux.mak $(DMD) -of$@ testgc.o gc.o gcx.o gcbits.o gclinux.o gcosxc.o -g diff --git a/std/c/linux/linux.d b/std/c/linux/linux.d index 49b7f0818..d191cbbf6 100644 --- a/std/c/linux/linux.d +++ b/std/c/linux/linux.d @@ -609,6 +609,13 @@ extern (C) int sigsuspend(sigset_t*); } +extern (C) +{ + /* from sched.h + */ + int sched_yield(); +} + extern (C) { /* from semaphore.h diff --git a/std/c/linux/pthread.d b/std/c/linux/pthread.d index d39b17cae..11a63fea7 100644 --- a/std/c/linux/pthread.d +++ b/std/c/linux/pthread.d @@ -131,6 +131,18 @@ version(linux) int __rw_kind; int __rw_pshared; } + + enum + { + PTHREAD_CANCEL_ENABLE, + PTHREAD_CANCEL_DISABLE + } + + enum + { + PTHREAD_CANCEL_DEFERRED, + PTHREAD_CANCEL_ASYNCHRONOUS + } } version(OSX) @@ -138,7 +150,8 @@ version(OSX) /* from bits/types.h */ - typedef int __time_t; + // in std.c.linux.linux + //typedef int __time_t; /* from time.h */ @@ -237,6 +250,18 @@ version(OSX) int __sig; byte[124] __opaque; } + + enum + { + PTHREAD_CANCEL_ENABLE = 1, + PTHREAD_CANCEL_DISABLE = 0 + } + + enum + { + PTHREAD_CANCEL_DEFERRED = 2, + PTHREAD_CANCEL_ASYNCHRONOUS = 0 + } } int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*); @@ -344,6 +369,7 @@ version(linux) pthread_t pthread_self(); int pthread_equal(pthread_t, pthread_t); int pthread_atfork(void function(), void function(), void function()); + int pthread_kill(pthread_t, int); void pthread_kill_other_threads_np(); int pthread_setschedparam(pthread_t, int, __sched_param*); int pthread_getschedparam(pthread_t, int*, __sched_param*); diff --git a/std/c/osx/osx.d b/std/c/osx/osx.d index 5dda63e7c..ccb98a975 100644 --- a/std/c/osx/osx.d +++ b/std/c/osx/osx.d @@ -6,6 +6,8 @@ module std.c.osx.osx; +public import std.c.linux.linux : pthread_t; + extern (C): alias int kern_return_t; @@ -73,24 +75,25 @@ version( i386 ) alias uint natural_t; alias natural_t mach_port_t; alias mach_port_t thread_act_t; + alias void thread_state_t; alias int thread_state_flavor_t; alias natural_t mach_msg_type_number_t; enum { - x86_THREAD_STATE32 1, - x86_FLOAT_STATE32 2, - x86_EXCEPTION_STATE32 3, - x86_THREAD_STATE64 4, - x86_FLOAT_STATE64 5, - x86_EXCEPTION_STATE64 6, - x86_THREAD_STATE 7, - x86_FLOAT_STATE 8, - x86_EXCEPTION_STATE 9, - x86_DEBUG_STATE32 10, - x86_DEBUG_STATE64 11, - x86_DEBUG_STATE 12, - THREAD_STATE_NONE 13, + x86_THREAD_STATE32 = 1, + x86_FLOAT_STATE32 = 2, + x86_EXCEPTION_STATE32 = 3, + x86_THREAD_STATE64 = 4, + x86_FLOAT_STATE64 = 5, + x86_EXCEPTION_STATE64 = 6, + x86_THREAD_STATE = 7, + x86_FLOAT_STATE = 8, + x86_EXCEPTION_STATE = 9, + x86_DEBUG_STATE32 = 10, + x86_DEBUG_STATE64 = 11, + x86_DEBUG_STATE = 12, + THREAD_STATE_NONE = 13, } struct x86_thread_state32_t @@ -147,11 +150,12 @@ version( i386 ) struct x86_thread_state_t { x86_state_hdr_t tsh; - union + union _uts { x86_thread_state32_t ts32; x86_thread_state64_t ts64; - } uts; + } + _uts uts; } enum : mach_msg_type_number_t @@ -165,6 +169,7 @@ version( i386 ) alias x86_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT; mach_port_t mach_thread_self(); + mach_port_t pthread_mach_thread_np(pthread_t); kern_return_t thread_suspend(thread_act_t); kern_return_t thread_resume(thread_act_t); kern_return_t thread_get_state(thread_act_t, thread_state_flavor_t, thread_state_t*, mach_msg_type_number_t*); diff --git a/std/thread.d b/std/thread.d index deb3c7cae..8c7a54592 100644 --- a/std/thread.d +++ b/std/thread.d @@ -532,12 +532,14 @@ version (Posix) private import std.c.linux.linux; private import std.c.linux.linuxextern; +private import std.c.linux.pthread; version (OSX) { + private import std.c.osx.osx; extern (C) extern void* __osx_stack_end; } - +/+ extern (C) alias void (*__sighandler_t)(int); struct sigset_t @@ -608,7 +610,7 @@ extern (C) PTHREAD_CANCEL_ASYNCHRONOUS } } - ++/ class ThreadError : Error { this(string s) @@ -650,6 +652,10 @@ class Thread pthread_t id; void* stackBottom; void* stackTop; + version (OSX) + { + mach_port_t machid; + } void start() { @@ -685,6 +691,12 @@ class Thread error("failed to start"); // BUG: should report errno } //printf("t = x%x, id = %d\n", this, id); + version (OSX) + { + machid = pthread_mach_thread_np( id ); + if( machid == machid.init ) + error("failed to obtain machid"); + } } int run() @@ -842,26 +854,42 @@ class Thread void pause() { - if (state == TS.RUNNING) - { - if (pthread_kill(id, SIGUSR1)) - error("cannot pause"); - else - sem_wait(&flagSuspend); // wait for acknowledgement - } - else - error("cannot pause"); + version (OSX) + { + if (state != TS.RUNNING || thread_suspend(machid) != KERN_SUCCESS) + error("cannot pause"); + } + else + { + if (state == TS.RUNNING) + { + if (pthread_kill(id, SIGUSR1)) + error("cannot pause"); + else + sem_wait(&flagSuspend); // wait for acknowledgement + } + else + error("cannot pause"); + } } void resume() { - if (state == TS.RUNNING) - { - if (pthread_kill(id, SIGUSR2)) - error("cannot resume"); + version (OSX) + { + if (state != TS.RUNNING || thread_resume(machid) != KERN_SUCCESS) + error("cannot pause"); + } + else + { + if (state == TS.RUNNING) + { + if (pthread_kill(id, SIGUSR2)) + error("cannot resume"); + } + else + error("cannot resume"); } - else - error("cannot resume"); } static void pauseAll() @@ -1045,83 +1073,90 @@ class Thread allThreadsDim = 1; t.idx = 0; - /* Install signal handlers so we can suspend/resume threads - */ + version (OSX) {} + else + { + /* Install signal handlers so we can suspend/resume threads + */ - int result; - sigaction_t sigact; - result = sigfillset(&sigact.sa_mask); - if (result) - goto Lfail; - sigact.sa_handler = &pauseHandler; - sigact.sa_flags = SA_RESTART; - result = sigaction(SIGUSR1, &sigact, null); - if (result) - goto Lfail; - sigact.sa_handler = &resumeHandler; - result = sigaction(SIGUSR2, &sigact, null); - if (result) - goto Lfail; - - result = sem_init(&flagSuspend, 0, 0); - if (result) - goto Lfail; + int result; + sigaction_t sigact; + result = sigfillset(&sigact.sa_mask); + if (result) + goto Lfail; + sigact.sa_handler = &pauseHandler; + sigact.sa_flags = SA_RESTART; + result = sigaction(SIGUSR1, &sigact, null); + if (result) + goto Lfail; + sigact.sa_handler = &resumeHandler; + result = sigaction(SIGUSR2, &sigact, null); + if (result) + goto Lfail; + result = sem_init(&flagSuspend, 0, 0); + if (result) + goto Lfail; + } return; Lfail: t.error("cannot initialize threads"); } - /********************************** - * This gets called when a thread gets SIGUSR1. - */ - - extern (C) static void pauseHandler(int sig) - { int result; - - // Save all registers on the stack so they'll be scanned by the GC - asm - { - pusha ; - } - - assert(sig == SIGUSR1); - - sigset_t sigmask; - result = sigfillset(&sigmask); - assert(result == 0); - result = sigdelset(&sigmask, SIGUSR2); - assert(result == 0); - - Thread t = getThis(); - t.stackTop = getESP(); - t.flags &= ~1; - // Release the semaphore _after_ stackTop is set - sem_post(&flagSuspend); - while (1) - { - sigsuspend(&sigmask); // suspend until SIGUSR2 - if (t.flags & 1) // ensure it was resumeHandler() - break; - } - - // Restore all registers - asm - { - popa ; - } - } - - /********************************** - * This gets called when a thread gets SIGUSR2. - */ - - extern (C) static void resumeHandler(int sig) + version (OSX) {} + else { - Thread t = getThis(); + /********************************** + * This gets called when a thread gets SIGUSR1. + */ - t.flags |= 1; + extern (C) static void pauseHandler(int sig) + { int result; + + // Save all registers on the stack so they'll be scanned by the GC + asm + { + pusha ; + } + + assert(sig == SIGUSR1); + + sigset_t sigmask; + result = sigfillset(&sigmask); + assert(result == 0); + result = sigdelset(&sigmask, SIGUSR2); + assert(result == 0); + + Thread t = getThis(); + t.stackTop = getESP(); + t.flags &= ~1; + // Release the semaphore _after_ stackTop is set + sem_post(&flagSuspend); + while (1) + { + sigsuspend(&sigmask); // suspend until SIGUSR2 + if (t.flags & 1) // ensure it was resumeHandler() + break; + } + + // Restore all registers + asm + { + popa ; + } + } + + /********************************** + * This gets called when a thread gets SIGUSR2. + */ + + extern (C) static void resumeHandler(int sig) + { + Thread t = getThis(); + + t.flags |= 1; + } } public static void* getESP()