1/*
2 * Copyright 2002-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <OS.h>
8
9#include <stdlib.h>
10#include <stdio.h>
11
12#include <libroot_private.h>
13#include <pthread_private.h>
14#include <runtime_loader.h>
15#include <thread_defs.h>
16#include <tls.h>
17#include <syscalls.h>
18
19
20#undef thread_entry
21	// thread_entry is still defined in OS.h for compatibility reasons
22
23
24typedef struct callback_node {
25	struct callback_node *next;
26	void (*function)(void *);
27	void *argument;
28} callback_node;
29
30
31void _thread_do_exit_work(void);
32void _thread_do_exit_notification(void);
33
34
35static status_t
36thread_entry(void* _entry, void* _thread)
37{
38	thread_func entry = (thread_func)_entry;
39	pthread_thread* thread = (pthread_thread*)_thread;
40	status_t returnCode;
41
42	__heap_thread_init();
43
44	returnCode = entry(thread->entry_argument);
45
46	_thread_do_exit_work();
47	__heap_thread_exit();
48
49	return returnCode;
50}
51
52
53void
54_thread_do_exit_notification(void)
55{
56	// empty stub for R5 compatibility
57}
58
59
60void
61_thread_do_exit_work(void)
62{
63	callback_node *node = tls_get(TLS_ON_EXIT_THREAD_SLOT);
64	callback_node *next;
65
66	while (node != NULL) {
67		next = node->next;
68
69		node->function(node->argument);
70		free(node);
71
72		node = next;
73	}
74
75	tls_set(TLS_ON_EXIT_THREAD_SLOT, NULL);
76
77	__pthread_destroy_thread();
78
79	__gRuntimeLoader->destroy_thread_tls();
80}
81
82
83void
84__set_stack_protection(void)
85{
86	if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU) {
87		area_info info;
88		ssize_t cookie = 0;
89
90		while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
91			if ((info.protection & B_STACK_AREA) != 0) {
92				_kern_set_area_protection(info.area,
93					B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA | B_STACK_AREA);
94			}
95		}
96	}
97}
98
99
100// #pragma mark -
101
102
103thread_id
104spawn_thread(thread_func entry, const char *name, int32 priority, void *data)
105{
106	struct thread_creation_attributes attributes;
107	pthread_thread* thread;
108	thread_id id;
109
110	thread = __allocate_pthread(NULL, data);
111	if (thread == NULL)
112		return B_NO_MEMORY;
113
114	_single_threaded = false;
115		// used for I/O locking - BeOS compatibility issue
116
117	__pthread_init_creation_attributes(NULL, thread, &thread_entry, entry,
118		thread, name, &attributes);
119	thread->flags |= THREAD_DETACHED;
120
121	attributes.priority = priority;
122
123	id = _kern_spawn_thread(&attributes);
124	if (id < 0)
125		free(thread);
126	else {
127		thread->id = id;
128		__set_stack_protection();
129	}
130
131	return id;
132}
133
134
135status_t
136kill_thread(thread_id thread)
137{
138	return _kern_kill_thread(thread);
139}
140
141
142status_t
143resume_thread(thread_id thread)
144{
145	return _kern_resume_thread(thread);
146}
147
148
149status_t
150suspend_thread(thread_id thread)
151{
152	return _kern_suspend_thread(thread);
153}
154
155
156status_t
157rename_thread(thread_id thread, const char *name)
158{
159	return _kern_rename_thread(thread, name);
160}
161
162
163status_t
164set_thread_priority(thread_id thread, int32 priority)
165{
166	return _kern_set_thread_priority(thread, priority);
167}
168
169
170void
171exit_thread(status_t status)
172{
173	_thread_do_exit_work();
174	__heap_thread_exit();
175	_kern_exit_thread(status);
176}
177
178
179status_t
180wait_for_thread(thread_id thread, status_t *_returnCode)
181{
182	return _kern_wait_for_thread(thread, _returnCode);
183}
184
185
186status_t
187wait_for_thread_etc(thread_id thread, uint32 flags, bigtime_t timeout, status_t *_returnCode)
188{
189	return _kern_wait_for_thread_etc(thread, flags, timeout, _returnCode);
190}
191
192
193status_t
194on_exit_thread(void (*callback)(void *), void *data)
195{
196	callback_node **head = (callback_node **)tls_address(TLS_ON_EXIT_THREAD_SLOT);
197
198	callback_node *node = malloc(sizeof(callback_node));
199	if (node == NULL)
200		return B_NO_MEMORY;
201
202	node->function = callback;
203	node->argument = data;
204
205	// add this node to the list
206	node->next = *head;
207	*head = node;
208
209	return B_OK;
210}
211
212
213status_t
214_get_thread_info(thread_id thread, thread_info *info, size_t size)
215{
216	if (info == NULL || size != sizeof(thread_info))
217		return B_BAD_VALUE;
218
219	return _kern_get_thread_info(thread, info);
220}
221
222
223status_t
224_get_next_thread_info(team_id team, int32 *cookie, thread_info *info, size_t size)
225{
226	if (info == NULL || size != sizeof(thread_info))
227		return B_BAD_VALUE;
228
229	return _kern_get_next_thread_info(team, cookie, info);
230}
231
232
233status_t
234send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize)
235{
236	return _kern_send_data(thread, code, buffer, bufferSize);
237}
238
239
240int32
241receive_data(thread_id *_sender, void *buffer, size_t bufferSize)
242{
243	return _kern_receive_data(_sender, buffer, bufferSize);
244}
245
246
247bool
248has_data(thread_id thread)
249{
250	return _kern_has_data(thread);
251}
252
253
254status_t
255snooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
256{
257	return _kern_snooze_etc(timeout, timeBase, flags, NULL);
258}
259
260
261status_t
262snooze(bigtime_t timeout)
263{
264	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT,
265		NULL);
266}
267
268
269status_t
270snooze_until(bigtime_t timeout, int timeBase)
271{
272	return _kern_snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT, NULL);
273}
274