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 | /* Simple test of the SDL threading code */ |
14 | |
15 | #include <stdio.h> |
16 | #include <stdlib.h> |
17 | #include <signal.h> |
18 | |
19 | #include "SDL.h" |
20 | |
21 | static SDL_TLSID tls; |
22 | static int alive = 0; |
23 | static int testprio = 0; |
24 | |
25 | /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
26 | static void |
27 | quit(int rc) |
28 | { |
29 | SDL_Quit(); |
30 | exit(rc); |
31 | } |
32 | |
33 | static const char * |
34 | getprioritystr(SDL_ThreadPriority priority) |
35 | { |
36 | switch(priority) |
37 | { |
38 | case SDL_THREAD_PRIORITY_LOW: return "SDL_THREAD_PRIORITY_LOW" ; |
39 | case SDL_THREAD_PRIORITY_NORMAL: return "SDL_THREAD_PRIORITY_NORMAL" ; |
40 | case SDL_THREAD_PRIORITY_HIGH: return "SDL_THREAD_PRIORITY_HIGH" ; |
41 | case SDL_THREAD_PRIORITY_TIME_CRITICAL: return "SDL_THREAD_PRIORITY_TIME_CRITICAL" ; |
42 | } |
43 | |
44 | return "???" ; |
45 | } |
46 | |
47 | int SDLCALL |
48 | ThreadFunc(void *data) |
49 | { |
50 | SDL_ThreadPriority prio = SDL_THREAD_PRIORITY_NORMAL; |
51 | |
52 | SDL_TLSSet(tls, "baby thread" , NULL); |
53 | SDL_Log("Started thread %s: My thread id is %lu, thread data = %s\n" , |
54 | (char *) data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls)); |
55 | while (alive) { |
56 | SDL_Log("Thread '%s' is alive!\n" , (char *) data); |
57 | |
58 | if (testprio) { |
59 | SDL_Log("SDL_SetThreadPriority(%s):%d\n" , getprioritystr(prio), SDL_SetThreadPriority(prio)); |
60 | if (++prio > SDL_THREAD_PRIORITY_TIME_CRITICAL) |
61 | prio = SDL_THREAD_PRIORITY_LOW; |
62 | } |
63 | |
64 | SDL_Delay(1 * 1000); |
65 | } |
66 | SDL_Log("Thread '%s' exiting!\n" , (char *) data); |
67 | return (0); |
68 | } |
69 | |
70 | static void |
71 | killed(int sig) |
72 | { |
73 | SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n" ); |
74 | SDL_Delay(5 * 1000); |
75 | alive = 0; |
76 | quit(0); |
77 | } |
78 | |
79 | int |
80 | main(int argc, char *argv[]) |
81 | { |
82 | int arg = 1; |
83 | SDL_Thread *thread; |
84 | |
85 | /* Enable standard application logging */ |
86 | SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); |
87 | |
88 | /* Load the SDL library */ |
89 | if (SDL_Init(0) < 0) { |
90 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n" , SDL_GetError()); |
91 | return (1); |
92 | } |
93 | |
94 | while (argv[arg] && *argv[arg] == '-') { |
95 | if (SDL_strcmp(argv[arg], "--prio" ) == 0) { |
96 | testprio = 1; |
97 | } |
98 | ++arg; |
99 | } |
100 | |
101 | tls = SDL_TLSCreate(); |
102 | SDL_assert(tls); |
103 | SDL_TLSSet(tls, "main thread" , NULL); |
104 | SDL_Log("Main thread data initially: %s\n" , (const char *)SDL_TLSGet(tls)); |
105 | |
106 | alive = 1; |
107 | thread = SDL_CreateThread(ThreadFunc, "One" , "#1" ); |
108 | if (thread == NULL) { |
109 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n" , SDL_GetError()); |
110 | quit(1); |
111 | } |
112 | SDL_Delay(5 * 1000); |
113 | SDL_Log("Waiting for thread #1\n" ); |
114 | alive = 0; |
115 | SDL_WaitThread(thread, NULL); |
116 | |
117 | SDL_Log("Main thread data finally: %s\n" , (const char *)SDL_TLSGet(tls)); |
118 | |
119 | alive = 1; |
120 | signal(SIGTERM, killed); |
121 | thread = SDL_CreateThread(ThreadFunc, "Two" , "#2" ); |
122 | if (thread == NULL) { |
123 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n" , SDL_GetError()); |
124 | quit(1); |
125 | } |
126 | raise(SIGTERM); |
127 | |
128 | SDL_Quit(); /* Never reached */ |
129 | return (0); /* Never reached */ |
130 | } |
131 | |