summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/sync/sync_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/sync/sync_windows.c')
-rw-r--r--src/osd/modules/sync/sync_windows.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/osd/modules/sync/sync_windows.c b/src/osd/modules/sync/sync_windows.c
new file mode 100644
index 00000000000..8326ce41f29
--- /dev/null
+++ b/src/osd/modules/sync/sync_windows.c
@@ -0,0 +1,376 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+//============================================================
+//
+// winsync.c - Win32 OSD core synchronization functions
+//
+//============================================================
+
+// standard windows headers
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdlib.h>
+#include <process.h>
+
+// MAME headers
+#include "osdcore.h"
+#include "osinline.h"
+#include "osdsync.h"
+
+
+//============================================================
+// DEBUGGING
+//============================================================
+
+#define DEBUG_SLOW_LOCKS 0
+#define USE_SCALABLE_LOCKS (0)
+
+
+
+//============================================================
+// TYPE DEFINITIONS
+//============================================================
+
+typedef BOOL (WINAPI *try_enter_critical_section_ptr)(LPCRITICAL_SECTION lpCriticalSection);
+
+struct osd_lock
+{
+ CRITICAL_SECTION critsect;
+};
+
+struct osd_event
+{
+ void * ptr;
+};
+
+struct osd_thread {
+ HANDLE handle;
+ osd_thread_callback callback;
+ void *param;
+};
+
+struct osd_scalable_lock
+{
+#if USE_SCALABLE_LOCKS
+ struct
+ {
+ volatile INT32 haslock; // do we have the lock?
+ INT32 filler[64/4-1]; // assumes a 64-byte cache line
+ } slot[WORK_MAX_THREADS]; // one slot per thread
+ volatile INT32 nextindex; // index of next slot to use
+#else
+ CRITICAL_SECTION section;
+#endif
+};
+
+
+//============================================================
+// GLOBAL VARIABLES
+//============================================================
+
+static try_enter_critical_section_ptr try_enter_critical_section = NULL;
+static int checked_for_try_enter = FALSE;
+
+
+
+//============================================================
+// osd_lock_alloc
+//============================================================
+
+osd_lock *osd_lock_alloc(void)
+{
+ osd_lock *lock = (osd_lock *)malloc(sizeof(*lock));
+ if (lock == NULL)
+ return NULL;
+ InitializeCriticalSection(&lock->critsect);
+ return lock;
+}
+
+
+//============================================================
+// osd_lock_acquire
+//============================================================
+
+void osd_lock_acquire(osd_lock *lock)
+{
+#if DEBUG_SLOW_LOCKS
+ osd_ticks_t ticks = osd_ticks();
+#endif
+
+ // block until we can acquire the lock
+ EnterCriticalSection(&lock->critsect);
+
+#if DEBUG_SLOW_LOCKS
+ // log any locks that take more than 1ms
+ ticks = osd_ticks() - ticks;
+ if (ticks > osd_ticks_per_second() / 1000) osd_printf_debug("Blocked %d ticks on lock acquire\n", (int)ticks);
+#endif
+}
+
+
+//============================================================
+// osd_lock_try
+//============================================================
+
+int osd_lock_try(osd_lock *lock)
+{
+ int result = TRUE;
+
+ // if we haven't yet checked for the TryEnter API, do it now
+ if (!checked_for_try_enter)
+ {
+ // see if we can use TryEnterCriticalSection
+ HMODULE library = LoadLibrary(TEXT("kernel32.dll"));
+ if (library != NULL)
+ try_enter_critical_section = (try_enter_critical_section_ptr)GetProcAddress(library, "TryEnterCriticalSection");
+ checked_for_try_enter = TRUE;
+ }
+
+ // if we have it, use it, otherwise just block
+ if (try_enter_critical_section != NULL)
+ result = (*try_enter_critical_section)(&lock->critsect);
+ else
+ EnterCriticalSection(&lock->critsect);
+ return result;
+}
+
+
+//============================================================
+// osd_lock_release
+//============================================================
+
+void osd_lock_release(osd_lock *lock)
+{
+ LeaveCriticalSection(&lock->critsect);
+}
+
+
+//============================================================
+// osd_lock_free
+//============================================================
+
+void osd_lock_free(osd_lock *lock)
+{
+ DeleteCriticalSection(&lock->critsect);
+ free(lock);
+}
+
+
+//============================================================
+// win_compare_exchange32
+//============================================================
+
+INT32 win_compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange)
+{
+ return InterlockedCompareExchange((LPLONG)ptr, (LONG)exchange, (LONG)compare);
+}
+
+
+//============================================================
+// win_compare_exchange64
+//============================================================
+
+#ifdef PTR64
+INT64 win_compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange)
+{
+ return InterlockedCompareExchange64((LONGLONG*)ptr, (LONGLONG)exchange, (LONGLONG)compare);
+}
+#endif
+
+
+//============================================================
+// win_atomic_exchange32
+//============================================================
+
+INT32 win_atomic_exchange32(INT32 volatile *ptr, INT32 exchange)
+{
+ return InterlockedExchange((LONG *) ptr, exchange);
+}
+
+
+//============================================================
+// win_atomic_add32
+//============================================================
+
+INT32 win_atomic_add32(INT32 volatile *ptr, INT32 delta)
+{
+ return InterlockedExchangeAdd((LONG *) ptr, delta) + delta;
+}
+
+//============================================================
+// osd_event_alloc
+//============================================================
+
+osd_event *osd_event_alloc(int manualreset, int initialstate)
+{
+ return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL);
+}
+
+//============================================================
+// osd_event_free
+//============================================================
+
+void osd_event_free(osd_event *event)
+{
+ CloseHandle((HANDLE) event);
+}
+
+//============================================================
+// osd_event_set
+//============================================================
+
+void osd_event_set(osd_event *event)
+{
+ SetEvent((HANDLE) event);
+}
+
+//============================================================
+// osd_event_reset
+//============================================================
+
+void osd_event_reset(osd_event *event)
+{
+ ResetEvent((HANDLE) event);
+}
+
+//============================================================
+// osd_event_wait
+//============================================================
+
+int osd_event_wait(osd_event *event, osd_ticks_t timeout)
+{
+ int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second());
+ return ( ret == WAIT_OBJECT_0);
+}
+
+//============================================================
+// osd_thread_create
+//============================================================
+
+static unsigned __stdcall worker_thread_entry(void *param)
+{
+ osd_thread *thread = (osd_thread *) param;
+ void *res;
+ res = thread->callback(thread->param);
+#ifdef PTR64
+ return (unsigned) (long long) res;
+#else
+ return (unsigned) res;
+#endif
+}
+
+osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam)
+{
+ osd_thread *thread;
+ uintptr_t handle;
+
+ thread = (osd_thread *)calloc(1, sizeof(osd_thread));
+ thread->callback = callback;
+ thread->param = cbparam;
+ handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL);
+ thread->handle = (HANDLE) handle;
+ return thread;
+}
+
+//============================================================
+// osd_thread_wait_free
+//============================================================
+
+void osd_thread_wait_free(osd_thread *thread)
+{
+ WaitForSingleObject(thread->handle, INFINITE);
+ CloseHandle(thread->handle);
+ free(thread);
+}
+
+//============================================================
+// osd_thread_adjust_priority
+//============================================================
+
+int osd_thread_adjust_priority(osd_thread *thread, int adjust)
+{
+ if (adjust)
+ SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL);
+ else
+ SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread()));
+ return TRUE;
+}
+
+//============================================================
+// osd_thread_cpu_affinity
+//============================================================
+
+int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask)
+{
+ return TRUE;
+}
+
+//============================================================
+// osd_process_kill
+//============================================================
+
+void osd_process_kill(void)
+{
+ TerminateProcess(GetCurrentProcess(), -1);
+}
+
+//============================================================
+// Scalable Locks
+//============================================================
+
+osd_scalable_lock *osd_scalable_lock_alloc(void)
+{
+ osd_scalable_lock *lock;
+
+ lock = (osd_scalable_lock *)calloc(1, sizeof(*lock));
+
+ memset(lock, 0, sizeof(*lock));
+#if USE_SCALABLE_LOCKS
+ lock->slot[0].haslock = TRUE;
+#else
+ InitializeCriticalSection(&lock->section);
+#endif
+ return lock;
+}
+
+
+INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock)
+{
+#if USE_SCALABLE_LOCKS
+ INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1);
+ INT32 backoff = 1;
+
+ while (!lock->slot[myslot].haslock)
+ {
+ INT32 backcount;
+ for (backcount = 0; backcount < backoff; backcount++)
+ osd_yield_processor();
+ backoff <<= 1;
+ }
+ lock->slot[myslot].haslock = FALSE;
+ return myslot;
+#else
+ EnterCriticalSection(&lock->section);
+ return 0;
+#endif
+}
+
+
+void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot)
+{
+#if USE_SCALABLE_LOCKS
+ atomic_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE);
+#else
+ LeaveCriticalSection(&lock->section);
+#endif
+}
+
+
+void osd_scalable_lock_free(osd_scalable_lock *lock)
+{
+#if USE_SCALABLE_LOCKS
+#else
+ DeleteCriticalSection(&lock->section);
+#endif
+ free(lock);
+}