A bunch of changes to fix threading and GC on OSX.

This commit is contained in:
Sean Kelly 2009-02-09 23:30:37 +00:00
parent 22c43c9139
commit 28253aae04
6 changed files with 197 additions and 101 deletions

View file

@ -63,6 +63,11 @@ version (Win32)
import std.c.windows.windows; import std.c.windows.windows;
} }
version (OSX)
{
import std.c.osx.osx;
}
version (Posix) version (Posix)
{ {
import gclinux; import gclinux;
@ -1898,6 +1903,23 @@ struct Gcx
mark(cast(void *)context.Esp, t.stackBottom); mark(cast(void *)context.Esp, t.stackBottom);
mark(&context.Edi, &context.Eip); 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) version (Posix)
{ {
// The registers are already stored in the stack // The registers are already stored in the stack

View file

@ -20,7 +20,8 @@ SRC= gc.d gcx.d gcbits.d win32.d gclinux.d gcosxc.c gcold.d testgc.d \
.d.o: .d.o:
$(DMD) -c $(DFLAGS) $* $(DMD) -c $(DFLAGS) $*
targets : testgc dmgc.a #targets : testgc dmgc.a
targets : dmgc.a
testgc : testgc.o $(OBJS) linux.mak testgc : testgc.o $(OBJS) linux.mak
$(DMD) -of$@ testgc.o gc.o gcx.o gcbits.o gclinux.o gcosxc.o -g $(DMD) -of$@ testgc.o gc.o gcx.o gcbits.o gclinux.o gcosxc.o -g

View file

@ -609,6 +609,13 @@ extern (C)
int sigsuspend(sigset_t*); int sigsuspend(sigset_t*);
} }
extern (C)
{
/* from sched.h
*/
int sched_yield();
}
extern (C) extern (C)
{ {
/* from semaphore.h /* from semaphore.h

View file

@ -131,6 +131,18 @@ version(linux)
int __rw_kind; int __rw_kind;
int __rw_pshared; int __rw_pshared;
} }
enum
{
PTHREAD_CANCEL_ENABLE,
PTHREAD_CANCEL_DISABLE
}
enum
{
PTHREAD_CANCEL_DEFERRED,
PTHREAD_CANCEL_ASYNCHRONOUS
}
} }
version(OSX) version(OSX)
@ -138,7 +150,8 @@ version(OSX)
/* from bits/types.h /* from bits/types.h
*/ */
typedef int __time_t; // in std.c.linux.linux
//typedef int __time_t;
/* from time.h /* from time.h
*/ */
@ -237,6 +250,18 @@ version(OSX)
int __sig; int __sig;
byte[124] __opaque; 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*); int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*);
@ -344,6 +369,7 @@ version(linux)
pthread_t pthread_self(); pthread_t pthread_self();
int pthread_equal(pthread_t, pthread_t); int pthread_equal(pthread_t, pthread_t);
int pthread_atfork(void function(), void function(), void function()); int pthread_atfork(void function(), void function(), void function());
int pthread_kill(pthread_t, int);
void pthread_kill_other_threads_np(); void pthread_kill_other_threads_np();
int pthread_setschedparam(pthread_t, int, __sched_param*); int pthread_setschedparam(pthread_t, int, __sched_param*);
int pthread_getschedparam(pthread_t, int*, __sched_param*); int pthread_getschedparam(pthread_t, int*, __sched_param*);

View file

@ -6,6 +6,8 @@
module std.c.osx.osx; module std.c.osx.osx;
public import std.c.linux.linux : pthread_t;
extern (C): extern (C):
alias int kern_return_t; alias int kern_return_t;
@ -73,24 +75,25 @@ version( i386 )
alias uint natural_t; alias uint natural_t;
alias natural_t mach_port_t; alias natural_t mach_port_t;
alias mach_port_t thread_act_t; alias mach_port_t thread_act_t;
alias void thread_state_t;
alias int thread_state_flavor_t; alias int thread_state_flavor_t;
alias natural_t mach_msg_type_number_t; alias natural_t mach_msg_type_number_t;
enum enum
{ {
x86_THREAD_STATE32 1, x86_THREAD_STATE32 = 1,
x86_FLOAT_STATE32 2, x86_FLOAT_STATE32 = 2,
x86_EXCEPTION_STATE32 3, x86_EXCEPTION_STATE32 = 3,
x86_THREAD_STATE64 4, x86_THREAD_STATE64 = 4,
x86_FLOAT_STATE64 5, x86_FLOAT_STATE64 = 5,
x86_EXCEPTION_STATE64 6, x86_EXCEPTION_STATE64 = 6,
x86_THREAD_STATE 7, x86_THREAD_STATE = 7,
x86_FLOAT_STATE 8, x86_FLOAT_STATE = 8,
x86_EXCEPTION_STATE 9, x86_EXCEPTION_STATE = 9,
x86_DEBUG_STATE32 10, x86_DEBUG_STATE32 = 10,
x86_DEBUG_STATE64 11, x86_DEBUG_STATE64 = 11,
x86_DEBUG_STATE 12, x86_DEBUG_STATE = 12,
THREAD_STATE_NONE 13, THREAD_STATE_NONE = 13,
} }
struct x86_thread_state32_t struct x86_thread_state32_t
@ -147,11 +150,12 @@ version( i386 )
struct x86_thread_state_t struct x86_thread_state_t
{ {
x86_state_hdr_t tsh; x86_state_hdr_t tsh;
union union _uts
{ {
x86_thread_state32_t ts32; x86_thread_state32_t ts32;
x86_thread_state64_t ts64; x86_thread_state64_t ts64;
} uts; }
_uts uts;
} }
enum : mach_msg_type_number_t enum : mach_msg_type_number_t
@ -165,6 +169,7 @@ version( i386 )
alias x86_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT; alias x86_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT;
mach_port_t mach_thread_self(); 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_suspend(thread_act_t);
kern_return_t thread_resume(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*); kern_return_t thread_get_state(thread_act_t, thread_state_flavor_t, thread_state_t*, mach_msg_type_number_t*);

View file

@ -532,12 +532,14 @@ version (Posix)
private import std.c.linux.linux; private import std.c.linux.linux;
private import std.c.linux.linuxextern; private import std.c.linux.linuxextern;
private import std.c.linux.pthread;
version (OSX) version (OSX)
{ {
private import std.c.osx.osx;
extern (C) extern void* __osx_stack_end; extern (C) extern void* __osx_stack_end;
} }
/+
extern (C) alias void (*__sighandler_t)(int); extern (C) alias void (*__sighandler_t)(int);
struct sigset_t struct sigset_t
@ -608,7 +610,7 @@ extern (C)
PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS
} }
} }
+/
class ThreadError : Error class ThreadError : Error
{ {
this(string s) this(string s)
@ -650,6 +652,10 @@ class Thread
pthread_t id; pthread_t id;
void* stackBottom; void* stackBottom;
void* stackTop; void* stackTop;
version (OSX)
{
mach_port_t machid;
}
void start() void start()
{ {
@ -685,6 +691,12 @@ class Thread
error("failed to start"); // BUG: should report errno error("failed to start"); // BUG: should report errno
} }
//printf("t = x%x, id = %d\n", this, id); //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() int run()
@ -842,26 +854,42 @@ class Thread
void pause() void pause()
{ {
if (state == TS.RUNNING) version (OSX)
{ {
if (pthread_kill(id, SIGUSR1)) if (state != TS.RUNNING || thread_suspend(machid) != KERN_SUCCESS)
error("cannot pause"); error("cannot pause");
else }
sem_wait(&flagSuspend); // wait for acknowledgement else
} {
else if (state == TS.RUNNING)
error("cannot pause"); {
if (pthread_kill(id, SIGUSR1))
error("cannot pause");
else
sem_wait(&flagSuspend); // wait for acknowledgement
}
else
error("cannot pause");
}
} }
void resume() void resume()
{ {
if (state == TS.RUNNING) version (OSX)
{ {
if (pthread_kill(id, SIGUSR2)) if (state != TS.RUNNING || thread_resume(machid) != KERN_SUCCESS)
error("cannot resume"); 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() static void pauseAll()
@ -1045,83 +1073,90 @@ class Thread
allThreadsDim = 1; allThreadsDim = 1;
t.idx = 0; 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; int result;
sigaction_t sigact; sigaction_t sigact;
result = sigfillset(&sigact.sa_mask); result = sigfillset(&sigact.sa_mask);
if (result) if (result)
goto Lfail; goto Lfail;
sigact.sa_handler = &pauseHandler; sigact.sa_handler = &pauseHandler;
sigact.sa_flags = SA_RESTART; sigact.sa_flags = SA_RESTART;
result = sigaction(SIGUSR1, &sigact, null); result = sigaction(SIGUSR1, &sigact, null);
if (result) if (result)
goto Lfail; goto Lfail;
sigact.sa_handler = &resumeHandler; sigact.sa_handler = &resumeHandler;
result = sigaction(SIGUSR2, &sigact, null); result = sigaction(SIGUSR2, &sigact, null);
if (result) if (result)
goto Lfail; goto Lfail;
result = sem_init(&flagSuspend, 0, 0);
if (result)
goto Lfail;
result = sem_init(&flagSuspend, 0, 0);
if (result)
goto Lfail;
}
return; return;
Lfail: Lfail:
t.error("cannot initialize threads"); t.error("cannot initialize threads");
} }
/********************************** version (OSX) {}
* This gets called when a thread gets SIGUSR1. else
*/
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(); /**********************************
* 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() public static void* getESP()