10865e4b2SAxel Dörfler/*
2ecf6b86cSAxel Dörfler * Copyright 2002-2009, Axel D��rfler, axeld@pinc-software.de.
32f9720f0SAxel Dörfler * Distributed under the terms of the MIT License.
42f9720f0SAxel Dörfler */
5712ec3d7SAxel Dörfler
6712ec3d7SAxel Dörfler
7712ec3d7SAxel Dörfler#include <OS.h>
88120de45SAxel Dörfler
98120de45SAxel Dörfler#include <stdlib.h>
10712ec3d7SAxel Dörfler#include <stdio.h>
11712ec3d7SAxel Dörfler
126b202f4eSIngo Weinhold#include <libroot_private.h>
13ecf6b86cSAxel Dörfler#include <pthread_private.h>
1444c0c4d3SPawel Dziepak#include <runtime_loader.h>
156b202f4eSIngo Weinhold#include <thread_defs.h>
166b202f4eSIngo Weinhold#include <tls.h>
176b202f4eSIngo Weinhold#include <syscalls.h>
18712ec3d7SAxel Dörfler
19712ec3d7SAxel Dörfler
208120de45SAxel Dörfler#undef thread_entry
218120de45SAxel Dörfler	// thread_entry is still defined in OS.h for compatibility reasons
228120de45SAxel Dörfler
238120de45SAxel Dörfler
248120de45SAxel Dörflertypedef struct callback_node {
258120de45SAxel Dörfler	struct callback_node *next;
268120de45SAxel Dörfler	void (*function)(void *);
278120de45SAxel Dörfler	void *argument;
288120de45SAxel Dörfler} callback_node;
298120de45SAxel Dörfler
308120de45SAxel Dörfler
31a4248cf5SJérôme Duvalvoid _thread_do_exit_work(void);
32ceee0a32SFrançois Revolvoid _thread_do_exit_notification(void);
338120de45SAxel Dörfler
348120de45SAxel Dörfler
35ecf6b86cSAxel Dörflerstatic status_t
3624df6592SIngo Weinholdthread_entry(void* _entry, void* _thread)
378120de45SAxel Dörfler{
3824df6592SIngo Weinhold	thread_func entry = (thread_func)_entry;
39ecf6b86cSAxel Dörfler	pthread_thread* thread = (pthread_thread*)_thread;
403b5e6232SAugustin Cavalier	status_t returnCode;
41ecf6b86cSAxel Dörfler
42e4103b1bSMichael Lotz	__heap_thread_init();
43e4103b1bSMichael Lotz
443b5e6232SAugustin Cavalier	returnCode = entry(thread->entry_argument);
458120de45SAxel Dörfler
46a4248cf5SJérôme Duval	_thread_do_exit_work();
47e4103b1bSMichael Lotz	__heap_thread_exit();
488120de45SAxel Dörfler
498120de45SAxel Dörfler	return returnCode;
508120de45SAxel Dörfler}
518120de45SAxel Dörfler
528120de45SAxel Dörfler
53ecf6b86cSAxel Dörflervoid
54ecf6b86cSAxel Dörfler_thread_do_exit_notification(void)
55a4248cf5SJérôme Duval{
56585a28afSJérôme Duval	// empty stub for R5 compatibility
57a4248cf5SJérôme Duval}
58a4248cf5SJérôme Duval
59a4248cf5SJérôme Duval
60a4248cf5SJérôme Duvalvoid
61a4248cf5SJérôme Duval_thread_do_exit_work(void)
62ecf6b86cSAxel Dörfler{
63ecf6b86cSAxel Dörfler	callback_node *node = tls_get(TLS_ON_EXIT_THREAD_SLOT);
64ecf6b86cSAxel Dörfler	callback_node *next;
65ecf6b86cSAxel Dörfler
66ecf6b86cSAxel Dörfler	while (node != NULL) {
67ecf6b86cSAxel Dörfler		next = node->next;
68ecf6b86cSAxel Dörfler
69ecf6b86cSAxel Dörfler		node->function(node->argument);
70ecf6b86cSAxel Dörfler		free(node);
71ecf6b86cSAxel Dörfler
72ecf6b86cSAxel Dörfler		node = next;
73ecf6b86cSAxel Dörfler	}
74ecf6b86cSAxel Dörfler
75ecf6b86cSAxel Dörfler	tls_set(TLS_ON_EXIT_THREAD_SLOT, NULL);
76ecf6b86cSAxel Dörfler
7744c0c4d3SPawel Dziepak	__gRuntimeLoader->destroy_thread_tls();
7844c0c4d3SPawel Dziepak
79ecf6b86cSAxel Dörfler	__pthread_destroy_thread();
80ecf6b86cSAxel Dörfler}
81ecf6b86cSAxel Dörfler
82ecf6b86cSAxel Dörfler
835d0a1da8SPawel Dziepakvoid
845d0a1da8SPawel Dziepak__set_stack_protection(void)
855d0a1da8SPawel Dziepak{
8607e1875eSPawel Dziepak	if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU) {
875d0a1da8SPawel Dziepak		area_info info;
885d0a1da8SPawel Dziepak		ssize_t cookie = 0;
895d0a1da8SPawel Dziepak
905d0a1da8SPawel Dziepak		while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
915d0a1da8SPawel Dziepak			if ((info.protection & B_STACK_AREA) != 0) {
925d0a1da8SPawel Dziepak				_kern_set_area_protection(info.area,
935d0a1da8SPawel Dziepak					B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA | B_STACK_AREA);
945d0a1da8SPawel Dziepak			}
955d0a1da8SPawel Dziepak		}
965d0a1da8SPawel Dziepak	}
975d0a1da8SPawel Dziepak}
985d0a1da8SPawel Dziepak
995d0a1da8SPawel Dziepak
100ecf6b86cSAxel Dörfler// #pragma mark -
101ecf6b86cSAxel Dörfler
102ecf6b86cSAxel Dörfler
103712ec3d7SAxel Dörflerthread_id
1048120de45SAxel Dörflerspawn_thread(thread_func entry, const char *name, int32 priority, void *data)
105712ec3d7SAxel Dörfler{
1064c49f205SIngo Weinhold	struct thread_creation_attributes attributes;
107ecf6b86cSAxel Dörfler	pthread_thread* thread;
10885b2f68bSPhilippe Saint-Pierre	thread_id id;
109ecf6b86cSAxel Dörfler
11024df6592SIngo Weinhold	thread = __allocate_pthread(NULL, data);
111ecf6b86cSAxel Dörfler	if (thread == NULL)
112ecf6b86cSAxel Dörfler		return B_NO_MEMORY;
1134c49f205SIngo Weinhold
1145685273fSAxel Dörfler	_single_threaded = false;
1155685273fSAxel Dörfler		// used for I/O locking - BeOS compatibility issue
1165685273fSAxel Dörfler
11724df6592SIngo Weinhold	__pthread_init_creation_attributes(NULL, thread, &thread_entry, entry,
11824df6592SIngo Weinhold		thread, name, &attributes);
1191bc85a38SJérôme Duval	thread->flags |= THREAD_DETACHED;
12024df6592SIngo Weinhold
1214c49f205SIngo Weinhold	attributes.priority = priority;
1224c49f205SIngo Weinhold
12385b2f68bSPhilippe Saint-Pierre	id = _kern_spawn_thread(&attributes);
1243a04b749SJérôme Duval	if (id < 0)
125bafa7591SJérôme Duval		free(thread);
1265d0a1da8SPawel Dziepak	else {
1273a04b749SJérôme Duval		thread->id = id;
1285d0a1da8SPawel Dziepak		__set_stack_protection();
1295d0a1da8SPawel Dziepak	}
1305d0a1da8SPawel Dziepak
1313a04b749SJérôme Duval	return id;
132712ec3d7SAxel Dörfler}
133712ec3d7SAxel Dörfler
134712ec3d7SAxel Dörfler
135712ec3d7SAxel Dörflerstatus_t
136712ec3d7SAxel Dörflerkill_thread(thread_id thread)
137712ec3d7SAxel Dörfler{
1383dbf98a5SAxel Dörfler	return _kern_kill_thread(thread);
139712ec3d7SAxel Dörfler}
140712ec3d7SAxel Dörfler
141712ec3d7SAxel Dörfler
142712ec3d7SAxel Dörflerstatus_t
143712ec3d7SAxel Dörflerresume_thread(thread_id thread)
144712ec3d7SAxel Dörfler{
1453dbf98a5SAxel Dörfler	return _kern_resume_thread(thread);
146712ec3d7SAxel Dörfler}
147712ec3d7SAxel Dörfler
148712ec3d7SAxel Dörfler
149712ec3d7SAxel Dörflerstatus_t
150712ec3d7SAxel Dörflersuspend_thread(thread_id thread)
151712ec3d7SAxel Dörfler{
1523dbf98a5SAxel Dörfler	return _kern_suspend_thread(thread);
153712ec3d7SAxel Dörfler}
154712ec3d7SAxel Dörfler
155712ec3d7SAxel Dörfler
156712ec3d7SAxel Dörflerstatus_t
157712ec3d7SAxel Dörflerrename_thread(thread_id thread, const char *name)
158712ec3d7SAxel Dörfler{
1590865e4b2SAxel Dörfler	return _kern_rename_thread(thread, name);
160712ec3d7SAxel Dörfler}
161712ec3d7SAxel Dörfler
162712ec3d7SAxel Dörfler
163712ec3d7SAxel Dörflerstatus_t
164712ec3d7SAxel Dörflerset_thread_priority(thread_id thread, int32 priority)
165712ec3d7SAxel Dörfler{
1663dbf98a5SAxel Dörfler	return _kern_set_thread_priority(thread, priority);
167712ec3d7SAxel Dörfler}
168712ec3d7SAxel Dörfler
169712ec3d7SAxel Dörfler
170712ec3d7SAxel Dörflervoid
171712ec3d7SAxel Dörflerexit_thread(status_t status)
172712ec3d7SAxel Dörfler{
17335c16bd3SAdrien Destugues	_thread_do_exit_work();
174e4103b1bSMichael Lotz	__heap_thread_exit();
1752f9720f0SAxel Dörfler	_kern_exit_thread(status);
176712ec3d7SAxel Dörfler}
177712ec3d7SAxel Dörfler
178712ec3d7SAxel Dörfler
179712ec3d7SAxel Dörflerstatus_t
1803dbf98a5SAxel Dörflerwait_for_thread(thread_id thread, status_t *_returnCode)
181712ec3d7SAxel Dörfler{
1823dbf98a5SAxel Dörfler	return _kern_wait_for_thread(thread, _returnCode);
183712ec3d7SAxel Dörfler}
184712ec3d7SAxel Dörfler
185712ec3d7SAxel Dörfler
1868120de45SAxel Dörflerstatus_t
1878120de45SAxel Dörfleron_exit_thread(void (*callback)(void *), void *data)
1888120de45SAxel Dörfler{
1898120de45SAxel Dörfler	callback_node **head = (callback_node **)tls_address(TLS_ON_EXIT_THREAD_SLOT);
1908120de45SAxel Dörfler
1918120de45SAxel Dörfler	callback_node *node = malloc(sizeof(callback_node));
1928120de45SAxel Dörfler	if (node == NULL)
1938120de45SAxel Dörfler		return B_NO_MEMORY;
1948120de45SAxel Dörfler
1958120de45SAxel Dörfler	node->function = callback;
1968120de45SAxel Dörfler	node->argument = data;
1978120de45SAxel Dörfler
1988120de45SAxel Dörfler	// add this node to the list
1998120de45SAxel Dörfler	node->next = *head;
2008120de45SAxel Dörfler	*head = node;
2018120de45SAxel Dörfler
2028120de45SAxel Dörfler	return B_OK;
203712ec3d7SAxel Dörfler}
204712ec3d7SAxel Dörfler
205712ec3d7SAxel Dörfler
206712ec3d7SAxel Dörflerstatus_t
207712ec3d7SAxel Dörfler_get_thread_info(thread_id thread, thread_info *info, size_t size)
208712ec3d7SAxel Dörfler{
2093dbf98a5SAxel Dörfler	if (info == NULL || size != sizeof(thread_info))
2103dbf98a5SAxel Dörfler		return B_BAD_VALUE;
2113dbf98a5SAxel Dörfler
2123dbf98a5SAxel Dörfler	return _kern_get_thread_info(thread, info);
213712ec3d7SAxel Dörfler}
214712ec3d7SAxel Dörfler
215712ec3d7SAxel Dörfler
216712ec3d7SAxel Dörflerstatus_t
217712ec3d7SAxel Dörfler_get_next_thread_info(team_id team, int32 *cookie, thread_info *info, size_t size)
218712ec3d7SAxel Dörfler{
2193dbf98a5SAxel Dörfler	if (info == NULL || size != sizeof(thread_info))
2203dbf98a5SAxel Dörfler		return B_BAD_VALUE;
2213dbf98a5SAxel Dörfler
2223dbf98a5SAxel Dörfler	return _kern_get_next_thread_info(team, cookie, info);
223712ec3d7SAxel Dörfler}
224712ec3d7SAxel Dörfler
225712ec3d7SAxel Dörfler
226712ec3d7SAxel Dörflerstatus_t
227712ec3d7SAxel Dörflersend_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize)
228712ec3d7SAxel Dörfler{
2293dbf98a5SAxel Dörfler	return _kern_send_data(thread, code, buffer, bufferSize);
230712ec3d7SAxel Dörfler}
231712ec3d7SAxel Dörfler
232712ec3d7SAxel Dörfler
233183dee22SAxel Dörflerint32
2343dbf98a5SAxel Dörflerreceive_data(thread_id *_sender, void *buffer, size_t bufferSize)
235712ec3d7SAxel Dörfler{
2363dbf98a5SAxel Dörfler	return _kern_receive_data(_sender, buffer, bufferSize);
237712ec3d7SAxel Dörfler}
238712ec3d7SAxel Dörfler
239712ec3d7SAxel Dörfler
240712ec3d7SAxel Dörflerbool
241712ec3d7SAxel Dörflerhas_data(thread_id thread)
242712ec3d7SAxel Dörfler{
2433dbf98a5SAxel Dörfler	return _kern_has_data(thread);
244712ec3d7SAxel Dörfler}
2453dbf98a5SAxel Dörfler
246712ec3d7SAxel Dörfler
247712ec3d7SAxel Dörflerstatus_t
2484b2d22c0SAxel Dörflersnooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
249712ec3d7SAxel Dörfler{
25024df6592SIngo Weinhold	return _kern_snooze_etc(timeout, timeBase, flags, NULL);
251712ec3d7SAxel Dörfler}
252712ec3d7SAxel Dörfler
253712ec3d7SAxel Dörfler
254712ec3d7SAxel Dörflerstatus_t
2554b2d22c0SAxel Dörflersnooze(bigtime_t timeout)
256712ec3d7SAxel Dörfler{
25724df6592SIngo Weinhold	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT,
25824df6592SIngo Weinhold		NULL);
2594b2d22c0SAxel Dörfler}
2604b2d22c0SAxel Dörfler
2614b2d22c0SAxel Dörfler
2624b2d22c0SAxel Dörflerstatus_t
2634b2d22c0SAxel Dörflersnooze_until(bigtime_t timeout, int timeBase)
2644b2d22c0SAxel Dörfler{
26524df6592SIngo Weinhold	return _kern_snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT, NULL);
266712ec3d7SAxel Dörfler}
267