38
|
1 #include "SimpleThread.h"
|
|
2 #include <stddef.h>
|
|
3 #include <stdlib.h>
|
|
4 #include <pthread.h>
|
|
5 #include <signal.h>
|
|
6
|
|
7 #if defined(DEBUG)
|
|
8 #include <stdio.h>
|
|
9 #define THRDDBG(x) printf x
|
|
10 #else
|
|
11 #define THRDDBG(x)
|
|
12 #endif
|
|
13
|
|
14
|
|
15 struct SimpleThread
|
|
16 {
|
|
17 size_t threadID;
|
|
18 pthread_t nativeThread;
|
|
19 int threadStatus;
|
|
20 // void* userData;
|
|
21 };
|
|
22
|
|
23 typedef struct SimpleThreadArguments
|
|
24 {
|
|
25 int (*userFunction)(void*);
|
|
26 void* userData;
|
|
27 SimpleThread* simpleThread;
|
|
28 } SimpleThreadArguments;
|
|
29
|
|
30
|
|
31
|
|
32 static void* Internal_RunThread(void* user_data)
|
|
33 {
|
|
34 int (*user_function)(void*);
|
|
35 void* function_user_data;
|
|
36 int* status_val;
|
|
37
|
|
38 #if 0
|
|
39 /* disable signals */
|
|
40 sigset_t disable_set;
|
|
41
|
|
42 /*
|
|
43 in the main thread, set up the desired signal mask, common to most threads
|
|
44 any newly created threads will inherit this signal mask
|
|
45 */
|
|
46 sigemptyset(&disable_set);
|
|
47 sigaddset(&disable_set, SIGHUP);
|
|
48 sigaddset(&disable_set, SIGINT);
|
|
49 sigaddset(&disable_set, SIGUSR1);
|
|
50 sigaddset(&disable_set, SIGUSR2);
|
|
51 sigaddset(&disable_set, SIGALRM);
|
|
52 sigaddset(&disable_set, SIGQUIT);
|
|
53 sigaddset(&disable_set, SIGPIPE);
|
|
54 sigaddset(&disable_set, SIGTERM);
|
|
55 sigaddset(&disable_set, SIGCHLD);
|
|
56 sigaddset(&disable_set, SIGWINCH);
|
|
57 sigaddset(&disable_set, SIGVTALRM);
|
|
58 sigaddset(&disable_set, SIGPROF);
|
|
59
|
|
60
|
|
61 /* block out these signals */
|
|
62 sigprocmask(SIG_BLOCK, &disable_set, NULL);
|
|
63 #endif
|
|
64
|
|
65 SimpleThreadArguments* simple_thread_arguments = (SimpleThreadArguments*)user_data;
|
|
66 simple_thread_arguments->simpleThread->threadID = SimpleThread_GetCurrentThreadID();
|
|
67
|
|
68 user_function = simple_thread_arguments->userFunction;
|
|
69 function_user_data = simple_thread_arguments->userData;
|
|
70 status_val = &simple_thread_arguments->simpleThread->threadStatus;
|
|
71
|
|
72
|
|
73 /* I hope this is safe to delete on a different thread than it was created for. */
|
|
74 free(simple_thread_arguments);
|
|
75
|
|
76 *status_val = user_function(function_user_data);
|
|
77
|
|
78 pthread_exit(NULL);
|
|
79 return NULL;
|
|
80 }
|
|
81
|
|
82
|
|
83 SimpleThread* SimpleThread_CreateThread(int (*user_function)(void*), void* user_data)
|
|
84 {
|
|
85 pthread_attr_t thread_attributes;
|
|
86 int ret_val;
|
|
87 SimpleThread* new_thread;
|
|
88 SimpleThreadArguments* simple_thread_arguments;
|
|
89
|
|
90 new_thread = (SimpleThread*)malloc(sizeof(SimpleThread));
|
|
91 if(NULL == new_thread)
|
|
92 {
|
|
93 THRDDBG(("Out of memory.\n"));
|
|
94 return NULL;
|
|
95 }
|
|
96
|
|
97 ret_val = pthread_attr_init(&thread_attributes);
|
|
98 if(0 != ret_val)
|
|
99 {
|
|
100 /* failed */
|
|
101 THRDDBG(("pthread_attr_init failed with: %d\n", ret_val));
|
|
102 free(new_thread);
|
|
103 return 0;
|
|
104 }
|
|
105 ret_val = pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
|
|
106 if(0 != ret_val)
|
|
107 {
|
|
108 THRDDBG(("pthread_attr_setdetachstate failed with: %d\n", ret_val));
|
|
109 free(new_thread);
|
|
110 return NULL;
|
|
111 }
|
|
112
|
|
113 simple_thread_arguments = (SimpleThreadArguments*)malloc(sizeof(SimpleThreadArguments));
|
|
114 if(NULL == simple_thread_arguments)
|
|
115 {
|
|
116 THRDDBG(("Out of memory.\n"));
|
|
117 free(new_thread);
|
|
118 return NULL;
|
|
119 }
|
|
120 simple_thread_arguments->userFunction = user_function;
|
|
121 simple_thread_arguments->userData = user_data;
|
|
122 simple_thread_arguments->simpleThread = new_thread;
|
|
123
|
|
124 ret_val = pthread_create(&new_thread->nativeThread, &thread_attributes, Internal_RunThread, simple_thread_arguments);
|
|
125 if(0 != ret_val)
|
|
126 {
|
|
127 THRDDBG(("pthread_create failed with: %d\n", ret_val));
|
|
128 free(simple_thread_arguments);
|
|
129 free(new_thread);
|
|
130 return NULL;
|
|
131 }
|
|
132
|
|
133 return new_thread;
|
|
134 }
|
|
135
|
|
136
|
|
137
|
|
138 size_t SimpleThread_GetCurrentThreadID()
|
|
139 {
|
|
140 return (size_t)pthread_self();
|
|
141 }
|
|
142
|
|
143 void SimpleThread_WaitThread(SimpleThread* simple_thread, int* thread_status)
|
|
144 {
|
|
145 int ret_val;
|
|
146 if(NULL == simple_thread)
|
|
147 {
|
|
148 THRDDBG(("SimpleThread_WaitThread was passed NULL\n"));
|
|
149 return;
|
|
150 }
|
|
151
|
|
152
|
|
153 ret_val = pthread_join(simple_thread->nativeThread, 0);
|
|
154 if(0 != ret_val)
|
|
155 {
|
|
156 THRDDBG(("pthread_join failed with: %d\n", ret_val));
|
|
157 }
|
|
158 if(NULL != thread_status)
|
|
159 {
|
|
160 *thread_status = simple_thread->threadStatus;
|
|
161 }
|
|
162 free(simple_thread);
|
|
163 }
|
|
164
|
|
165 size_t SimpleThread_GetThreadID(SimpleThread* simple_thread)
|
|
166 {
|
|
167 if(NULL == simple_thread)
|
|
168 {
|
|
169 THRDDBG(("SimpleThread_GetThreadID was passed NULL\n"));
|
|
170 return 0;
|
|
171 }
|
|
172 return simple_thread->threadID;
|
|
173 }
|
|
174
|
|
175
|
|
176 int SimpleThread_GetThreadPriority(SimpleThread* simple_thread)
|
|
177 {
|
|
178 struct sched_param schedule_param;
|
|
179 int sched_policy;
|
|
180 int ret_val;
|
|
181
|
|
182 if(NULL == simple_thread)
|
|
183 {
|
|
184 THRDDBG(("SimpleThread_GetThreadPriority was passed NULL\n"));
|
|
185 return -1; /* Not sure what to return. Do other platforms use negative numbers? */
|
|
186 }
|
|
187 ret_val = pthread_getschedparam(simple_thread->nativeThread, &sched_policy, &schedule_param);
|
|
188 if(0 != ret_val)
|
|
189 {
|
|
190 THRDDBG(("SimpleThread_GetThreadPriority pthread_getschedparam failed with: %d\n", ret_val));
|
|
191 return -1;
|
|
192 }
|
|
193 return schedule_param.sched_priority;
|
|
194 }
|
|
195
|
|
196 void SimpleThread_SetThreadPriority(SimpleThread* simple_thread, int priority_level)
|
|
197 {
|
|
198 struct sched_param schedule_param;
|
|
199 int ret_val;
|
|
200
|
|
201 if(NULL == simple_thread)
|
|
202 {
|
|
203 THRDDBG(("SimpleThread_SetThreadPriority was passed NULL\n"));
|
|
204 return;
|
|
205 }
|
|
206 schedule_param.sched_priority = priority_level; /* PTHREAD_MIN_PRIORITY=0 to PTHREAD_MAX_PRIORITY=31 */
|
|
207 ret_val = pthread_setschedparam(simple_thread->nativeThread, SCHED_OTHER, &schedule_param);
|
|
208 if(0 != ret_val)
|
|
209 {
|
|
210 THRDDBG(("SimpleThread_SetThreadPriority pthread_setschedparam failed with: %d\n", ret_val));
|
|
211 return;
|
|
212 }
|
|
213 }
|
|
214
|