text: /*
   * Win32 implementation for mutex/cond/thread functions
   *
   * Copyright Red Hat, Inc. 2010
   *
   * Author:
   *  Paolo Bonzini <pbonzini@redhat.com>
   *
   * This work is licensed under the terms of the GNU GPL, version 2 or later.
   * See the COPYING file in the top-level directory.
   *
   */
  #include "qemu-common.h"
  #include "qemu-thread.h"
  #include <process.h>
  #include <assert.h>
  #include <limits.h>
  
  static void error_exit(int err, const char *msg)
  {
      char *pstr;
  
      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                    NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
      fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
      LocalFree(pstr);
      abort();
  }
  
  void qemu_mutex_init(QemuMutex *mutex)
  {
      mutex->owner = 0;
      InitializeCriticalSection(&mutex->lock);
  }
  
  void qemu_mutex_destroy(QemuMutex *mutex)
  {
      assert(mutex->owner == 0);
      DeleteCriticalSection(&mutex->lock);
  }
  
  void qemu_mutex_lock(QemuMutex *mutex)
  {
      EnterCriticalSection(&mutex->lock);
  
      /* Win32 CRITICAL_SECTIONs are recursive.  Assert that we're not
       * using them as such.
       */
      assert(mutex->owner == 0);
      mutex->owner = GetCurrentThreadId();
  }
  
  int qemu_mutex_trylock(QemuMutex *mutex)
  {
      int owned;
  
      owned = TryEnterCriticalSection(&mutex->lock);
      if (owned) {
          assert(mutex->owner == 0);
          mutex->owner = GetCurrentThreadId();
      }
      return !owned;
  }
  
  void qemu_mutex_unlock(QemuMutex *mutex)
  {
      assert(mutex->owner == GetCurrentThreadId());
      mutex->owner = 0;
      LeaveCriticalSection(&mutex->lock);
  }
  
  void qemu_cond_init(QemuCond *cond)
  {
      memset(cond, 0, sizeof(*cond));
  
      cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
      if (!cond->sema) {
          error_exit(GetLastError(), __func__);
      }
      cond->continue_event = CreateEvent(NULL,    /* security */
                                         FALSE,   /* auto-reset */
                                         FALSE,   /* not signaled */
                                         NULL);   /* name */
      if (!cond->continue_event) {
          error_exit(GetLastError(), __func__);
      }
  }
  
  void qemu_cond_destroy(QemuCond *cond)
  {
      BOOL result;
      result = CloseHandle(cond->continue_event);
      if (!result) {
          error_exit(GetLastError(), __func__);
      }
      cond->continue_event = 0;
      result = CloseHandle(cond->sema);
      if (!result) {
          error_exit(GetLastError(), __func__);
      }
      cond->sema = 0;
  }
  
  void qemu_cond_signal(QemuCond *cond)
  {
      DWORD result;
  
      /*
       * Signal only when there are waiters.  cond->waiters is
       * incremented by pthread_cond_wait under the external lock,
       * so we are safe about that.
       */
      if (cond->waiters == 0) {
          return;
      }
  
      /*
       * Waiting threads decrement it outside the external lock, but
       * only if another thread is executing pthread_cond_broadcast and
       * has the mutex.  So, it also cannot be decremented concurrently
       * with this particular access.
       */
      cond->target = cond->waiters - 1;
      result = SignalObjectAndWait(cond->sema, cond->continue_event,
                                   INFINITE, FALSE);
      if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
          error_exit(GetLastError(), __func__);
      }
  }
  
  void qemu_cond_broadcast(QemuCond *cond)
  {
      BOOLEAN result;
      /*
       * As in pthread_cond_signal, access to cond->waiters and
       * cond->target is locked via the external mutex.
       */
      if (cond->waiters == 0) {
          return;
      }
  
      cond->target = 0;
      result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
      if (!result) {
          error_exit(GetLastError(), __func__);
      }
  
      /*
       * At this point all waiters continue. Each one takes its
       * slice of the semaphore. Now it's our turn to wait: Since
       * the external mutex is held, no thread can leave cond_wait,
       * yet. For this reason, we can be sure that no thread gets
       * a chance to eat *more* than one slice. OTOH, it means
       * that the last waiter must send us a wake-up.
       */
      WaitForSingleObject(cond->continue_event, INFINITE);
  }
  
  void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
  {
      /*
       * This access is protected under the mutex.
       */
      cond->waiters++;
  
      /*
       * Unlock external mutex and wait for signal.
       * NOTE: we've held mutex locked long enough to increment
       * waiters count above, so there's no problem with
       * leaving mutex unlocked before we wait on semaphore.
       */
      qemu_mutex_unlock(mutex);
      WaitForSingleObject(cond->sema, INFINITE);
  
      /* Now waiters must rendez-vous with the signaling thread and
       * let it continue.  For cond_broadcast this has heavy contention
       * and triggers thundering herd.  So goes life.
       *
       * Decrease waiters count.  The mutex is not taken, so we have
       * to do this atomically.
       *
       * All waiters contend for the mutex at the end of this function
       * until the signaling thread relinquishes it.  To ensure
       * each waiter consumes exactly one slice of the semaphore,
       * the signaling thread stops until it is told by the last
       * waiter that it can go on.
       */
      if (InterlockedDecrement(&cond->waiters) == cond->target) {
          SetEvent(cond->continue_event);
      }
  
      qemu_mutex_lock(mutex);
  }
  
  struct QemuThreadData {
      /* Passed to win32_start_routine.  */
      void             *(*start_routine)(void *);
      void             *arg;
      short             mode;
  
      /* Only used for joinable threads. */
      bool              exited;
      void             *ret;
      CRITICAL_SECTION  cs;
  };
  
  static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES;
  
  static unsigned __stdcall win32_start_routine(void *arg)
  {
      QemuThreadData *data = (QemuThreadData *) arg;
      void *(*start_routine)(void *) = data->start_routine;
      void *thread_arg = data->arg;
  
      if (data->mode == QEMU_THREAD_DETACHED) {
          g_free(data);
          data = NULL;
      }
      TlsSetValue(qemu_thread_tls_index, data);
      qemu_thread_exit(start_routine(thread_arg));
      abort();
  }
  
  void qemu_thread_exit(void *arg)
  {
      QemuThreadData *data = TlsGetValue(qemu_thread_tls_index);
      if (data) {
          assert(data->mode != QEMU_THREAD_DETACHED);
          data->ret = arg;
          EnterCriticalSection(&data->cs);
          data->exited = true;
          LeaveCriticalSection(&data->cs);
      }
      _endthreadex(0);
  }
  
  void *qemu_thread_join(QemuThread *thread)
  {
      QemuThreadData *data;
      void *ret;
      HANDLE handle;
  
      data = thread->data;
      if (!data) {
          return NULL;
      }
      /*
       * Because multiple copies of the QemuThread can exist via
       * qemu_thread_get_self, we need to store a value that cannot
       * leak there.  The simplest, non racy way is to store the TID,
       * discard the handle that _beginthreadex gives back, and
       * get another copy of the handle here.
       */
      handle = qemu_thread_get_handle(thread);
      if (handle) {
          WaitForSingleObject(handle, INFINITE);
          CloseHandle(handle);
      }
      ret = data->ret;
      assert(data->mode != QEMU_THREAD_DETACHED);
      DeleteCriticalSection(&data->cs);
      g_free(data);
      return ret;
  }
  
  static inline void qemu_thread_init(void)
  {
      if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
          qemu_thread_tls_index = TlsAlloc();
          if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
              error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__);
          }
      }
  }
  
  
  void qemu_thread_create(QemuThread *thread,
                         void *(*start_routine)(void *),
                         void *arg, int mode)
  {
      HANDLE hThread;
  
      struct QemuThreadData *data;
      qemu_thread_init();
      data = g_malloc(sizeof *data);
      data->start_routine = start_routine;
      data->arg = arg;
      data->mode = mode;
      data->exited = false;
  
      if (data->mode != QEMU_THREAD_DETACHED) {
          InitializeCriticalSection(&data->cs);
      }
  
      hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
                                        data, 0, &thread->tid);
      if (!hThread) {
          error_exit(GetLastError(), __func__);
      }
      CloseHandle(hThread);
      thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
  }
  
  void qemu_thread_get_self(QemuThread *thread)
  {
      qemu_thread_init();
      thread->data = TlsGetValue(qemu_thread_tls_index);
      thread->tid = GetCurrentThreadId();
  }
  
  HANDLE qemu_thread_get_handle(QemuThread *thread)
  {
      QemuThreadData *data;
      HANDLE handle;
  
      data = thread->data;
      if (!data) {
          return NULL;
      }
  
      assert(data->mode != QEMU_THREAD_DETACHED);
      EnterCriticalSection(&data->cs);
      if (!data->exited) {
          handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
                              thread->tid);
      } else {
          handle = NULL;
      }
      LeaveCriticalSection(&data->cs);
      return handle;
  }
  
  int qemu_thread_is_self(QemuThread *thread)
  {
      return GetCurrentThreadId() == thread->tid;
  }
  