Przeglądaj źródła

Z991239-385 #comment toolkit添加 跨平台 mutex 和 once

gifur 5 lat temu
rodzic
commit
833c9ad04b
3 zmienionych plików z 191 dodań i 4 usunięć
  1. 25 4
      libtoolkit/toolkit.h
  2. 85 0
      libtoolkit/unix/mutex.c
  3. 81 0
      libtoolkit/win/mutex.c

+ 25 - 4
libtoolkit/toolkit.h

@@ -11,25 +11,46 @@
 
 #include "config.h"
 #include <stdint.h>
+#include "memutil.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#ifdef _WIN32
+    typedef CRITICAL_SECTION toolkit_mutex_t;
+	typedef struct toolkit_once_s {
+		unsigned char ran;
+		HANDLE event;
+    } toolkit_once_t;
+#define TOOLKIT_ONCE_INIT { 0, NULL }
+#else
+    typedef pthread_mutex_t toolkit_mutex_t;
+    typedef pthread_once_t toolkit_once_t;
+#define TOOLKIT_ONCE_INIT PTHREAD_ONCE_INIT
+
+#endif //_WIN32
+
+    TOOLKIT_API void toolkit_once(toolkit_once_t* guard, void (*callback)(void));
+
+	TOOLKIT_API int toolkit_mutex_init(toolkit_mutex_t* handle);
+	TOOLKIT_API int toolkit_mutex_init_recursive(toolkit_mutex_t* handle);
+	TOOLKIT_API void toolkit_mutex_destroy(toolkit_mutex_t* handle);
+	TOOLKIT_API void toolkit_mutex_lock(toolkit_mutex_t* handle);
+	TOOLKIT_API int toolkit_mutex_trylock(toolkit_mutex_t* handle);
+	TOOLKIT_API void toolkit_mutex_unlock(toolkit_mutex_t* handle);
 
 
     typedef struct tk_process_s tk_process_t;
     typedef struct tk_process_option_s tk_process_option_t;
     typedef void (*tk_exit_cb)(tk_process_t*, int64_t);
     
-	struct tk_process_s
-    {
+	struct tk_process_s {
         int pid;
         HANDLE handle;
     };
 
-    struct tk_process_option_s
-    {
+    struct tk_process_option_s {
         tk_exit_cb exit_cb;
         const char* file;
         char* params;

+ 85 - 0
libtoolkit/unix/mutex.c

@@ -0,0 +1,85 @@
+#include "toolkit.h"
+
+#ifndef _WIN32
+
+int toolkit_mutex_init(toolkit_mutex_t* mutex)
+{
+#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
+	if (pthread_mutex_init(mutex, NULL) != 0)
+		return -1;
+	return 0;
+#else
+	pthread_mutexattr_t attr;
+	int err;
+
+	if (pthread_mutexattr_init(&attr))
+		abort();
+
+	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
+		abort();
+
+	err = pthread_mutex_init(mutex, &attr);
+
+	if (pthread_mutexattr_destroy(&attr))
+		abort();
+
+	return err == 0 ? 0 : -1;
+#endif
+}
+
+
+int toolkit_mutex_init_recursive(toolkit_mutex_t* mutex) {
+	pthread_mutexattr_t attr;
+	int err;
+
+	if (pthread_mutexattr_init(&attr))
+		abort();
+
+	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+		abort();
+
+	err = pthread_mutex_init(mutex, &attr);
+
+	if (pthread_mutexattr_destroy(&attr))
+		abort();
+
+	return err == 0 ? 0 : -1;
+}
+
+
+void toolkit_mutex_destroy(toolkit_mutex_t* mutex) {
+	if (pthread_mutex_destroy(mutex))
+		abort();
+}
+
+
+void toolkit_mutex_lock(toolkit_mutex_t* mutex) {
+	if (pthread_mutex_lock(mutex))
+		abort();
+}
+
+
+int toolkit_mutex_trylock(toolkit_mutex_t* mutex) {
+	int err;
+
+	err = pthread_mutex_trylock(mutex);
+	if (err) {
+		if (err != EBUSY && err != EAGAIN)
+			abort();
+		return -1;
+	}
+
+	return 0;
+}
+
+void toolkit_mutex_unlock(toolkit_mutex_t* mutex) {
+	if (pthread_mutex_unlock(mutex))
+		abort();
+}
+
+void toolkit_once(toolkit_once_t* guard, void (*callback)(void)) {
+	if (pthread_once(guard, callback))
+		abort();
+}
+
+#endif //NOT _WIN32

+ 81 - 0
libtoolkit/win/mutex.c

@@ -0,0 +1,81 @@
+#include "toolkit.h"
+#include "assert.h"
+
+#ifdef _WIN32
+
+int toolkit_mutex_init(toolkit_mutex_t* mutex) {
+	InitializeCriticalSection(mutex);
+	return 0;
+}
+
+
+int toolkit_mutex_init_recursive(toolkit_mutex_t* mutex) {
+	return toolkit_mutex_init(mutex);
+}
+
+
+void toolkit_mutex_destroy(toolkit_mutex_t* mutex) {
+	DeleteCriticalSection(mutex);
+}
+
+
+void toolkit_mutex_lock(toolkit_mutex_t* mutex) {
+	EnterCriticalSection(mutex);
+}
+
+int toolkit_mutex_trylock(toolkit_mutex_t* mutex) {
+	if (TryEnterCriticalSection(mutex))
+		return 0;
+	else
+		return -1;
+}
+
+
+void toolkit_mutex_unlock(toolkit_mutex_t* mutex) {
+	LeaveCriticalSection(mutex);
+}
+
+static void toolkit__once_inner(toolkit_once_t* guard, void (*callback)(void)) 
+{
+    DWORD result;
+    HANDLE existing_event, created_event;
+
+    created_event = CreateEvent(NULL, 1, 0, NULL);
+    if (created_event == 0) {
+        /* Could fail in a low-memory situation? */
+        abort();
+    }
+
+    existing_event = InterlockedCompareExchangePointer(&guard->event,
+        created_event,
+        NULL);
+
+    if (existing_event == NULL) {
+        /* We won the race */
+        callback();
+
+        result = SetEvent(created_event);
+        assert(result);
+        guard->ran = 1;
+
+    }
+    else {
+        /* We lost the race. Destroy the event we created and wait for the existing
+         * one to become signaled. */
+        CloseHandle(created_event);
+        result = WaitForSingleObject(existing_event, INFINITE);
+        assert(result == WAIT_OBJECT_0);
+    }
+}
+
+
+void toolkit_once(toolkit_once_t* guard, void (*callback)(void))
+{
+    /* Fast case - avoid WaitForSingleObject. */
+    if (guard->ran) {
+        return;
+    }
+    toolkit__once_inner(guard, callback);
+}
+
+#endif //_WIN32