Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rcheevos/src/rc_compat.c
4246 views
1
#if !defined(RC_NO_THREADS) && !defined(_WIN32) && !defined(GEKKO) && !defined(_3DS) && (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) < 500)
2
/* We'll want to use pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE, but glibc only conditionally exposes pthread_mutexattr_settype and PTHREAD_MUTEX_RECURSIVE depending on feature flags
3
* Defining _XOPEN_SOURCE must be done at the top of the source file, before including any headers
4
* pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE are specified the Single UNIX Specification (Version 2, 1997), along with POSIX later on (IEEE Standard 1003.1-2008), so should cover practically any pthread implementation
5
*/
6
#undef _XOPEN_SOURCE
7
#define _XOPEN_SOURCE 500
8
#endif
9
10
#include "rc_compat.h"
11
12
#include <assert.h>
13
#include <ctype.h>
14
#include <stdarg.h>
15
16
#ifdef RC_C89_HELPERS
17
18
int rc_strncasecmp(const char* left, const char* right, size_t length)
19
{
20
while (length)
21
{
22
if (*left != *right)
23
{
24
const int diff = tolower(*left) - tolower(*right);
25
if (diff != 0)
26
return diff;
27
}
28
29
++left;
30
++right;
31
--length;
32
}
33
34
return 0;
35
}
36
37
int rc_strcasecmp(const char* left, const char* right)
38
{
39
while (*left || *right)
40
{
41
if (*left != *right)
42
{
43
const int diff = tolower(*left) - tolower(*right);
44
if (diff != 0)
45
return diff;
46
}
47
48
++left;
49
++right;
50
}
51
52
return 0;
53
}
54
55
char* rc_strdup(const char* str)
56
{
57
const size_t length = strlen(str);
58
char* buffer = (char*)malloc(length + 1);
59
if (buffer)
60
memcpy(buffer, str, length + 1);
61
return buffer;
62
}
63
64
int rc_snprintf(char* buffer, size_t size, const char* format, ...)
65
{
66
int result;
67
va_list args;
68
69
va_start(args, format);
70
71
#ifdef __STDC_SECURE_LIB__
72
result = vsprintf_s(buffer, size, format, args);
73
#else
74
/* assume buffer is large enough and ignore size */
75
(void)size;
76
result = vsprintf(buffer, format, args);
77
#endif
78
79
va_end(args);
80
81
return result;
82
}
83
84
#endif
85
86
#ifndef __STDC_SECURE_LIB__
87
88
struct tm* rc_gmtime_s(struct tm* buf, const time_t* timer)
89
{
90
struct tm* tm = gmtime(timer);
91
memcpy(buf, tm, sizeof(*tm));
92
return buf;
93
}
94
95
#endif
96
97
#ifndef RC_NO_THREADS
98
99
#if defined(_WIN32)
100
101
/* https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c */
102
/* implementation largely taken from https://github.com/libsdl-org/SDL/blob/0fc3574/src/thread/windows/SDL_sysmutex.c */
103
104
#if defined(WINVER) && WINVER >= 0x0600
105
106
void rc_mutex_init(rc_mutex_t* mutex)
107
{
108
InitializeSRWLock(&mutex->srw_lock);
109
/* https://learn.microsoft.com/en-us/windows/win32/procthread/thread-handles-and-identifiers */
110
/* thread ids are never 0 */
111
mutex->owner = 0;
112
mutex->count = 0;
113
}
114
115
void rc_mutex_destroy(rc_mutex_t* mutex)
116
{
117
/* Nothing to do here */
118
(void)mutex;
119
}
120
121
void rc_mutex_lock(rc_mutex_t* mutex)
122
{
123
DWORD current_thread = GetCurrentThreadId();
124
if (mutex->owner == current_thread) {
125
++mutex->count;
126
assert(mutex->count > 0);
127
}
128
else {
129
AcquireSRWLockExclusive(&mutex->srw_lock);
130
assert(mutex->owner == 0 && mutex->count == 0);
131
mutex->owner = current_thread;
132
mutex->count = 1;
133
}
134
}
135
136
void rc_mutex_unlock(rc_mutex_t* mutex)
137
{
138
if (mutex->owner == GetCurrentThreadId()) {
139
assert(mutex->count > 0);
140
if (--mutex->count == 0) {
141
mutex->owner = 0;
142
ReleaseSRWLockExclusive(&mutex->srw_lock);
143
}
144
}
145
else {
146
assert(!"Tried to unlock unowned mutex");
147
}
148
}
149
150
#else
151
152
void rc_mutex_init(rc_mutex_t* mutex)
153
{
154
InitializeCriticalSection(&mutex->critical_section);
155
}
156
157
void rc_mutex_destroy(rc_mutex_t* mutex)
158
{
159
DeleteCriticalSection(&mutex->critical_section);
160
}
161
162
void rc_mutex_lock(rc_mutex_t* mutex)
163
{
164
EnterCriticalSection(&mutex->critical_section);
165
}
166
167
void rc_mutex_unlock(rc_mutex_t* mutex)
168
{
169
LeaveCriticalSection(&mutex->critical_section);
170
}
171
172
#endif
173
174
#elif defined(GEKKO)
175
176
/* https://github.com/libretro/RetroArch/pull/16116 */
177
178
void rc_mutex_init(rc_mutex_t* mutex)
179
{
180
/* LWP_MutexInit has the handle passed by reference */
181
/* Other LWP_Mutex* calls have the handle passed by value */
182
LWP_MutexInit(&mutex->handle, 1);
183
}
184
185
void rc_mutex_destroy(rc_mutex_t* mutex)
186
{
187
LWP_MutexDestroy(mutex->handle);
188
}
189
190
void rc_mutex_lock(rc_mutex_t* mutex)
191
{
192
LWP_MutexLock(mutex->handle);
193
}
194
195
void rc_mutex_unlock(rc_mutex_t* mutex)
196
{
197
LWP_MutexUnlock(mutex->handle);
198
}
199
200
#elif defined(_3DS)
201
202
void rc_mutex_init(rc_mutex_t* mutex)
203
{
204
RecursiveLock_Init(mutex);
205
}
206
207
void rc_mutex_destroy(rc_mutex_t* mutex)
208
{
209
/* Nothing to do here */
210
(void)mutex;
211
}
212
213
void rc_mutex_lock(rc_mutex_t* mutex)
214
{
215
RecursiveLock_Lock(mutex);
216
}
217
218
void rc_mutex_unlock(rc_mutex_t* mutex)
219
{
220
RecursiveLock_Unlock(mutex);
221
}
222
223
#else
224
225
void rc_mutex_init(rc_mutex_t* mutex)
226
{
227
/* Define the mutex as recursive, for consistent semantics against other rc_mutex_t implementations */
228
pthread_mutexattr_t attr;
229
pthread_mutexattr_init(&attr);
230
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
231
pthread_mutex_init(mutex, &attr);
232
pthread_mutexattr_destroy(&attr);
233
}
234
235
void rc_mutex_destroy(rc_mutex_t* mutex)
236
{
237
pthread_mutex_destroy(mutex);
238
}
239
240
void rc_mutex_lock(rc_mutex_t* mutex)
241
{
242
pthread_mutex_lock(mutex);
243
}
244
245
void rc_mutex_unlock(rc_mutex_t* mutex)
246
{
247
pthread_mutex_unlock(mutex);
248
}
249
250
#endif
251
#endif /* RC_NO_THREADS */
252
253