1 /* 2 * Copyright 2024, Haiku, Inc. All rights reserved. 3 * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. 4 * Copyright 2006, Jérôme Duval. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "pthread_private.h" 10 11 #include <signal.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <TLS.h> 16 17 #include <syscall_utils.h> 18 19 #include <libroot_private.h> 20 #include <syscalls.h> 21 #include <thread_defs.h> 22 #include <time_private.h> 23 #include <tls.h> 24 25 #include <user_thread.h> 26 27 28 static pthread_attr pthread_attr_default = { 29 PTHREAD_CREATE_JOINABLE, 30 B_NORMAL_PRIORITY, 31 USER_STACK_SIZE, 32 USER_STACK_GUARD_SIZE, 33 NULL 34 }; 35 36 37 static pthread_thread sMainThread; 38 static int sConcurrencyLevel; 39 40 41 static status_t 42 pthread_thread_entry(void*, void* _thread) 43 { 44 pthread_thread* thread = (pthread_thread*)_thread; 45 46 __heap_thread_init(); 47 48 pthread_exit(thread->entry(thread->entry_argument)); 49 return 0; 50 } 51 52 53 // #pragma mark - private API 54 55 56 void 57 __pthread_destroy_thread(void) 58 { 59 pthread_thread* thread = pthread_self(); 60 61 // call cleanup handlers 62 while (true) { 63 struct __pthread_cleanup_handler* handler 64 = __pthread_cleanup_pop_handler(); 65 if (handler == NULL) 66 break; 67 68 handler->function(handler->argument); 69 } 70 71 __pthread_key_call_destructors(thread); 72 73 if ((atomic_or(&thread->flags, THREAD_DEAD) & THREAD_DETACHED) != 0) 74 free(thread); 75 } 76 77 78 pthread_thread* 79 __allocate_pthread(void* (*entry)(void*), void *data) 80 { 81 pthread_thread* thread = (pthread_thread*)malloc(sizeof(pthread_thread)); 82 if (thread == NULL) 83 return NULL; 84 85 __init_pthread(thread, entry, data); 86 87 return thread; 88 } 89 90 91 void 92 __init_pthread(pthread_thread* thread, void* (*entry)(void*), void* data) 93 { 94 thread->entry = entry; 95 thread->entry_argument = data; 96 thread->exit_value = NULL; 97 thread->cleanup_handlers = NULL; 98 thread->flags = THREAD_CANCEL_ENABLED; 99 // thread cancellation enabled, but deferred 100 101 memset(thread->specific, 0, sizeof(thread->specific)); 102 } 103 104 105 status_t 106 __pthread_init_creation_attributes(const pthread_attr_t* pthreadAttributes, 107 pthread_t thread, status_t (*entryFunction)(void*, void*), 108 void* argument1, void* argument2, const char* name, 109 thread_creation_attributes* attributes) 110 { 111 const pthread_attr* attr = NULL; 112 if (pthreadAttributes == NULL) { 113 attr = &pthread_attr_default; 114 } else { 115 attr = *pthreadAttributes; 116 if (attr == NULL) 117 return EINVAL; 118 } 119 120 attributes->entry = entryFunction; 121 attributes->name = name; 122 attributes->priority = attr->sched_priority; 123 attributes->args1 = argument1; 124 attributes->args2 = argument2; 125 attributes->stack_address = attr->stack_address; 126 attributes->stack_size = attr->stack_size; 127 attributes->guard_size = attr->guard_size; 128 attributes->pthread = thread; 129 attributes->flags = 0; 130 131 if (thread != NULL && attr->detach_state == PTHREAD_CREATE_DETACHED) 132 thread->flags |= THREAD_DETACHED; 133 134 return B_OK; 135 } 136 137 138 void 139 __pthread_set_default_priority(int32 priority) 140 { 141 pthread_attr_default.sched_priority = priority; 142 } 143 144 145 static int 146 __pthread_join(pthread_t thread, void** _value, int flags = 0, bigtime_t timeout = 0) 147 { 148 status_t status; 149 do { 150 status_t dummy; 151 status = wait_for_thread_etc(thread->id, flags, timeout, &dummy); 152 } while (status == B_INTERRUPTED); 153 154 if (status == B_BAD_THREAD_ID) 155 RETURN_AND_TEST_CANCEL(ESRCH); 156 if (status == B_WOULD_BLOCK || status == B_TIMED_OUT) 157 RETURN_AND_TEST_CANCEL(ETIMEDOUT); 158 if (status < B_OK) 159 RETURN_AND_TEST_CANCEL(status); 160 161 if (_value != NULL) 162 *_value = thread->exit_value; 163 164 if ((atomic_or(&thread->flags, THREAD_DETACHED) & THREAD_DEAD) != 0) 165 free(thread); 166 167 RETURN_AND_TEST_CANCEL(B_OK); 168 } 169 170 171 // #pragma mark - public API 172 173 174 int 175 pthread_create(pthread_t* _thread, const pthread_attr_t* attr, 176 void* (*startRoutine)(void*), void* arg) 177 { 178 if (_thread == NULL) 179 return EINVAL; 180 181 pthread_thread* thread = __allocate_pthread(startRoutine, arg); 182 if (thread == NULL) 183 return EAGAIN; 184 185 thread_creation_attributes attributes; 186 status_t error = __pthread_init_creation_attributes(attr, thread, 187 &pthread_thread_entry, NULL, thread, "pthread func", &attributes); 188 if (error != B_OK) { 189 free(thread); 190 return error; 191 } 192 193 thread->id = _kern_spawn_thread(&attributes); 194 if (thread->id < 0) { 195 // stupid error code but demanded by POSIX 196 free(thread); 197 return EAGAIN; 198 } 199 200 __set_stack_protection(); 201 *_thread = thread; 202 resume_thread(thread->id); 203 204 return 0; 205 } 206 207 208 pthread_t 209 pthread_self(void) 210 { 211 pthread_thread* thread = get_user_thread()->pthread; 212 if (thread == NULL) 213 return &sMainThread; 214 215 return thread; 216 } 217 218 219 int 220 pthread_equal(pthread_t t1, pthread_t t2) 221 { 222 return t1 == t2; 223 } 224 225 226 int 227 pthread_join(pthread_t thread, void** _value) 228 { 229 return __pthread_join(thread, _value); 230 } 231 232 233 void 234 pthread_exit(void* value) 235 { 236 pthread_self()->exit_value = value; 237 exit_thread(B_OK); 238 } 239 240 241 int 242 pthread_kill(pthread_t thread, int sig) 243 { 244 status_t status = send_signal(thread->id, (uint)sig); 245 if (status != B_OK) { 246 if (status == B_BAD_THREAD_ID) 247 return ESRCH; 248 249 return status; 250 } 251 252 return 0; 253 } 254 255 256 int 257 pthread_detach(pthread_t thread) 258 { 259 int32 flags; 260 261 if (thread == NULL) 262 return EINVAL; 263 264 flags = atomic_or(&thread->flags, THREAD_DETACHED); 265 if ((flags & THREAD_DETACHED) != 0) 266 return 0; 267 268 if ((flags & THREAD_DEAD) != 0) 269 free(thread); 270 271 return 0; 272 } 273 274 275 int 276 pthread_getconcurrency(void) 277 { 278 return sConcurrencyLevel; 279 } 280 281 282 int 283 pthread_setconcurrency(int newLevel) 284 { 285 if (newLevel < 0) 286 return EINVAL; 287 288 sConcurrencyLevel = newLevel; 289 return 0; 290 } 291 292 293 int 294 pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) 295 { 296 thread_info info; 297 status_t status = _kern_get_thread_info(thread->id, &info); 298 if (status == B_BAD_THREAD_ID) 299 return ESRCH; 300 param->sched_priority = info.priority; 301 if (policy != NULL) { 302 if (info.priority >= B_FIRST_REAL_TIME_PRIORITY) 303 *policy = SCHED_RR; 304 else 305 *policy = SCHED_OTHER; 306 } 307 return 0; 308 } 309 310 311 int 312 pthread_setschedparam(pthread_t thread, int policy, 313 const struct sched_param *param) 314 { 315 if (policy != SCHED_RR && policy != SCHED_OTHER) 316 return ENOTSUP; 317 if (policy == SCHED_RR && param->sched_priority < B_FIRST_REAL_TIME_PRIORITY) 318 return EINVAL; 319 if (policy == SCHED_OTHER && param->sched_priority >= B_FIRST_REAL_TIME_PRIORITY) 320 return EINVAL; 321 322 status_t status = _kern_set_thread_priority(thread->id, param->sched_priority); 323 if (status == B_BAD_THREAD_ID) 324 return ESRCH; 325 if (status < B_OK) 326 return status; 327 return 0; 328 } 329 330 331 // #pragma mark - extensions 332 333 334 extern "C" int 335 pthread_getname_np(pthread_t thread, char* buffer, size_t length) 336 { 337 thread_info info; 338 status_t status = _kern_get_thread_info(thread->id, &info); 339 if (status == B_BAD_THREAD_ID) 340 return ESRCH; 341 if (status < B_OK) 342 return status; 343 if (strlcpy(buffer, info.name, length) >= length) 344 return ERANGE; 345 return 0; 346 } 347 348 349 extern "C" int 350 pthread_setname_np(pthread_t thread, const char* name) 351 { 352 status_t status = _kern_rename_thread(thread->id, name); 353 if (status == B_BAD_THREAD_ID) 354 return ESRCH; 355 if (status < B_OK) 356 return status; 357 return 0; 358 } 359 360 361 extern "C" int 362 pthread_timedjoin_np(pthread_t thread, void** _value, const struct timespec* abstime) 363 { 364 int flags = 0; 365 bigtime_t timeout = 0; 366 if (abstime != NULL) { 367 if (!timespec_to_bigtime(*abstime, timeout)) 368 RETURN_AND_TEST_CANCEL(EINVAL); 369 flags |= B_ABSOLUTE_REAL_TIME_TIMEOUT; 370 } else { 371 timeout = 0; 372 flags |= B_RELATIVE_TIMEOUT; 373 } 374 375 return __pthread_join(thread, _value, flags, timeout); 376 } 377 378 379 // #pragma mark - Haiku thread API bridge 380 381 382 thread_id 383 get_pthread_thread_id(pthread_t thread) 384 { 385 return thread->id; 386 } 387