xref: /haiku/src/system/libroot/os/thread.c (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
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 	__pthread_destroy_thread();
78 
79 	__gRuntimeLoader->destroy_thread_tls();
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 wait_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 
193 status_t
194 on_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 
213 status_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 
223 status_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 
233 status_t
234 send_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 
240 int32
241 receive_data(thread_id *_sender, void *buffer, size_t bufferSize)
242 {
243 	return _kern_receive_data(_sender, buffer, bufferSize);
244 }
245 
246 
247 bool
248 has_data(thread_id thread)
249 {
250 	return _kern_has_data(thread);
251 }
252 
253 
254 status_t
255 snooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
256 {
257 	return _kern_snooze_etc(timeout, timeBase, flags, NULL);
258 }
259 
260 
261 status_t
262 snooze(bigtime_t timeout)
263 {
264 	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT,
265 		NULL);
266 }
267 
268 
269 status_t
270 snooze_until(bigtime_t timeout, int timeBase)
271 {
272 	return _kern_snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT, NULL);
273 }
274