1 /* radare - LGPL - Copyright 2009-2018 - pancake */
2
3 #include <r_th.h>
4 #include <r_util.h>
5
6 #if __APPLE__
7 // Here to avoid polluting mach types macro redefinitions...
8 #include <mach/thread_act.h>
9 #include <mach/thread_policy.h>
10 #endif
11
12 #if __sun
13 #include <sys/pset.h>
14 #endif
15
16 #if __HAIKU__
17 #include <kernel/scheduler.h>
18 #endif
19
20 #if __WINDOWS__
_r_th_launcher(void * _th)21 static DWORD WINAPI _r_th_launcher(void *_th) {
22 #else
23 static void *_r_th_launcher(void *_th) {
24 #endif
25 int ret;
26 RThread *th = _th;
27 th->ready = true;
28 if (th->delay > 0) {
29 r_sys_sleep (th->delay);
30 } else if (th->delay < 0) {
31 r_th_lock_wait (th->lock);
32 }
33 r_th_lock_enter (th->lock);
34 do {
35 r_th_lock_leave (th->lock);
36 th->running = true;
37 ret = th->fun (th);
38 if (ret < 0) {
39 // th has been freed
40 return 0;
41 }
42 th->running = false;
43 r_th_lock_enter (th->lock);
44 } while (ret);
45 r_th_lock_leave (th->lock);
46 #if HAVE_PTHREAD
47 pthread_exit (&ret);
48 #endif
49 return 0;
50 }
51
52 R_API int r_th_push_task(struct r_th_t *th, void *user) {
53 int ret = true;
54 th->user = user;
55 r_th_lock_leave (th->lock);
56 return ret;
57 }
58
59 R_API R_TH_TID r_th_self(void) {
60 #if HAVE_PTHREAD
61 return pthread_self ();
62 #elif __WINDOWS__
63 return GetCurrentThread ();
64 #else
65 #pragma message("Not implemented on this platform")
66 return (R_TH_TID)-1;
67 #endif
68 }
69
70 R_API bool r_th_setname(RThread *th, const char *name) {
71 #if defined(HAVE_PTHREAD_NP) && HAVE_PTHREAD_NP
72 #if __linux__ || __sun
73 if (pthread_setname_np (th->tid, name) != 0) {
74 eprintf ("Failed to set thread name\n");
75 return false;
76 }
77 #elif __APPLE__
78 if (pthread_setname_np (name) != 0) {
79 eprintf ("Failed to set thread name\n");
80 return false;
81 }
82 #elif __FreeBSD__ || __OpenBSD__ || __DragonFly__ || __sun
83 pthread_set_name_np (th->tid, name);
84 #elif __NetBSD__
85 if (pthread_setname_np (th->tid, "%s", (void *)name) != 0) {
86 eprintf ("Failed to set thread name\n");
87 return false;
88 }
89 #elif __HAIKU__
90 if (rename_thread ((thread_id)th->tid, name) != B_OK) {
91 eprintf ("Failed to set thread name\n");
92 return false;
93 }
94 #else
95 #pragma message("warning r_th_setname not implemented")
96 #endif
97 #endif
98 return true;
99 }
100
101 R_API bool r_th_getname(RThread *th, char *name, size_t len) {
102 #if defined(HAVE_PTHREAD_NP) && HAVE_PTHREAD_NP
103 #if __linux__ || __NetBSD__ || __APPLE__ || __sun
104 if (pthread_getname_np (th->tid, name, len) != 0) {
105 eprintf ("Failed to get thread name\n");
106 return false;
107 }
108 #elif (__FreeBSD__ && __FreeBSD_version >= 1200000) || __DragonFly__ || (__OpenBSD__ && OpenBSD >= 201905)
109 pthread_get_name_np (th->tid, name, len);
110 #elif defined(__HAIKU__)
111 thread_info ti;
112 size_t flen = len < B_OS_NAME_LENGTH ? len : B_OS_NAME_LENGTH;
113
114 if (get_thread_info ((thread_id)th->tid, &ti) != B_OK) {
115 eprintf ("Failed to get thread name\n");
116 return false;
117 }
118
119 r_str_ncpy (name, ti.name, flen);
120 #else
121 #pragma message("warning r_th_getname not implemented")
122 #endif
123 #endif
124 return true;
125 }
126
127 R_API bool r_th_setaffinity(RThread *th, int cpuid) {
128 #if __linux__
129 #if defined(__GLIBC__) && defined (__GLIBC_MINOR__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)
130 // Old versions of GNU libc don't have this feature
131 #pragma message("warning r_th_setaffinity not implemented")
132 #else
133 cpu_set_t c;
134 CPU_ZERO(&c);
135 CPU_SET(cpuid, &c);
136
137 if (sched_setaffinity (th->tid, sizeof (c), &c) != 0) {
138 eprintf ("Failed to set cpu affinity\n");
139 return false;
140 }
141 #endif
142 #elif __FreeBSD__ || __DragonFly__
143 cpuset_t c;
144 CPU_ZERO(&c);
145 CPU_SET(cpuid, &c);
146
147 if (pthread_setaffinity_np (th->tid, sizeof (c), &c) != 0) {
148 eprintf ("Failed to set cpu affinity\n");
149 return false;
150 }
151 #elif __NetBSD__
152 cpuset_t *c;
153 c = cpuset_create ();
154
155 if (pthread_setaffinity_np (th->tid, cpuset_size(c), c) != 0) {
156 cpuset_destroy (c);
157 eprintf ("Failed to set cpu affinity\n");
158 return false;
159 }
160
161 cpuset_destroy (c);
162 #elif __APPLE__
163 thread_affinity_policy_data_t c = {cpuid};
164 if (thread_policy_set (pthread_mach_thread_np (th->tid),
165 THREAD_AFFINITY_POLICY, (thread_policy_t)&c, 1) != KERN_SUCCESS) {
166 eprintf ("Failed to set cpu affinity\n");
167 return false;
168 }
169 #elif __WINDOWS__
170 if (SetThreadAffinityMask (th->tid, (DWORD_PTR)1 << cpuid) == 0) {
171 eprintf ("Failed to set cpu affinity\n");
172 return false;
173 }
174 #elif __sun
175 psetid_t c;
176
177 pset_create (&c);
178 pset_assign (c, cpuid, NULL);
179
180 if (pset_bind (c, P_PID, getpid (), NULL)) {
181 pset_destroy (c);
182 eprintf ("Failed to set cpu affinity\n");
183 return false;
184 }
185
186 pset_destroy (c);
187 #else
188 #pragma message("warning r_th_setaffinity not implemented")
189 #endif
190 return true;
191 }
192
193 R_API RThread *r_th_new(R_TH_FUNCTION(fun), void *user, int delay) {
194 RThread *th = R_NEW0 (RThread);
195 if (th) {
196 th->lock = r_th_lock_new (false);
197 th->running = false;
198 th->fun = fun;
199 th->user = user;
200 th->delay = delay;
201 th->breaked = false;
202 th->ready = false;
203 #if HAVE_PTHREAD
204 pthread_create (&th->tid, NULL, _r_th_launcher, th);
205 #elif __WINDOWS__
206 th->tid = CreateThread (NULL, 0, _r_th_launcher, th, 0, 0);
207 #endif
208 }
209 return th;
210 }
211
212 R_API void r_th_break(RThread *th) {
213 th->breaked = true;
214 }
215
216 R_API bool r_th_kill(RThread *th, bool force) {
217 if (!th || !th->tid) {
218 return false;
219 }
220 th->breaked = true;
221 r_th_break (th);
222 r_th_wait (th);
223 #if HAVE_PTHREAD
224 #ifdef __ANDROID__
225 pthread_kill (th->tid, 9);
226 #else
227 pthread_cancel (th->tid);
228 #endif
229 #elif __WINDOWS__
230 TerminateThread (th->tid, -1);
231 #endif
232 return 0;
233 }
234
235 R_API bool r_th_start(RThread *th, int enable) {
236 bool ret = true;
237 if (enable) {
238 if (!th->running) {
239 // start thread
240 while (!th->ready) {
241 /* spinlock */
242 }
243 r_th_lock_leave (th->lock);
244 }
245 } else {
246 if (th->running) {
247 // stop thread
248 //r_th_kill (th, 0);
249 r_th_lock_enter (th->lock); // deadlock?
250 }
251 }
252 th->running = enable;
253 return ret;
254 }
255
256 R_API int r_th_wait(struct r_th_t *th) {
257 int ret = false;
258 if (th) {
259 #if HAVE_PTHREAD
260 void *thret;
261 ret = pthread_join (th->tid, &thret);
262 #elif __WINDOWS__
263 ret = WaitForSingleObject (th->tid, INFINITE);
264 #endif
265 th->running = false;
266 }
267 return ret;
268 }
269
270 R_API int r_th_wait_async(struct r_th_t *th) {
271 return th->running;
272 }
273
274 R_API void *r_th_free(struct r_th_t *th) {
275 if (!th) {
276 return NULL;
277 }
278 #if __WINDOWS__
279 CloseHandle (th->tid);
280 #endif
281 r_th_lock_free (th->lock);
282 free (th);
283 return NULL;
284 }
285
286 R_API void *r_th_kill_free(struct r_th_t *th) {
287 if (!th) {
288 return NULL;
289 }
290 r_th_kill (th, true);
291 r_th_free (th);
292 return NULL;
293 }
294
295 #if 0
296
297 // Thread Pipes
298 typedef struct r_th_pipe_t {
299 RList *msglist;
300 RThread *th;
301 //RThreadLock *lock;
302 } RThreadPipe;
303
304 r_th_pipe_new();
305
306 #endif
307
308