Rizin
unix-like reverse engineering framework and cli tools
thread.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2020-2021 ret2libc <sirmy15@gmail.com>
2 // SPDX-FileCopyrightText: 2020-2022 deroad <wargio@libero.it>
3 // SPDX-FileCopyrightText: 2022 GustavoLCR <gugulcr@gmail.com>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 #include <rz_util.h>
7 #include "thread.h"
8 
9 /*
10  * Main thread function, this function is meant to be
11  * hidden from the user which is using the C APIs.
12  */
13 static RZ_TH_RET_T thread_main_function(void *_th) {
14 #if HAVE_PTHREAD
15 #ifndef __ANDROID__
16  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
17  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
18 #endif
19 #endif
20  RzThread *th = (RzThread *)_th;
21  th->retv = th->function(th->user);
22  return NULL;
23 }
24 
25 RZ_IPI RZ_TH_TID rz_th_self(void) {
26 #if HAVE_PTHREAD
27  return pthread_self();
28 #elif __WINDOWS__
29  return GetCurrentThread();
30 #else
31 #pragma message("Not implemented on this platform")
32  return (RZ_TH_TID)-1;
33 #endif
34 }
35 
45  rz_return_val_if_fail(th && name, false);
46 
47 #if defined(HAVE_PTHREAD_NP) && HAVE_PTHREAD_NP
48 #if __linux__ || __sun
49  if (pthread_setname_np(th->tid, name) != 0) {
50  RZ_LOG_ERROR("thread: Failed to set thread name\n");
51  return false;
52  }
53 #elif __APPLE__ && defined(MAC_OS_X_VERSION_10_6)
54  if (pthread_setname_np(name) != 0) {
55  RZ_LOG_ERROR("thread: Failed to set thread name\n");
56  return false;
57  }
58 #elif __FreeBSD__ || __OpenBSD__ || __DragonFly__ || __sun
59  pthread_set_name_np(th->tid, name);
60 #elif __NetBSD__
61  if (pthread_setname_np(th->tid, "%s", (void *)name) != 0) {
62  RZ_LOG_ERROR("thread: Failed to set thread name\n");
63  return false;
64  }
65 #elif __HAIKU__
66  if (rename_thread((thread_id)th->tid, name) != B_OK) {
67  RZ_LOG_ERROR("thread: Failed to set thread name\n");
68  return false;
69  }
70 #else
71 #pragma message("warning rz_th_setname not implemented")
72 #endif
73 #endif
74  return true;
75 }
76 
87  rz_return_val_if_fail(th && name && len > 0, false);
88 
89 #if defined(HAVE_PTHREAD_NP) && HAVE_PTHREAD_NP
90 #if __linux__ || __NetBSD__ || (__APPLE__ && defined(MAC_OS_X_VERSION_10_6)) || __sun
91  if (pthread_getname_np(th->tid, name, len) != 0) {
92  RZ_LOG_ERROR("thread: Failed to get thread name\n");
93  return false;
94  }
95 #elif (__FreeBSD__ && __FreeBSD_version >= 1200000) || __DragonFly__ || (__OpenBSD__ && OpenBSD >= 201905)
96  pthread_get_name_np(th->tid, name, len);
97 #elif defined(__HAIKU__)
98  thread_info ti;
99  size_t flen = len < B_OS_NAME_LENGTH ? len : B_OS_NAME_LENGTH;
100 
101  if (get_thread_info((thread_id)th->tid, &ti) != B_OK) {
102  RZ_LOG_ERROR("thread: Failed to get thread name\n");
103  return false;
104  }
105 
106  rz_str_ncpy(name, ti.name, flen);
107 #else
108 #pragma message("warning rz_th_getname not implemented")
109 #endif
110 #endif
111  return true;
112 }
113 
123  rz_return_val_if_fail(th, false);
124 
125 #if __linux__
126 #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)
127  // Old versions of GNU libc don't have this feature
128 #pragma message("warning rz_th_setaffinity not implemented")
129 #else
130  cpu_set_t c;
131  CPU_ZERO(&c);
132  CPU_SET(cpuid, &c);
133 
134  if (sched_setaffinity((pid_t)(ut64)th->tid, sizeof(c), &c) != 0) {
135  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
136  return false;
137  }
138 #endif
139 #elif __FreeBSD__ || __DragonFly__
140  cpuset_t c;
141  CPU_ZERO(&c);
142  CPU_SET(cpuid, &c);
143 
144  if (pthread_setaffinity_np(th->tid, sizeof(c), &c) != 0) {
145  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
146  return false;
147  }
148 #elif __NetBSD__
149  cpuset_t *c;
150  c = cpuset_create();
151 
152  if (pthread_setaffinity_np(th->tid, cpuset_size(c), c) != 0) {
153  cpuset_destroy(c);
154  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
155  return false;
156  }
157 
158  cpuset_destroy(c);
159 #elif __APPLE__
160  thread_affinity_policy_data_t c = { cpuid };
161  if (thread_policy_set(pthread_mach_thread_np(th->tid),
162  THREAD_AFFINITY_POLICY, (thread_policy_t)&c, 1) != KERN_SUCCESS) {
163  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
164  return false;
165  }
166 #elif __WINDOWS__
167  if (SetThreadAffinityMask(th->tid, (DWORD_PTR)1 << cpuid) == 0) {
168  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
169  return false;
170  }
171 #elif __sun
172  psetid_t c;
173 
174  pset_create(&c);
175  pset_assign(c, cpuid, NULL);
176 
177  if (pset_bind(c, P_PID, getpid(), NULL)) {
178  pset_destroy(c);
179  RZ_LOG_ERROR("thread: Failed to set cpu affinity\n");
180  return false;
181  }
182 
183  pset_destroy(c);
184 #else
185 #pragma message("warning rz_th_setaffinity not implemented")
186 #endif
187  return true;
188 }
189 
199  rz_return_val_if_fail(function, NULL);
200 
201  RzThread *th = RZ_NEW0(RzThread);
202  if (!th) {
203  RZ_LOG_ERROR("thread: Failed to allocate RzThread\n");
204  return NULL;
205  }
206 
207  th->function = function;
208  th->user = user;
209 
210 #if HAVE_PTHREAD
211  if (!pthread_create(&th->tid, NULL, thread_main_function, th)) {
212  return th;
213  }
214 #elif __WINDOWS__
215  if ((th->tid = CreateThread(NULL, 0, thread_main_function, th, 0, 0))) {
216  return th;
217  }
218 #endif
219  RZ_LOG_ERROR("thread: Failed to start the RzThread\n");
220  free(th);
221  return NULL;
222 }
223 
232  rz_return_val_if_fail(th, false);
233 #if HAVE_PTHREAD
234  void *thret = NULL;
235  return pthread_join(th->tid, &thret) == 0;
236 #elif __WINDOWS__
237  return WaitForSingleObject(th->tid, INFINITE) == 0; // WAIT_OBJECT_0
238 #endif
239 }
240 
247  if (!th) {
248  return;
249  }
250 #if __WINDOWS__
251  CloseHandle(th->tid);
252 #endif
253  free(th);
254 }
255 
265  return th->user;
266 }
267 
277  return th->retv;
278 }
279 
285 RZ_API bool rz_th_yield(void) {
286 #if __WINDOWS__
287  return SwitchToThread() != 0;
288 #else
289  // sched_yield is not available everywhere.
290  // usleep is more portable.
291  rz_sys_usleep(1);
292  return true;
293 #endif
294 }
size_t len
Definition: 6502dis.c:15
#define RZ_IPI
Definition: analysis_wasm.c:11
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
static RZ_TH_RET_T thread_main_function(void *_th)
Definition: thread.c:13
RZ_API void rz_th_free(RZ_NULLABLE RzThread *th)
Frees a RzThread structure.
Definition: thread.c:246
RZ_API RZ_OWN void * rz_th_get_user(RZ_NONNULL RzThread *th)
Returns user pointer of thread.
Definition: thread.c:263
RZ_API bool rz_th_yield(void)
Yield the processor.
Definition: thread.c:285
RZ_API bool rz_th_set_affinity(RZ_NONNULL RzThread *th, int cpuid)
Sets the thread cpu affinity.
Definition: thread.c:122
RZ_API bool rz_th_get_name(RZ_NONNULL RzThread *th, RZ_NONNULL RZ_OUT char *name, size_t len)
Gets the name of the thread and writes it into the output buffer.
Definition: thread.c:86
RZ_API RZ_OWN RzThread * rz_th_new(RZ_NONNULL RzThreadFunction function, RZ_NULLABLE void *user)
Creates and starts a new thread.
Definition: thread.c:198
RZ_API RZ_OWN void * rz_th_get_retv(RZ_NONNULL RzThread *th)
Returns return value of the thread.
Definition: thread.c:275
RZ_API bool rz_th_wait(RZ_NONNULL RzThread *th)
Awaits indefinetely for a thread to join.
Definition: thread.c:231
RZ_IPI RZ_TH_TID rz_th_self(void)
Definition: thread.c:25
RZ_API bool rz_th_set_name(RZ_NONNULL RzThread *th, RZ_NONNULL const char *name)
Sets the name of the thread.
Definition: thread.c:44
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
RZ_API int rz_sys_usleep(int usecs)
Sleep for usecs microseconds.
Definition: sys.c:317
void *(* RzThreadFunction)(void *user)
Definition: rz_th.h:28
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_OUT
Definition: rz_types.h:51
#define RZ_NONNULL
Definition: rz_types.h:64
int pid_t
Definition: sftypes.h:38
#define c(i)
Definition: sha256.c:43
Definition: z80asm.h:102
char name[1]
Definition: z80asm.h:104
Definition: thread.h:84
void * retv
Thread return value.
Definition: thread.h:88
RZ_TH_TID tid
Thread identifier.
Definition: thread.h:85
void * user
User defined thread data to pass (can be NULL).
Definition: thread.h:87
RzThreadFunction function
User defined thread function.
Definition: thread.h:86
ut64(WINAPI *w32_GetEnabledXStateFeatures)()