1 // Copyright 2022 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 #include <string.h>
7
8 #include <xnnpack.h>
9 #include <xnnpack/common.h>
10 #include <xnnpack/log.h>
11 #include <xnnpack/mutex.h>
12
13 #if XNN_PLATFORM_WINDOWS
14 #ifndef WIN32_LEAN_AND_MEAN
15 #define WIN32_LEAN_AND_MEAN
16 #endif
17 #include <windows.h>
18 #elif XNN_PLATFORM_MACOS || XNN_PLATFORM_IOS
19 #include <dispatch/dispatch.h>
20 #else
21 #include <pthread.h>
22 #endif
23
xnn_mutex_init(struct xnn_mutex * mutex)24 enum xnn_status xnn_mutex_init(struct xnn_mutex* mutex) {
25 #if XNN_PLATFORM_WINDOWS
26 mutex->handle = CreateMutexW(
27 /* security attributes */ NULL,
28 /* initially owned */ FALSE,
29 /* name */ NULL);
30 if (mutex->handle == NULL) {
31 xnn_log_error("failed to initialize mutex, error code: %" PRIu32, (uint32_t) GetLastError());
32 return xnn_status_out_of_memory;
33 }
34 #elif XNN_PLATFORM_MACOS || XNN_PLATFORM_IOS
35 mutex->semaphore = dispatch_semaphore_create(1);
36 if (mutex->semaphore == NULL) {
37 xnn_log_error("failed to initialize mutex");
38 return xnn_status_out_of_memory;
39 }
40 #elif !XNN_PLATFORM_WEB || defined(__EMSCRIPTEN_PTHREADS__)
41 const int ret = pthread_mutex_init(&mutex->mutex, NULL);
42 if (ret != 0) {
43 xnn_log_error("failed to initialize mutex, error code: %d", ret);
44 return xnn_status_out_of_memory;
45 }
46 #endif
47 return xnn_status_success;
48 }
49
xnn_mutex_lock(struct xnn_mutex * mutex)50 enum xnn_status xnn_mutex_lock(struct xnn_mutex* mutex) {
51 #if XNN_PLATFORM_WINDOWS
52 const DWORD wait_result = WaitForSingleObject(mutex->handle, INFINITE);
53 if (WAIT_OBJECT_0 != wait_result) {
54 xnn_log_error("failed to lock mutex, error code: %" PRIu32, (uint32_t) wait_result);
55 return xnn_status_invalid_state;
56 }
57 #elif XNN_PLATFORM_MACOS || XNN_PLATFORM_IOS
58 const int wait_result = dispatch_semaphore_wait(mutex->semaphore, DISPATCH_TIME_FOREVER);
59 if (0 != wait_result) {
60 xnn_log_error("failed to lock mutex, error code: %d", wait_result);
61 return xnn_status_invalid_state;
62 }
63 #elif !XNN_PLATFORM_WEB || defined(__EMSCRIPTEN_PTHREADS__)
64 const int ret = pthread_mutex_lock(&mutex->mutex);
65 if (ret != 0) {
66 xnn_log_error("failed to lock mutex, error code: %d", ret);
67 return xnn_status_invalid_state;
68 }
69 #endif
70 return xnn_status_success;
71 }
72
xnn_mutex_unlock(struct xnn_mutex * mutex)73 enum xnn_status xnn_mutex_unlock(struct xnn_mutex* mutex) {
74 #if XNN_PLATFORM_WINDOWS
75 if (ReleaseMutex(mutex->handle) == 0) {
76 xnn_log_error("failed to unlock mutex, error code: %" PRIu32, (uint32_t) GetLastError());
77 return xnn_status_invalid_state;
78 }
79 #elif XNN_PLATFORM_MACOS || XNN_PLATFORM_IOS
80 dispatch_semaphore_signal(mutex->semaphore);
81 #elif !XNN_PLATFORM_WEB || defined(__EMSCRIPTEN_PTHREADS__)
82 const int ret = pthread_mutex_unlock(&mutex->mutex);
83 if (ret != 0) {
84 xnn_log_error("failed to unlock mutex, error code: %d", ret);
85 return xnn_status_invalid_state;
86 }
87 #endif
88 return xnn_status_success;
89 }
90
xnn_mutex_destroy(struct xnn_mutex * mutex)91 enum xnn_status xnn_mutex_destroy(struct xnn_mutex* mutex) {
92 #if XNN_PLATFORM_WINDOWS
93 if (CloseHandle(mutex->handle) == 0) {
94 xnn_log_error("failed to destroy mutex, error code: %" PRIu32, (uint32_t) GetLastError());
95 return xnn_status_invalid_state;
96 }
97 #elif XNN_PLATFORM_MACOS || XNN_PLATFORM_IOS
98 dispatch_release(mutex->semaphore);
99 #elif !XNN_PLATFORM_WEB || defined(__EMSCRIPTEN_PTHREADS__)
100 const int ret = pthread_mutex_destroy(&mutex->mutex);
101 if (ret != 0) {
102 xnn_log_error("failed to destroy mutex, error code: %d", ret);
103 return xnn_status_invalid_state;
104 }
105 #endif
106 memset(mutex, 0, sizeof(struct xnn_mutex));
107 return xnn_status_success;
108 }
109