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
24enum 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
50enum 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
73enum 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
91enum 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