aboutsummaryrefslogtreecommitdiff
path: root/src/platform/windows/win_thread.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-01-12 20:46:20 -0800
committerGarrett D'Amore <garrett@damore.org>2017-01-12 21:44:44 -0800
commit2bb6a23037656474a90d869c5147b32bae1a2e40 (patch)
tree90697aa3fba3186296a18decb32691a1a143b50a /src/platform/windows/win_thread.c
parent70348e2d4725c9ec43f51811d290c22c782058ac (diff)
downloadnng-2bb6a23037656474a90d869c5147b32bae1a2e40.tar.gz
nng-2bb6a23037656474a90d869c5147b32bae1a2e40.tar.bz2
nng-2bb6a23037656474a90d869c5147b32bae1a2e40.zip
Initial swag at Win32. Much to do still.
Diffstat (limited to 'src/platform/windows/win_thread.c')
-rw-r--r--src/platform/windows/win_thread.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c
new file mode 100644
index 00000000..2c967b84
--- /dev/null
+++ b/src/platform/windows/win_thread.c
@@ -0,0 +1,200 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+// POSIX threads.
+
+#include "core/nng_impl.h"
+
+#ifdef PLATFORM_WINDOWS
+
+int
+nni_plat_mtx_init(nni_plat_mtx *mtx)
+{
+ InitializeCritialSection(&mtx->cs);
+ mtx->owner = 0;
+ return (0);
+}
+
+
+void
+nni_plat_mtx_fini(nni_plat_mtx *mtx)
+{
+ if (mtx->owner != 0) {
+ nni_panic("cannot delete critical section: mutex owned!")
+ }
+ DeleteCriticalSection(&mtx->cs);
+}
+
+
+void
+nni_plat_mtx_lock(nni_plat_mtx *mtx)
+{
+ EnterCriticalSection(&mtx->cs);
+ if (mtx->owner != 0) {
+ nni_panic("recursive mutex entry!");
+ }
+ mtx->owner = GetCurrentThreadId();
+}
+
+
+void
+nni_plat_mtx_unlock(nni_plat_mtx *mtx)
+{
+ if (mtx->owner != GetCurrentThreadId()) {
+ nni_panic("cannot unlock mutex: not owner!");
+ }
+ self->owner = 0;
+ LeaveCriticalSection(&mtx->cs);
+}
+
+
+int
+nni_plat_mtx_trylock(nni_plat_mtx *mtx)
+{
+ BOOL ok;
+
+ ok = TryEnterCriticalSection(&mtx->cs);
+ if (!ok) {
+ return (NNG_EBUSY);
+ }
+ if (mtx->owner != 0) {
+ nni_panic("recursive trymutex entry?!?")
+ }
+ mtx->owner = GetCurrentThreadId();
+ return (0);
+}
+
+
+int
+nni_plat_cv_init(nni_plat_cv *cv, nni_plat_mtx *mtx)
+{
+ InitializeConditionVariable(&cv->cv);
+ cv->cs = &mtx->cs;
+ return (0);
+}
+
+
+void
+nni_plat_cv_wake(nni_plat_cv *cv)
+{
+ int rv;
+
+ if ((rv = pthread_cond_broadcast(&cv->cv)) != 0) {
+ nni_panic("pthread_cond_broadcast: %s", strerror(rv));
+ }
+}
+
+
+void
+nni_plat_cv_wait(nni_plat_cv *cv)
+{
+ (void) SleepConditionVariable(&cv->cv, &cv->cs, INFINITE);
+}
+
+
+int
+nni_plat_cv_until(nni_plat_cv *cv, nni_time until)
+{
+ nni_time now;
+ DWORD msec;
+ BOOL ok;
+
+ now = nni_plat_clock();
+ if (now > until) {
+ msec = 0;
+ } else {
+ // times are in usec, but win32 wants millis
+ msec = (until - now)/1000;
+ }
+
+ ok = SleepConditionVariable(&cv->cv, &cv->cs, msec);
+ return (ok ? 0 : NNG_ETIMEDOUT);
+}
+
+
+void
+nni_plat_cv_fini(nni_plat_cv *cv)
+{
+}
+
+
+static unsigned int __stdcall
+nni_plat_thread_main(void *arg)
+{
+ nni_plat_thr *thr = arg;
+
+ thr->func(thr->arg);
+ return (0);
+}
+
+
+int
+nni_plat_thr_init(nni_plat_thr *thr, void (*fn)(void *), void *arg)
+{
+ thr->func = fn;
+ thr->arg = arg;
+
+ thr->handle = (HANDLE) _beginthreadex(NULL, 0,
+ nni_plat_thr_main, thr, 0, NULL);
+ if (thr->handle == NULL) {
+ return (NNG_ENOMEM); // Best guess...
+ }
+ return (0);
+}
+
+
+void
+nni_plat_thr_fini(nni_plat_thr *thr)
+{
+ if (WaitForSingleObject(thr->handle, INFINITE) == WAIT_FAILED) {
+ nni_panic("waiting for thread failed!");
+ }
+ if (CloseHandle(thr->handle) == 0) {
+ nni_panic("close handle for thread failed!");
+ }
+}
+
+
+int
+nni_plat_init(int (*helper)(void))
+{
+ int rv;
+ LONG old;
+ static LONG initing = 0;
+ static LONG inited = 0;
+
+ if (inited) {
+ return (0); // fast path
+ }
+
+ // This logic gets us to initialize the platform just once.
+ // If two threads enter here together, only one will get to run,
+ // and the other will be put to sleep briefly so that the first
+ // can complete. This is a poor man's singleton initializer, since
+ // we can't statically initialize critical sections.
+ while ((old = InterlockedTestExchange(&initing, 0, 1)) != 0) {
+ Sleep(1);
+ }
+ if (!inited) {
+ helper();
+ inited = 1;
+ }
+ InterlockExchange(&initing, 0);
+
+ return (rv);
+}
+
+
+void
+nni_plat_fini(void)
+{
+}
+
+
+#endif