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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -609,6 +609,13 @@ extern (C)
|
|||
int sigsuspend(sigset_t*);
|
||||
}
|
||||
|
||||
extern (C)
|
||||
{
|
||||
/* from sched.h
|
||||
*/
|
||||
int sched_yield();
|
||||
}
|
||||
|
||||
extern (C)
|
||||
{
|
||||
/* from semaphore.h
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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*);
|
||||
|
|
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.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()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue