headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / pthread / pthread.cpp
blobcb7b5f2547853d47334f2c8df3aada6abcee87a1
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 */
8 #include "pthread_private.h"
10 #include <signal.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <TLS.h>
16 #include <syscall_utils.h>
18 #include <libroot_private.h>
19 #include <syscalls.h>
20 #include <thread_defs.h>
21 #include <tls.h>
23 #include <user_thread.h>
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
34 static pthread_thread sMainThread;
35 static int sConcurrencyLevel;
38 static status_t
39 pthread_thread_entry(void*, void* _thread)
41 pthread_thread* thread = (pthread_thread*)_thread;
43 pthread_exit(thread->entry(thread->entry_argument));
44 return 0;
48 // #pragma mark - private API
51 void
52 __pthread_destroy_thread(void)
54 pthread_thread* thread = pthread_self();
56 // call cleanup handlers
57 while (true) {
58 struct __pthread_cleanup_handler* handler
59 = __pthread_cleanup_pop_handler();
60 if (handler == NULL)
61 break;
63 handler->function(handler->argument);
66 __pthread_key_call_destructors(thread);
68 if ((atomic_or(&thread->flags, THREAD_DEAD) & THREAD_DETACHED) != 0)
69 free(thread);
73 pthread_thread*
74 __allocate_pthread(void* (*entry)(void*), void *data)
76 pthread_thread* thread = (pthread_thread*)malloc(sizeof(pthread_thread));
77 if (thread == NULL)
78 return NULL;
80 __init_pthread(thread, entry, data);
82 return thread;
86 void
87 __init_pthread(pthread_thread* thread, void* (*entry)(void*), void* data)
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
96 memset(thread->specific, 0, sizeof(thread->specific));
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)
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;
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;
126 if (thread != NULL && attr->detach_state == PTHREAD_CREATE_DETACHED)
127 thread->flags |= THREAD_DETACHED;
129 return B_OK;
133 // #pragma mark - public API
137 pthread_create(pthread_t* _thread, const pthread_attr_t* attr,
138 void* (*startRoutine)(void*), void* arg)
140 if (_thread == NULL)
141 return EINVAL;
143 pthread_thread* thread = __allocate_pthread(startRoutine, arg);
144 if (thread == NULL)
145 return EAGAIN;
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;
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;
162 __set_stack_protection();
163 resume_thread(thread->id);
164 *_thread = thread;
166 return 0;
170 pthread_t
171 pthread_self(void)
173 pthread_thread* thread = get_user_thread()->pthread;
174 if (thread == NULL)
175 return &sMainThread;
177 return thread;
182 pthread_equal(pthread_t t1, pthread_t t2)
184 return t1 == t2;
189 pthread_join(pthread_t thread, void** _value)
191 status_t dummy;
192 status_t error;
193 do {
194 error = wait_for_thread(thread->id, &dummy);
195 } while (error == B_INTERRUPTED);
197 if (error == B_BAD_THREAD_ID)
198 RETURN_AND_TEST_CANCEL(ESRCH);
200 if (_value != NULL)
201 *_value = thread->exit_value;
203 if ((atomic_or(&thread->flags, THREAD_DETACHED) & THREAD_DEAD) != 0)
204 free(thread);
206 RETURN_AND_TEST_CANCEL(error);
210 void
211 pthread_exit(void* value)
213 pthread_self()->exit_value = value;
214 exit_thread(B_OK);
219 pthread_kill(pthread_t thread, int sig)
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;
226 return status;
229 return 0;
234 pthread_detach(pthread_t thread)
236 int32 flags;
238 if (thread == NULL)
239 return EINVAL;
241 flags = atomic_or(&thread->flags, THREAD_DETACHED);
242 if ((flags & THREAD_DETACHED) != 0)
243 return 0;
245 if ((flags & THREAD_DEAD) != 0)
246 free(thread);
248 return 0;
253 pthread_getconcurrency(void)
255 return sConcurrencyLevel;
260 pthread_setconcurrency(int newLevel)
262 if (newLevel < 0)
263 return EINVAL;
265 sConcurrencyLevel = newLevel;
266 return 0;
271 pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
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;
285 pthread_setschedparam(pthread_t thread, int policy,
286 const struct sched_param *param)
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;
300 // #pragma mark - Haiku thread API bridge
303 thread_id
304 get_pthread_thread_id(pthread_t thread)
306 return thread->id;