Logo Search packages:      
Sourcecode: ldc version File versions

thread.d

// 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;
    }
    }
}


}


Generated by  Doxygen 1.6.0   Back to index