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