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