xref: /haiku/src/system/libroot/os/thread.c (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
24 typedef struct callback_node {
25 	struct callback_node *next;
26 	void (*function)(void *);
27 	void *argument;
28 } callback_node;
29 
30 
31 void _thread_do_exit_work(void);
32 void _thread_do_exit_notification(void);
33 
34 
35 static status_t
36 thread_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 
53 void
54 _thread_do_exit_notification(void)
55 {
56 	// empty stub for R5 compatibility
57 }
58 
59 
60 void
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 	__gRuntimeLoader->destroy_thread_tls();
78 
79 	__pthread_destroy_thread();
80 }
81 
82 
83 void
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 
103 thread_id
104 spawn_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 
135 status_t
136 kill_thread(thread_id thread)
137 {
138 	return _kern_kill_thread(thread);
139 }
140 
141 
142 status_t
143 resume_thread(thread_id thread)
144 {
145 	return _kern_resume_thread(thread);
146 }
147 
148 
149 status_t
150 suspend_thread(thread_id thread)
151 {
152 	return _kern_suspend_thread(thread);
153 }
154 
155 
156 status_t
157 rename_thread(thread_id thread, const char *name)
158 {
159 	return _kern_rename_thread(thread, name);
160 }
161 
162 
163 status_t
164 set_thread_priority(thread_id thread, int32 priority)
165 {
166 	return _kern_set_thread_priority(thread, priority);
167 }
168 
169 
170 void
171 exit_thread(status_t status)
172 {
173 	_thread_do_exit_work();
174 	__heap_thread_exit();
175 	_kern_exit_thread(status);
176 }
177 
178 
179 status_t
180 wait_for_thread(thread_id thread, status_t *_returnCode)
181 {
182 	return _kern_wait_for_thread(thread, _returnCode);
183 }
184 
185 
186 status_t
187 on_exit_thread(void (*callback)(void *), void *data)
188 {
189 	callback_node **head = (callback_node **)tls_address(TLS_ON_EXIT_THREAD_SLOT);
190 
191 	callback_node *node = malloc(sizeof(callback_node));
192 	if (node == NULL)
193 		return B_NO_MEMORY;
194 
195 	node->function = callback;
196 	node->argument = data;
197 
198 	// add this node to the list
199 	node->next = *head;
200 	*head = node;
201 
202 	return B_OK;
203 }
204 
205 
206 status_t
207 _get_thread_info(thread_id thread, thread_info *info, size_t size)
208 {
209 	if (info == NULL || size != sizeof(thread_info))
210 		return B_BAD_VALUE;
211 
212 	return _kern_get_thread_info(thread, info);
213 }
214 
215 
216 status_t
217 _get_next_thread_info(team_id team, int32 *cookie, thread_info *info, size_t size)
218 {
219 	if (info == NULL || size != sizeof(thread_info))
220 		return B_BAD_VALUE;
221 
222 	return _kern_get_next_thread_info(team, cookie, info);
223 }
224 
225 
226 status_t
227 send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize)
228 {
229 	return _kern_send_data(thread, code, buffer, bufferSize);
230 }
231 
232 
233 int32
234 receive_data(thread_id *_sender, void *buffer, size_t bufferSize)
235 {
236 	return _kern_receive_data(_sender, buffer, bufferSize);
237 }
238 
239 
240 bool
241 has_data(thread_id thread)
242 {
243 	return _kern_has_data(thread);
244 }
245 
246 
247 status_t
248 snooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
249 {
250 	return _kern_snooze_etc(timeout, timeBase, flags, NULL);
251 }
252 
253 
254 status_t
255 snooze(bigtime_t timeout)
256 {
257 	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT,
258 		NULL);
259 }
260 
261 
262 status_t
263 snooze_until(bigtime_t timeout, int timeBase)
264 {
265 	return _kern_snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT, NULL);
266 }
267