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