mirror of
https://github.com/dlang/phobos.git
synced 2025-05-13 07:39:15 +03:00
A bunch of changes to fix threading and GC on OSX.
This commit is contained in:
parent
22c43c9139
commit
28253aae04
6 changed files with 197 additions and 101 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
203
std/thread.d
203
std/thread.d
|
@ -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()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue