parent
7357273daa
commit
457f297551
@ -1,12 +1,227 @@ |
||||
#include "jagex3_jagmisc_jagmisc.h" |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <windows.h> |
||||
#include <VersionHelpers.h> |
||||
|
||||
#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1) |
||||
|
||||
#define JAGMISC_SPIN_COUNT 4000 |
||||
#define JAGMISC_NANOS_PER_SEC 1000000000LL |
||||
|
||||
// TODO(gpe): do any of these need to be volatile?
|
||||
static bool jagmisc_unpinned; |
||||
static LARGE_INTEGER jagmisc_freq; |
||||
static CRITICAL_SECTION jagmisc_lock; |
||||
static HANDLE jagmisc_start_event; |
||||
static HANDLE jagmisc_time_request_event; |
||||
static HANDLE jagmisc_time_ready_event; |
||||
static HANDLE jagmisc_stop_event; |
||||
static HANDLE jagmisc_thread; |
||||
static int64_t jagmisc_time; |
||||
|
||||
static inline int64_t jagmisc_to_nanos(LARGE_INTEGER count) { |
||||
return count.QuadPart * JAGMISC_NANOS_PER_SEC / jagmisc_freq.QuadPart; |
||||
} |
||||
|
||||
static DWORD WINAPI jagmisc_run(LPVOID parameter) { |
||||
/* pin this thread to the system's first processor */ |
||||
HANDLE thread = GetCurrentThread(); |
||||
|
||||
DWORD_PTR affinity_mask = 0x1; |
||||
bool success = SetThreadAffinityMask(thread, affinity_mask); |
||||
|
||||
CloseHandle(thread); |
||||
|
||||
if (!success) { |
||||
return 1; |
||||
} |
||||
|
||||
/* notify Java_jagex3_jagmisc_jagmisc_init() that the thread has started successfully */ |
||||
if (!SetEvent(jagmisc_start_event)) { |
||||
return 1; |
||||
} |
||||
|
||||
/* serve time request and stop events */ |
||||
const HANDLE handles[] = { jagmisc_time_request_event, jagmisc_stop_event }; |
||||
for (;;) { |
||||
switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE)) { |
||||
case WAIT_OBJECT_0: |
||||
LARGE_INTEGER count; |
||||
if (QueryPerformanceCounter(&count)) { |
||||
jagmisc_time = jagmisc_to_nanos(count); |
||||
} else { |
||||
jagmisc_time = 0; |
||||
} |
||||
|
||||
if (!SetEvent(jagmisc_time_ready_event)) { |
||||
return 1; |
||||
} |
||||
break; |
||||
case WAIT_OBJECT_1: |
||||
return 0; |
||||
default: |
||||
return 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void jagmisc_stop(void) { |
||||
// TODO(gpe): think about what to do if we fail to stop the thread. We
|
||||
// could call TerminateThread (which sounds dangerous based on the
|
||||
// documentation) or throw a Java exception. The current behaviour of
|
||||
// ignoring the failure is okay as long as jagmisc.init() is never called
|
||||
// again in the same JVM.
|
||||
if (SetEvent(jagmisc_stop_event)) { |
||||
WaitForSingleObject(jagmisc_thread, INFINITE); |
||||
} |
||||
|
||||
CloseHandle(jagmisc_thread); |
||||
jagmisc_thread = NULL; |
||||
|
||||
CloseHandle(jagmisc_stop_event); |
||||
jagmisc_stop_event = NULL; |
||||
|
||||
CloseHandle(jagmisc_time_ready_event); |
||||
jagmisc_time_ready_event = NULL; |
||||
|
||||
CloseHandle(jagmisc_time_request_event); |
||||
jagmisc_time_request_event = NULL; |
||||
|
||||
CloseHandle(jagmisc_start_event); |
||||
jagmisc_start_event = NULL; |
||||
} |
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { |
||||
if (fdwReason == DLL_PROCESS_ATTACH) { |
||||
/*
|
||||
* We only need to pin the timer thread to a single processor prior to |
||||
* Windows Vista. |
||||
*/ |
||||
jagmisc_unpinned = IsWindowsVistaOrGreater(); |
||||
if (jagmisc_unpinned) { |
||||
return TRUE; |
||||
} |
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&jagmisc_lock, JAGMISC_SPIN_COUNT)) { |
||||
return FALSE; |
||||
} |
||||
} |
||||
return TRUE; |
||||
} |
||||
|
||||
JNIEXPORT jboolean JNICALL Java_jagex3_jagmisc_jagmisc_init(JNIEnv *env, jclass cls) { |
||||
return JNI_FALSE; |
||||
if (jagmisc_unpinned) { |
||||
return (jboolean) QueryPerformanceFrequency(&jagmisc_freq); |
||||
} |
||||
|
||||
EnterCriticalSection(&jagmisc_lock); |
||||
jboolean success = JNI_FALSE; |
||||
|
||||
if (jagmisc_thread) { |
||||
jagmisc_stop(); |
||||
} |
||||
|
||||
if (!QueryPerformanceFrequency(&jagmisc_freq)) { |
||||
goto unlock; |
||||
} |
||||
|
||||
jagmisc_start_event = CreateEventA(NULL, FALSE, FALSE, NULL); |
||||
if (!jagmisc_start_event) { |
||||
goto unlock; |
||||
} |
||||
|
||||
jagmisc_time_request_event = CreateEventA(NULL, FALSE, FALSE, NULL); |
||||
if (!jagmisc_time_request_event) { |
||||
goto create_time_request_event_failed; |
||||
} |
||||
|
||||
jagmisc_time_ready_event = CreateEventA(NULL, FALSE, FALSE, NULL); |
||||
if (!jagmisc_time_ready_event) { |
||||
goto create_time_ready_event_failed; |
||||
} |
||||
|
||||
jagmisc_stop_event = CreateEventA(NULL, FALSE, FALSE, NULL); |
||||
if (!jagmisc_stop_event) { |
||||
goto create_stop_event_failed; |
||||
} |
||||
|
||||
jagmisc_thread = CreateThread(NULL, 0, &jagmisc_run, NULL, 0, NULL); |
||||
if (!jagmisc_thread) { |
||||
goto create_thread_failed; |
||||
} |
||||
|
||||
const HANDLE handles[] = { jagmisc_start_event, jagmisc_thread }; |
||||
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); |
||||
if (result != WAIT_OBJECT_0) { |
||||
goto start_failed; |
||||
} |
||||
|
||||
success = JNI_TRUE; |
||||
goto unlock; |
||||
|
||||
start_failed: |
||||
CloseHandle(jagmisc_thread); |
||||
jagmisc_thread = NULL; |
||||
create_thread_failed: |
||||
CloseHandle(jagmisc_stop_event); |
||||
jagmisc_stop_event = NULL; |
||||
create_stop_event_failed: |
||||
CloseHandle(jagmisc_time_ready_event); |
||||
jagmisc_time_ready_event = NULL; |
||||
create_time_ready_event_failed: |
||||
CloseHandle(jagmisc_time_request_event); |
||||
jagmisc_time_request_event = NULL; |
||||
create_time_request_event_failed: |
||||
CloseHandle(jagmisc_start_event); |
||||
jagmisc_start_event = NULL; |
||||
unlock: |
||||
LeaveCriticalSection(&jagmisc_lock); |
||||
return success; |
||||
} |
||||
|
||||
JNIEXPORT void JNICALL Java_jagex3_jagmisc_jagmisc_Quit0(JNIEnv *env, jclass cls) { |
||||
if (jagmisc_unpinned) { |
||||
return; |
||||
} |
||||
|
||||
EnterCriticalSection(&jagmisc_lock); |
||||
if (jagmisc_thread) { |
||||
jagmisc_stop(); |
||||
} |
||||
LeaveCriticalSection(&jagmisc_lock); |
||||
} |
||||
|
||||
JNIEXPORT jlong JNICALL Java_jagex3_jagmisc_jagmisc_nanoTime(JNIEnv *env, jclass cls) { |
||||
if (jagmisc_unpinned) { |
||||
LARGE_INTEGER count; |
||||
if (!QueryPerformanceCounter(&count)) { |
||||
return 0; |
||||
} |
||||
return jagmisc_to_nanos(count); |
||||
} |
||||
|
||||
EnterCriticalSection(&jagmisc_lock); |
||||
jlong time = 0; |
||||
|
||||
if (!jagmisc_thread) { |
||||
goto unlock; |
||||
} |
||||
|
||||
if (!SetEvent(jagmisc_time_request_event)) { |
||||
goto unlock; |
||||
} |
||||
|
||||
const HANDLE handles[] = { jagmisc_time_ready_event, jagmisc_thread }; |
||||
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); |
||||
if (result != WAIT_OBJECT_0) { |
||||
goto unlock; |
||||
} |
||||
|
||||
time = jagmisc_time; |
||||
|
||||
unlock: |
||||
LeaveCriticalSection(&jagmisc_lock); |
||||
return time; |
||||
} |
||||
|
Loading…
Reference in new issue