xref: /haiku/src/system/libroot/posix/pthread/pthread.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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