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
23static SDL_mutex *mutex = NULL;
24static SDL_threadID mainthread;
25static SDL_Thread *threads[6];
26static SDL_atomic_t doterminate;
27
28/*
29 * SDL_Quit() shouldn't be used with atexit() directly because
30 * calling conventions may differ...
31 */
32static void
33SDL_Quit_Wrapper(void)
34{
35 SDL_Quit();
36}
37
38void
39printid(void)
40{
41 SDL_Log("Process %lu: exiting\n", SDL_ThreadID());
42}
43
44void
45terminate(int sig)
46{
47 signal(SIGINT, terminate);
48 SDL_AtomicSet(&doterminate, 1);
49}
50
51void
52closemutex(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
64int SDLCALL
65Run(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
92int
93main(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