diff lphobos/std/thread.d @ 131:5825d48b27d1 trunk

[svn r135] * Merged DMD 1.025 * * Fixed a minor linking order mishap * * Added an command line option -annotate * * Fixed some problems with running optimizations * * Added std.stdio and dependencies to lphobos (still not 100% working, but compiles and links) * * Fixed problems with passing aggregate types to variadic functions * * Added initial code towards full GC support, currently based on malloc and friends, not all the runtime calls the GC yet for memory * * Fixed problems with resolving nested function context pointers for some heavily nested cases * * Redid function argument passing + other minor code cleanups, still lots to do on this end... *
author lindquist
date Fri, 04 Jan 2008 01:38:42 +0100
parents
children 373489eeaf90
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/thread.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,1127 @@
+// Written in the D programming language
+
+/*
+ *  Copyright (C) 2002-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/**************************
+ * The thread module defines the class $(B Thread).
+ *
+ * $(B Thread) is the basis
+ * for writing multithreaded applications. Each thread
+ * has a unique instance of class $(B Thread) associated with it.
+ * It is important to use the $(B Thread) class to create and manage
+ * threads as the garbage collector needs to know about all the threads.
+ * Macros:
+ *	WIKI=Phobos/StdThread
+ */
+
+module std.thread;
+
+import std.c.stdio;
+
+//debug=thread;
+
+/* ================================ Win32 ================================= */
+
+version (Win32)
+{
+
+private import std.c.windows.windows;
+
+extern (Windows) alias uint (*stdfp)(void *);
+
+extern (C)
+    thread_hdl _beginthreadex(void* security, uint stack_size,
+	stdfp start_addr, void* arglist, uint initflag,
+	thread_id* thrdaddr);
+
+/**
+ * The type of the thread handle used by the operating system.
+ * For Windows, it is equivalent to a HANDLE from windows.d.
+ */
+alias HANDLE thread_hdl;
+
+alias uint thread_id;
+
+/**
+ * Thrown for errors.
+ */
+class ThreadError : Error
+{
+    this(char[] s)
+    {
+	super("Thread error: " ~ s);
+    }
+}
+
+/**
+ * One of these is created for each thread.
+ */
+class Thread
+{
+    /**
+     * Constructor used by classes derived from Thread that override main(). 
+     * The optional stacksize parameter default value of 0 will cause threads
+     * to be created with the default size for the executable - Dave Fladebo
+     */
+    this(size_t stacksize = 0)
+    {
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Constructor used by classes derived from Thread that override run().
+     */
+    this(int (*fp)(void *), void *arg, size_t stacksize = 0)
+    {
+	this.fp = fp;
+	this.arg = arg;
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Constructor used by classes derived from Thread that override run().
+     */
+    this(int delegate() dg, size_t stacksize = 0)
+    {
+	this.dg = dg;
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Destructor
+     *
+     * If the thread hasn't been joined yet, detach it.
+     */
+    ~this()
+    {
+        if (state != TS.FINISHED)
+            CloseHandle(hdl);
+    }
+
+    /**
+     * The handle to this thread assigned by the operating system. This is set
+     * to thread_id.init if the thread hasn't been started yet.
+     */
+    thread_hdl hdl;
+
+    void* stackBottom;
+
+    /**
+     * Create a new thread and start it running. The new thread initializes
+     * itself and then calls run(). start() can only be called once.
+     */
+    void start()
+    {
+	if (state != TS.INITIAL)
+	    error("already started");
+
+	synchronized (Thread.classinfo)
+	{
+	    for (int i = 0; 1; i++)
+	    {
+		if (i == allThreads.length)
+		    error("too many threads");
+		if (!allThreads[i])
+		{   allThreads[i] = this;
+		    idx = i;
+		    if (i >= allThreadsDim)
+			allThreadsDim = i + 1;
+		    break;
+		}
+	    }
+	    nthreads++;
+	}
+
+	state = TS.RUNNING;
+	hdl = _beginthreadex(null, cast(uint)stacksize, &threadstart, cast(void*)this, 0, &id);
+	if (hdl == cast(thread_hdl)0)
+	{   state = TS.FINISHED;
+	    synchronized (Thread.classinfo) allThreads[idx] = null;
+	    idx = -1;
+	    error("failed to start");
+	}
+    }
+
+    /**
+     * Entry point for a thread. If not overridden, it calls the function
+     * pointer fp and argument arg passed in the constructor, or the delegate
+     * dg.
+     * Returns: the thread exit code, which is normally 0.
+     */
+    int run()
+    {
+	if (fp)
+	    return fp(arg);
+	else if (dg)
+	    return dg();
+	assert(0);
+    }
+
+    /*****************************
+     * Wait for this thread to terminate.
+     * Simply returns if thread has already terminated.
+     * Throws: $(B ThreadError) if the thread hasn't begun yet or
+     * is called on itself.
+     */
+    void wait()
+    {
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{   DWORD dw;
+
+	    dw = WaitForSingleObject(hdl, 0xFFFFFFFF);
+            state = TS.FINISHED;
+            CloseHandle(hdl);
+            hdl = null;
+	}
+    }
+
+    /******************************
+     * Wait for this thread to terminate or until milliseconds time has
+     * elapsed, whichever occurs first.
+     * Simply returns if thread has already terminated.
+     * Throws: $(B ThreadError) if the thread hasn't begun yet or
+     * is called on itself.
+     */
+    void wait(uint milliseconds)
+    {
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{   DWORD dw;
+
+	    dw = WaitForSingleObject(hdl, milliseconds);
+            state = TS.FINISHED;
+            CloseHandle(hdl);
+            hdl = null;
+	}
+    }
+
+    /**
+     * The state of a thread.
+     */
+    enum TS
+    {
+	INITIAL,	/// The thread hasn't been started yet.
+	RUNNING,	/// The thread is running or paused.
+	TERMINATED,	/// The thread has ended.
+        FINISHED        /// The thread has been cleaned up
+    }
+
+    /**
+     * Returns the state of a thread.
+     */
+    TS getState()
+    {
+	return state;
+    }
+
+    /**
+     * The priority of a thread.
+     */
+    enum PRIORITY
+    {
+	INCREASE,	/// Increase thread priority
+	DECREASE,	/// Decrease thread priority
+	IDLE,		/// Assign thread low priority
+	CRITICAL	/// Assign thread high priority
+    }
+
+    /**
+     * Adjust the priority of this thread.
+     * Throws: ThreadError if cannot set priority
+     */
+    void setPriority(PRIORITY p)
+    {
+	int nPriority;
+
+	switch (p)
+	{
+	    case PRIORITY.INCREASE:
+		nPriority = THREAD_PRIORITY_ABOVE_NORMAL;
+		break;
+	    case PRIORITY.DECREASE:
+		nPriority = THREAD_PRIORITY_BELOW_NORMAL;
+		break;
+	    case PRIORITY.IDLE:
+		nPriority = THREAD_PRIORITY_IDLE;
+		break;
+	    case PRIORITY.CRITICAL:
+		nPriority = THREAD_PRIORITY_TIME_CRITICAL;
+		break;
+	    default:
+		assert(0);
+	}
+
+	if (SetThreadPriority(hdl, nPriority) == THREAD_PRIORITY_ERROR_RETURN)
+	    error("set priority");
+    }
+
+    /**
+     * Returns true if this thread is the current thread.
+     */
+    bool isSelf()
+    {
+	//printf("id = %d, self = %d\n", id, pthread_self());
+	return (id == GetCurrentThreadId());
+    }
+
+    /**
+     * Returns a reference to the Thread for the thread that called the
+     * function.
+     */
+    static Thread getThis()
+    {
+	//printf("getThis(), allThreadsDim = %d\n", allThreadsDim);
+        thread_id id = GetCurrentThreadId();
+        for (int i = 0; i < allThreadsDim; i++)
+        {
+            Thread t = allThreads[i];
+            if (t && id == t.id)
+            {
+                return t;
+            }
+        }
+	printf("didn't find it\n");
+	assert(0);
+    }
+
+    /**
+     * Returns an array of all the threads currently running.
+     */
+    static Thread[] getAll()
+    {
+	synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
+    }
+
+    /**
+     * Suspend execution of this thread.
+     */
+    void pause()
+    {
+	if (state != TS.RUNNING || SuspendThread(hdl) == 0xFFFFFFFF)
+	    error("cannot pause");
+    }
+
+    /**
+     * Resume execution of this thread.
+     */
+    void resume()
+    {
+	if (state != TS.RUNNING || ResumeThread(hdl) == 0xFFFFFFFF)
+	    error("cannot resume");
+    }
+
+    /**
+     * Suspend execution of all threads but this thread.
+     */
+    static void pauseAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                    thread_id thisid = GetCurrentThreadId();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                    {
+                        Thread t = allThreads[i];
+                        if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.pause();
+                }
+            }
+        }
+    }
+
+    /**
+     * Resume execution of all paused threads.
+     */
+    static void resumeAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                thread_id thisid = GetCurrentThreadId();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.resume();
+                }
+            }
+        }
+    }
+
+    /**
+     * Give up the remainder of this thread's time slice.
+     */
+    static void yield()
+    {
+	Sleep(0);
+    }
+
+    /**
+     *
+     */
+    static uint nthreads = 1;
+
+  private:
+
+    static uint allThreadsDim;
+    static Thread[0x400] allThreads;	// length matches value in C runtime
+
+    TS state;
+    int idx = -1;			// index into allThreads[]
+    thread_id id;
+    size_t stacksize = 0;
+
+    int (*fp)(void *);
+    void *arg;
+
+    int delegate() dg;
+
+    void error(char[] msg)
+    {
+	throw new ThreadError(msg);
+    }
+
+
+    /* ***********************************************
+     * This is just a wrapper to interface between C rtl and Thread.run().
+     */
+
+    extern (Windows) static uint threadstart(void *p)
+    {
+	Thread t = cast(Thread)p;
+	int result;
+
+	debug (thread) printf("Starting thread %d\n", t.idx);
+	t.stackBottom = os_query_stackBottom();
+	try
+	{
+	    result = t.run();
+	}
+	catch (Object o)
+	{
+	    fprintf(stderr, "Error: %.*s\n", o.toString());
+	    result = 1;
+	}
+
+	debug (thread) printf("Ending thread %d\n", t.idx);
+	t.state = TS.TERMINATED;
+        synchronized (Thread.classinfo)
+        {
+            allThreads[t.idx] = null;
+            t.idx = -1;
+            nthreads--;
+        }
+	return result;
+    }
+
+
+    /**************************************
+     * Create a Thread for global main().
+     */
+
+    public static void thread_init()
+    {
+	Thread t = new Thread();
+
+	t.state = TS.RUNNING;
+	t.id = GetCurrentThreadId();
+	t.hdl = Thread.getCurrentThreadHandle();
+	t.stackBottom = os_query_stackBottom();
+
+	assert(!allThreads[0]);
+	allThreads[0] = t;
+	allThreadsDim = 1;
+	t.idx = 0;
+    }
+
+    static ~this()
+    {
+	if (allThreadsDim)
+	{
+	    CloseHandle(allThreads[0].hdl);
+	    allThreads[0].hdl = GetCurrentThread();
+	}
+    }
+          
+    /********************************************
+     * Returns the handle of the current thread.
+     * This is needed because GetCurrentThread() always returns -2 which
+     * is a pseudo-handle representing the current thread.
+     * The returned thread handle is a windows resource and must be explicitly
+     * closed.
+     * Many thanks to Justin (jhenzie@mac.com) for figuring this out
+     * and providing the fix.
+     */
+    static thread_hdl getCurrentThreadHandle()
+    {
+	thread_hdl currentThread = GetCurrentThread();
+	thread_hdl actualThreadHandle;
+
+	//thread_hdl currentProcess = cast(thread_hdl)-1;
+	thread_hdl currentProcess = GetCurrentProcess(); // http://www.digitalmars.com/drn-bin/wwwnews?D/21217
+
+
+	uint access = cast(uint)0x00000002;
+
+	DuplicateHandle(currentProcess, currentThread, currentProcess,
+			 &actualThreadHandle, cast(uint)0, TRUE, access);
+
+	return actualThreadHandle;
+     }
+}
+
+
+/**********************************************
+ * Determine "bottom" of stack (actually the top on Win32 systems).
+ */
+
+void *os_query_stackBottom()
+{
+    asm
+    {
+	naked			;
+	mov	EAX,FS:4	;
+	ret			;
+    }
+}
+
+}
+
+/* ================================ linux ================================= */
+
+version (linux)
+{
+
+private import std.c.linux.linux;
+private import std.c.linux.linuxextern;
+private import llvm.intrinsic;
+
+alias uint pthread_t;
+extern (C) alias void (*__sighandler_t)(int);
+
+struct sigset_t
+{
+    uint __val[1024 / (8 * uint.sizeof)];
+}
+
+struct sigaction_t
+{
+    __sighandler_t sa_handler;
+    sigset_t sa_mask;
+    int sa_flags;
+    void (*sa_restorer)();
+}
+
+struct pthread_attr_t
+{
+    int __detachstate;
+    int __schedpolicy;
+    struct __schedparam
+    {
+	int __sched_priority;
+    }
+    int __inheritsched;
+    int __scope;
+    size_t __guardsize;
+    int __stackaddr_set;
+    void *__stackaddr;
+    size_t __stacksize;
+}
+
+unittest
+{
+    assert(sigset_t.sizeof  == 128);
+    assert(sigaction_t.sizeof == 140);
+    assert(sem_t.sizeof == 16);
+}
+
+extern (C)
+{
+    int pthread_create(pthread_t*, void*, void* (*)(void*), void*);
+    int pthread_join(pthread_t, void**);
+    int pthread_kill(pthread_t, int);
+    pthread_t pthread_self();
+    int pthread_equal(pthread_t, pthread_t);
+    int pthread_attr_init(pthread_attr_t*);
+    int pthread_attr_setstacksize(pthread_attr_t *, size_t);
+    int pthread_cancel(pthread_t);
+    int pthread_setcancelstate(int, int*);
+    int pthread_setcanceltype(int, int*);
+    int sched_yield();
+    int sigfillset(sigset_t*);
+    int sigdelset(sigset_t*, int);
+    int sigaction(int, sigaction_t*, sigaction_t*);
+    int sigsuspend(sigset_t*);
+
+    enum
+    {
+	PTHREAD_CANCEL_ENABLE,
+	PTHREAD_CANCEL_DISABLE
+    }
+
+    enum
+    {
+	PTHREAD_CANCEL_DEFERRED,
+	PTHREAD_CANCEL_ASYNCHRONOUS
+    }
+}
+
+class ThreadError : Error
+{
+    this(char[] s)
+    {
+	super("Thread error: " ~ s);
+    }
+}
+
+class Thread
+{
+    // The optional stacksize parameter default value of 0 will cause threads
+    //  to be created with the default pthread size - Dave Fladebo
+    this(size_t stacksize = 0)
+    {
+	init(stacksize);
+    }
+
+    this(int (*fp)(void *), void *arg, size_t stacksize = 0)
+    {
+	this.fp = fp;
+	this.arg = arg;
+	init(stacksize);
+    }
+
+    this(int delegate() dg, size_t stacksize = 0)
+    {
+	this.dg = dg;
+	init(stacksize);
+    }
+
+    ~this()
+    {
+	pthread_cond_destroy(&waitCond);
+	pthread_mutex_destroy(&waitMtx);
+        if (state != TS.FINISHED)
+            pthread_detach(id);
+    }
+
+    pthread_t id;
+    void* stackBottom;
+    void* stackTop;
+
+    void start()
+    {
+	if (state != TS.INITIAL)
+	    error("already started");
+
+	synchronized (Thread.classinfo)
+	{
+	    for (int i = 0; 1; i++)
+	    {
+		if (i == allThreads.length)
+		    error("too many threads");
+		if (!allThreads[i])
+		{   allThreads[i] = this;
+		    idx = i;
+		    if (i >= allThreadsDim)
+			allThreadsDim = i + 1;
+		    break;
+		}
+	    }
+	    nthreads++;
+	}
+
+	state = TS.RUNNING;
+	//printf("creating thread x%x\n", this);
+	//result = pthread_create(&id, null, &threadstart, this);
+	// Create with thread attributes to allow non-default stack size - Dave Fladebo
+	int result = pthread_create(&id, &threadAttrs, &threadstart, cast(void*)this);
+	if (result)
+	{   state = TS.FINISHED;
+	    synchronized (Thread.classinfo) allThreads[idx] = null;
+	    idx = -1;
+	    error("failed to start");	// BUG: should report errno
+	}
+	//printf("t = x%x, id = %d\n", this, id);
+    }
+
+    int run()
+    {
+	if (fp)
+	    return fp(arg);
+	else if (dg)
+	    return dg();
+	assert(0);
+    }
+
+    void wait()
+    {
+	if (isSelf)
+	    error("wait on self");
+
+	if (state != TS.FINISHED)
+	{
+	    void *value;
+
+	    int result = pthread_join(id, &value);
+            state = TS.FINISHED;
+	    if (result)
+		error("failed to wait");
+	}
+    }
+
+    void wait(uint milliseconds)
+    {
+	// Implemented for POSIX systems by Dave Fladebo
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{
+	    timespec ts; 
+	    timeval  tv;
+
+	    pthread_mutex_lock(&waitMtx);
+	    gettimeofday(&tv, null);
+	    ts.tv_sec = cast(__time_t)tv.tv_sec + cast(__time_t)(milliseconds / 1_000);
+	    ts.tv_nsec = (tv.tv_usec * 1_000) + ((milliseconds % 1_000) * 1_000_000);
+	    if (ts.tv_nsec > 1_000_000_000)
+	    {
+		ts.tv_sec += 1;
+		ts.tv_nsec -= 1_000_000_000;
+	    }
+	    if (pthread_cond_timedwait(&waitCond, &waitMtx, &ts))
+	    {
+		int oldstate, oldtype;
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+
+		if (pthread_cancel(id))     // thread was not completed in the timeout period, cancel it
+		{
+		    pthread_mutex_unlock(&waitMtx);
+		    error("cannot terminate thread via timed wait");
+		}
+
+		pthread_setcancelstate(oldstate, null);
+		pthread_setcanceltype(oldtype, null);
+
+		state = TS.TERMINATED;
+                synchronized (Thread.classinfo)
+                {
+                    allThreads[idx] = null;
+                    idx = -1;
+                    nthreads--;
+                }
+
+		pthread_mutex_unlock(&waitMtx);
+	    }
+	    else
+	    {
+		pthread_mutex_unlock(&waitMtx);
+		wait();	// condition has been signalled as complete (see threadstart()), terminate normally
+	    }
+	}
+    }
+
+    enum TS
+    {
+	INITIAL,        // created
+	RUNNING,        // running
+	TERMINATED,     // execution finished
+        FINISHED        // pthread_join()'ed
+    }
+
+    TS getState()
+    {
+	return state;
+    }
+
+    enum PRIORITY
+    {
+	INCREASE,
+	DECREASE,
+	IDLE,
+	CRITICAL
+    }
+
+    void setPriority(PRIORITY p)
+    {
+	/+ not implemented
+	int nPriority;
+
+	switch (p)
+	{
+	    case PRIORITY.INCREASE:
+		nPriority = THREAD_PRIORITY_ABOVE_NORMAL;
+		break;
+	    case PRIORITY.DECREASE:
+		nPriority = THREAD_PRIORITY_BELOW_NORMAL;
+		break;
+	    case PRIORITY.IDLE:
+		nPriority = THREAD_PRIORITY_IDLE;
+		break;
+	    case PRIORITY.CRITICAL:
+		nPriority = THREAD_PRIORITY_TIME_CRITICAL;
+		break;
+	}
+
+	if (SetThreadPriority(hdl, nPriority) == THREAD_PRIORITY_ERROR_RETURN)
+	    error("set priority");
+	+/
+    }
+
+    int isSelf()
+    {
+	//printf("id = %d, self = %d\n", id, pthread_self());
+	return pthread_equal(pthread_self(), id);
+    }
+
+    static Thread getThis()
+    {
+	//printf("getThis(), allThreadsDim = %d\n", allThreadsDim);
+        pthread_t id = pthread_self();
+        //printf("id = %d\n", id);
+        for (int i = 0; i < allThreadsDim; i++)
+        {
+            Thread t = allThreads[i];
+            //printf("allThreads[%d] = x%x, id = %d\n", i, t, (t ? t.id : 0));
+            if (t && pthread_equal(id, t.id))
+            {
+                return t;
+            }
+        }
+	printf("didn't find it\n");
+	assert(null);
+    }
+
+    static Thread[] getAll()
+    {
+	synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
+    }
+
+    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");
+    }
+
+    void resume()
+    {
+	if (state == TS.RUNNING)
+	{
+	    if (pthread_kill(id, SIGUSR2))
+		error("cannot resume");
+	}
+	else
+	    error("cannot resume");
+    }
+
+    static void pauseAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                pthread_t thisid = pthread_self();
+                int npause = 0;
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && !pthread_equal(thisid, t.id) && t.state == TS.RUNNING)
+                    {
+                        if (pthread_kill(t.id, SIGUSR1))
+                            t.error("cannot pause");
+                        else
+                            npause++;	// count of paused threads
+                    }
+                }
+
+                // Wait for each paused thread to acknowledge
+                while (npause--)
+                {
+                    sem_wait(&flagSuspend);
+                }
+            }
+        }
+    }
+
+    static void resumeAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                pthread_t thisid = pthread_self();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.resume();
+                }
+            }
+        }
+    }
+
+    static void yield()
+    {
+	sched_yield();
+    }
+
+    static uint nthreads = 1;
+
+  private:
+
+    static uint allThreadsDim;
+
+    // Set max to Windows equivalent for compatibility.
+    // pthread_create will fail gracefully if stack limit
+    // is reached prior to allThreads max.
+    static Thread[0x400] allThreads;
+
+    static sem_t flagSuspend;
+
+    TS state;
+    int idx = -1;			// index into allThreads[]
+    int flags = 0;
+
+    pthread_attr_t threadAttrs;
+    pthread_mutex_t waitMtx;
+    pthread_cond_t waitCond;
+
+    int (*fp)(void *);
+    void *arg;
+
+    int delegate() dg;
+
+    void error(char[] msg)
+    {
+	throw new ThreadError(msg);
+    }
+
+    void init(size_t stackSize)
+    {
+	// set to default values regardless
+	// passing this as the 2nd arg. for pthread_create()
+	// w/o setting an attribute is equivalent to passing null.
+	pthread_attr_init(&threadAttrs);
+	if (stackSize > 0)
+	{
+	    if (pthread_attr_setstacksize(&threadAttrs,stackSize))
+		error("cannot set stack size");
+	}
+
+	if (pthread_mutex_init(&waitMtx, null))
+	    error("cannot initialize wait mutex");
+
+	if (pthread_cond_init(&waitCond, null))
+	    error("cannot initialize wait condition");
+    }
+
+    /************************************************
+     * This is just a wrapper to interface between C rtl and Thread.run().
+     */
+
+    extern (C) static void *threadstart(void *p)
+    {
+	Thread t = cast(Thread)p;
+	int result;
+
+	debug (thread) printf("Starting thread x%x (%d)\n", t, t.idx);
+
+	// Need to set t.id here, because thread is off and running
+	// before pthread_create() sets it.
+	t.id = pthread_self();
+
+	t.stackBottom = getESP();
+	try
+	{
+	    if(t.state == TS.RUNNING)
+		pthread_cond_signal(&t.waitCond);     // signal the wait condition (see the timed wait function)
+	    result = t.run();
+	}
+	catch (Object o)
+	{
+	    fprintf(stderr, "Error: %.*s\n", o.toString());
+	    result = 1;
+	}
+
+	debug (thread) printf("Ending thread %d\n", t.idx);
+	t.state = TS.TERMINATED;
+        synchronized (Thread.classinfo)
+        {
+            allThreads[t.idx] = null;
+            t.idx = -1;
+            nthreads--;
+        }
+	return cast(void*)result;
+    }
+
+
+    /**************************************
+     * Create a Thread for global main().
+     */
+
+    public static void thread_init()
+    {
+	Thread t = new Thread();
+
+	t.state = TS.RUNNING;
+	t.id = pthread_self();
+
+	version (none)
+	{
+	    // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
+	    static void** libc_stack_end;
+
+	    if (libc_stack_end == libc_stack_end.init)
+	    {
+		void* handle = dlopen(null, RTLD_NOW);
+		libc_stack_end = cast(void **)dlsym(handle, "__libc_stack_end");
+		dlclose(handle);
+	    }
+	    t.stackBottom = *libc_stack_end;
+	}
+	else
+	{
+	    t.stackBottom = cast(void*)__libc_stack_end;
+	}
+
+	assert(!allThreads[0]);
+	allThreads[0] = t;
+	allThreadsDim = 1;
+	t.idx = 0;
+
+	/* 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;
+	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
+	version(none) 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
+	version(none) 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()
+    {
+    version(D_InlineAsm_X86)
+    {
+	asm
+	{   naked	;
+	    mov EAX,ESP	;
+	    ret		;
+	}
+    }
+    else
+    {
+        void* p = llvm_frameaddress(0);
+        assert(p !is null);
+        return p;
+    }
+    }
+}
+
+
+}
+