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