1 | /* |
2 | Copyright (C) 1997-2021 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 <stdio.h> |
19 | #include <stdlib.h> /* for atexit() */ |
20 | |
21 | #include "SDL.h" |
22 | |
23 | static SDL_mutex *mutex = NULL; |
24 | static SDL_threadID mainthread; |
25 | static SDL_Thread *threads[6]; |
26 | static SDL_atomic_t doterminate; |
27 | |
28 | /* |
29 | * SDL_Quit() shouldn't be used with atexit() directly because |
30 | * calling conventions may differ... |
31 | */ |
32 | static void |
33 | SDL_Quit_Wrapper(void) |
34 | { |
35 | SDL_Quit(); |
36 | } |
37 | |
38 | void |
39 | printid(void) |
40 | { |
41 | SDL_Log("Process %lu: exiting\n" , SDL_ThreadID()); |
42 | } |
43 | |
44 | void |
45 | terminate(int sig) |
46 | { |
47 | signal(SIGINT, terminate); |
48 | SDL_AtomicSet(&doterminate, 1); |
49 | } |
50 | |
51 | void |
52 | closemutex(int sig) |
53 | { |
54 | SDL_threadID id = SDL_ThreadID(); |
55 | int i; |
56 | SDL_Log("Process %lu: Cleaning up...\n" , id == mainthread ? 0 : id); |
57 | SDL_AtomicSet(&doterminate, 1); |
58 | for (i = 0; i < 6; ++i) |
59 | SDL_WaitThread(threads[i], NULL); |
60 | SDL_DestroyMutex(mutex); |
61 | exit(sig); |
62 | } |
63 | |
64 | int SDLCALL |
65 | Run(void *data) |
66 | { |
67 | if (SDL_ThreadID() == mainthread) |
68 | signal(SIGTERM, closemutex); |
69 | while (!SDL_AtomicGet(&doterminate)) { |
70 | SDL_Log("Process %lu ready to work\n" , SDL_ThreadID()); |
71 | if (SDL_LockMutex(mutex) < 0) { |
72 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't lock mutex: %s" , SDL_GetError()); |
73 | exit(1); |
74 | } |
75 | SDL_Log("Process %lu, working!\n" , SDL_ThreadID()); |
76 | SDL_Delay(1 * 1000); |
77 | SDL_Log("Process %lu, done!\n" , SDL_ThreadID()); |
78 | if (SDL_UnlockMutex(mutex) < 0) { |
79 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't unlock mutex: %s" , SDL_GetError()); |
80 | exit(1); |
81 | } |
82 | /* If this sleep isn't done, then threads may starve */ |
83 | SDL_Delay(10); |
84 | } |
85 | if (SDL_ThreadID() == mainthread && SDL_AtomicGet(&doterminate)) { |
86 | SDL_Log("Process %lu: raising SIGTERM\n" , SDL_ThreadID()); |
87 | raise(SIGTERM); |
88 | } |
89 | return (0); |
90 | } |
91 | |
92 | int |
93 | main(int argc, char *argv[]) |
94 | { |
95 | int i; |
96 | int maxproc = 6; |
97 | |
98 | /* Enable standard application logging */ |
99 | SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); |
100 | |
101 | /* Load the SDL library */ |
102 | if (SDL_Init(0) < 0) { |
103 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n" , SDL_GetError()); |
104 | exit(1); |
105 | } |
106 | atexit(SDL_Quit_Wrapper); |
107 | |
108 | SDL_AtomicSet(&doterminate, 0); |
109 | |
110 | if ((mutex = SDL_CreateMutex()) == NULL) { |
111 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create mutex: %s\n" , SDL_GetError()); |
112 | exit(1); |
113 | } |
114 | |
115 | mainthread = SDL_ThreadID(); |
116 | SDL_Log("Main thread: %lu\n" , mainthread); |
117 | atexit(printid); |
118 | for (i = 0; i < maxproc; ++i) { |
119 | char name[64]; |
120 | SDL_snprintf(name, sizeof (name), "Worker%d" , i); |
121 | if ((threads[i] = SDL_CreateThread(Run, name, NULL)) == NULL) |
122 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread!\n" ); |
123 | } |
124 | signal(SIGINT, terminate); |
125 | Run(NULL); |
126 | |
127 | return (0); /* Never reached */ |
128 | } |
129 | |