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