summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testlock.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testlock.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testlock.c b/src/contrib/SDL-3.2.20/test/testlock.c
new file mode 100644
index 0000000..971b303
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testlock.c
@@ -0,0 +1,212 @@
1/*
2 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12
13/* Test the thread and mutex locking functions
14 Also exercises the system's signal/thread interaction
15*/
16
17#include <signal.h>
18#include <stdlib.h> /* for atexit() */
19
20#include <SDL3/SDL.h>
21#include <SDL3/SDL_main.h>
22#include <SDL3/SDL_test.h>
23
24static SDL_Mutex *mutex = NULL;
25static SDL_ThreadID mainthread;
26static SDL_AtomicInt doterminate;
27static int nb_threads = 6;
28static SDL_Thread **threads;
29static int worktime = 1000;
30static SDLTest_CommonState *state;
31
32/**
33 * SDL_Quit() shouldn't be used with atexit() directly because
34 * calling conventions may differ...
35 */
36static void
37SDL_Quit_Wrapper(void)
38{
39 SDL_Quit();
40 SDLTest_CommonDestroyState(state);
41}
42
43static void printid(void)
44{
45 SDL_Log("Thread %" SDL_PRIu64 ": exiting", SDL_GetCurrentThreadID());
46}
47
48static void terminate(int sig)
49{
50 (void)signal(SIGINT, terminate);
51 SDL_SetAtomicInt(&doterminate, 1);
52}
53
54static void closemutex(int sig)
55{
56 SDL_ThreadID id = SDL_GetCurrentThreadID();
57 int i;
58 SDL_Log("Thread %" SDL_PRIu64 ": Cleaning up...", id == mainthread ? 0 : id);
59 SDL_SetAtomicInt(&doterminate, 1);
60 if (threads) {
61 for (i = 0; i < nb_threads; ++i) {
62 SDL_WaitThread(threads[i], NULL);
63 }
64 SDL_free(threads);
65 threads = NULL;
66 }
67 SDL_DestroyMutex(mutex);
68 /* Let 'main()' return normally */
69 if (sig != 0) {
70 exit(sig);
71 }
72}
73
74static int SDLCALL
75Run(void *data)
76{
77 SDL_ThreadID current_thread = SDL_GetCurrentThreadID();
78
79 if (current_thread == mainthread) {
80 (void)signal(SIGTERM, closemutex);
81 }
82 SDL_Log("Thread %" SDL_PRIu64 ": starting up", current_thread);
83 while (!SDL_GetAtomicInt(&doterminate)) {
84 SDL_Log("Thread %" SDL_PRIu64 ": ready to work", current_thread);
85 SDL_LockMutex(mutex);
86 SDL_Log("Thread %" SDL_PRIu64 ": start work!", current_thread);
87 SDL_Delay(1 * worktime);
88 SDL_Log("Thread %" SDL_PRIu64 ": work done!", current_thread);
89 SDL_UnlockMutex(mutex);
90
91 /* If this sleep isn't done, then threads may starve */
92 SDL_Delay(10);
93 }
94 if (current_thread == mainthread && SDL_GetAtomicInt(&doterminate)) {
95 SDL_Log("Thread %" SDL_PRIu64 ": raising SIGTERM", current_thread);
96 (void)raise(SIGTERM);
97 }
98 SDL_Log("Thread %" SDL_PRIu64 ": exiting!", current_thread);
99 return 0;
100}
101
102#ifndef _WIN32
103static Uint32 hit_timeout(void *param, SDL_TimerID timerID, Uint32 interval) {
104 SDL_Log("Hit timeout! Sending SIGINT!");
105 (void)raise(SIGINT);
106 return 0;
107}
108#endif
109
110int main(int argc, char *argv[])
111{
112 int i;
113#ifndef _WIN32
114 int timeout = 0;
115#endif
116
117 /* Initialize test framework */
118 state = SDLTest_CommonCreateState(argv, 0);
119 if (!state) {
120 return 1;
121 }
122
123 /* Parse commandline */
124 for (i = 1; i < argc;) {
125 int consumed;
126
127 consumed = SDLTest_CommonArg(state, i);
128 if (!consumed) {
129 if (SDL_strcmp(argv[i], "--nbthreads") == 0) {
130 if (argv[i + 1]) {
131 char *endptr;
132 nb_threads = SDL_strtol(argv[i + 1], &endptr, 0);
133 if (endptr != argv[i + 1] && *endptr == '\0' && nb_threads > 0) {
134 consumed = 2;
135 }
136 }
137 } else if (SDL_strcmp(argv[i], "--worktime") == 0) {
138 if (argv[i + 1]) {
139 char *endptr;
140 nb_threads = SDL_strtol(argv[i + 1], &endptr, 0);
141 if (endptr != argv[i + 1] && *endptr == '\0' && nb_threads > 0) {
142 consumed = 2;
143 }
144 }
145#ifndef _WIN32
146 } else if (SDL_strcmp(argv[i], "--timeout") == 0) {
147 if (argv[i + 1]) {
148 char *endptr;
149 timeout = SDL_strtol(argv[i + 1], &endptr, 0);
150 if (endptr != argv[i + 1] && *endptr == '\0' && timeout > 0) {
151 consumed = 2;
152 }
153 }
154#endif
155 }
156 }
157 if (consumed <= 0) {
158 static const char *options[] = {
159 "[--nbthreads NB]",
160 "[--worktime ms]",
161#ifndef _WIN32
162 "[--timeout ms]",
163#endif
164 NULL,
165 };
166 SDLTest_CommonLogUsage(state, argv[0], options);
167 exit(1);
168 }
169
170 i += consumed;
171 }
172
173 threads = SDL_malloc(nb_threads * sizeof(SDL_Thread*));
174
175 /* Load the SDL library */
176 if (!SDL_Init(0)) {
177 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError());
178 exit(1);
179 }
180 (void)atexit(SDL_Quit_Wrapper);
181
182 SDL_SetAtomicInt(&doterminate, 0);
183
184 mutex = SDL_CreateMutex();
185 if (!mutex) {
186 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create mutex: %s", SDL_GetError());
187 exit(1);
188 }
189
190 mainthread = SDL_GetCurrentThreadID();
191 SDL_Log("Main thread: %" SDL_PRIu64, mainthread);
192 (void)atexit(printid);
193 for (i = 0; i < nb_threads; ++i) {
194 char name[64];
195 (void)SDL_snprintf(name, sizeof(name), "Worker%d", i);
196 threads[i] = SDL_CreateThread(Run, name, NULL);
197 if (threads[i] == NULL) {
198 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread!");
199 }
200 }
201
202#ifndef _WIN32
203 if (timeout) {
204 SDL_AddTimer(timeout, hit_timeout, NULL);
205 }
206#endif
207
208 (void)signal(SIGINT, terminate);
209 Run(NULL);
210
211 return 0; /* Never reached */
212}