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 }; 32 33 34 static pthread_thread sMainThread; 35 static int sConcurrencyLevel; 36 37 38 static status_t 39 pthread_thread_entry(void*, void* _thread) 40 { 41 pthread_thread* thread = (pthread_thread*)_thread; 42 43 __heap_thread_init(); 44 45 pthread_exit(thread->entry(thread->entry_argument)); 46 return 0; 47 } 48 49 50 // #pragma mark - private API 51 52 53 void 54 __pthread_destroy_thread(void) 55 { 56 pthread_thread* thread = pthread_self(); 57 58 // call cleanup handlers 59 while (true) { 60 struct __pthread_cleanup_handler* handler 61 = __pthread_cleanup_pop_handler(); 62 if (handler == NULL) 63 break; 64 65 handler->function(handler->argument); 66 } 67 68 __pthread_key_call_destructors(thread); 69 70 if ((atomic_or(&thread->flags, THREAD_DEAD) & THREAD_DETACHED) != 0) 71 free(thread); 72 } 73 74 75 pthread_thread* 76 __allocate_pthread(void* (*entry)(void*), void *data) 77 { 78 pthread_thread* thread = (pthread_thread*)malloc(sizeof(pthread_thread)); 79 if (thread == NULL) 80 return NULL; 81 82 __init_pthread(thread, entry, data); 83 84 return thread; 85 } 86 87 88 void 89 __init_pthread(pthread_thread* thread, void* (*entry)(void*), void* data) 90 { 91 thread->entry = entry; 92 thread->entry_argument = data; 93 thread->exit_value = NULL; 94 thread->cleanup_handlers = NULL; 95 thread->flags = THREAD_CANCEL_ENABLED; 96 // thread cancellation enabled, but deferred 97 98 memset(thread->specific, 0, sizeof(thread->specific)); 99 } 100 101 102 status_t 103 __pthread_init_creation_attributes(const pthread_attr_t* pthreadAttributes, 104 pthread_t thread, status_t (*entryFunction)(void*, void*), 105 void* argument1, void* argument2, const char* name, 106 thread_creation_attributes* attributes) 107 { 108 const pthread_attr* attr = NULL; 109 if (pthreadAttributes == NULL) { 110 attr = &pthread_attr_default; 111 } else { 112 attr = *pthreadAttributes; 113 if (attr == NULL) 114 return EINVAL; 115 } 116 117 attributes->entry = entryFunction; 118 attributes->name = name; 119 attributes->priority = attr->sched_priority; 120 attributes->args1 = argument1; 121 attributes->args2 = argument2; 122 attributes->stack_address = NULL; 123 attributes->stack_size = attr->stack_size; 124 attributes->guard_size = attr->guard_size; 125 attributes->pthread = thread; 126 attributes->flags = 0; 127 128 if (thread != NULL && attr->detach_state == PTHREAD_CREATE_DETACHED) 129 thread->flags |= THREAD_DETACHED; 130 131 return B_OK; 132 } 133 134 135 void 136 __pthread_set_default_priority(int32 priority) 137 { 138 pthread_attr_default.sched_priority = priority; 139 } 140 141 142 // #pragma mark - public API 143 144 145 int 146 pthread_create(pthread_t* _thread, const pthread_attr_t* attr, 147 void* (*startRoutine)(void*), void* arg) 148 { 149 if (_thread == NULL) 150 return EINVAL; 151 152 pthread_thread* thread = __allocate_pthread(startRoutine, arg); 153 if (thread == NULL) 154 return EAGAIN; 155 156 thread_creation_attributes attributes; 157 status_t error = __pthread_init_creation_attributes(attr, thread, 158 &pthread_thread_entry, NULL, thread, "pthread func", &attributes); 159 if (error != B_OK) { 160 free(thread); 161 return error; 162 } 163 164 thread->id = _kern_spawn_thread(&attributes); 165 if (thread->id < 0) { 166 // stupid error code but demanded by POSIX 167 free(thread); 168 return EAGAIN; 169 } 170 171 __set_stack_protection(); 172 *_thread = thread; 173 resume_thread(thread->id); 174 175 return 0; 176 } 177 178 179 pthread_t 180 pthread_self(void) 181 { 182 pthread_thread* thread = get_user_thread()->pthread; 183 if (thread == NULL) 184 return &sMainThread; 185 186 return thread; 187 } 188 189 190 int 191 pthread_equal(pthread_t t1, pthread_t t2) 192 { 193 return t1 == t2; 194 } 195 196 197 int 198 pthread_join(pthread_t thread, void** _value) 199 { 200 status_t dummy; 201 status_t error; 202 do { 203 error = wait_for_thread(thread->id, &dummy); 204 } while (error == B_INTERRUPTED); 205 206 if (error == B_BAD_THREAD_ID) 207 RETURN_AND_TEST_CANCEL(ESRCH); 208 209 if (_value != NULL) 210 *_value = thread->exit_value; 211 212 if ((atomic_or(&thread->flags, THREAD_DETACHED) & THREAD_DEAD) != 0) 213 free(thread); 214 215 RETURN_AND_TEST_CANCEL(error); 216 } 217 218 219 void 220 pthread_exit(void* value) 221 { 222 pthread_self()->exit_value = value; 223 exit_thread(B_OK); 224 } 225 226 227 int 228 pthread_kill(pthread_t thread, int sig) 229 { 230 status_t status = send_signal(thread->id, (uint)sig); 231 if (status != B_OK) { 232 if (status == B_BAD_THREAD_ID) 233 return ESRCH; 234 235 return status; 236 } 237 238 return 0; 239 } 240 241 242 int 243 pthread_detach(pthread_t thread) 244 { 245 int32 flags; 246 247 if (thread == NULL) 248 return EINVAL; 249 250 flags = atomic_or(&thread->flags, THREAD_DETACHED); 251 if ((flags & THREAD_DETACHED) != 0) 252 return 0; 253 254 if ((flags & THREAD_DEAD) != 0) 255 free(thread); 256 257 return 0; 258 } 259 260 261 int 262 pthread_getconcurrency(void) 263 { 264 return sConcurrencyLevel; 265 } 266 267 268 int 269 pthread_setconcurrency(int newLevel) 270 { 271 if (newLevel < 0) 272 return EINVAL; 273 274 sConcurrencyLevel = newLevel; 275 return 0; 276 } 277 278 279 int 280 pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) 281 { 282 thread_info info; 283 status_t status = _kern_get_thread_info(thread->id, &info); 284 if (status == B_BAD_THREAD_ID) 285 return ESRCH; 286 param->sched_priority = info.priority; 287 if (policy != NULL) 288 *policy = SCHED_RR; 289 return 0; 290 } 291 292 293 int 294 pthread_setschedparam(pthread_t thread, int policy, 295 const struct sched_param *param) 296 { 297 status_t status; 298 if (policy != SCHED_RR) 299 return ENOTSUP; 300 status = _kern_set_thread_priority(thread->id, param->sched_priority); 301 if (status == B_BAD_THREAD_ID) 302 return ESRCH; 303 if (status < B_OK) 304 return status; 305 return 0; 306 } 307 308 309 // #pragma mark - Haiku thread API bridge 310 311 312 thread_id 313 get_pthread_thread_id(pthread_t thread) 314 { 315 return thread->id; 316 } 317