xref: /haiku/src/system/libroot/os/thread.c (revision 0754c319592cd8a523959d85fb06ab23c64a98a6)
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 	returnCode = entry(thread->entry_argument);
43 
44 	_thread_do_exit_work();
45 
46 	return returnCode;
47 }
48 
49 
50 void
51 _thread_do_exit_notification(void)
52 {
53 	// empty stub for R5 compatibility
54 }
55 
56 
57 void
58 _thread_do_exit_work(void)
59 {
60 	callback_node *node = tls_get(TLS_ON_EXIT_THREAD_SLOT);
61 	callback_node *next;
62 
63 	while (node != NULL) {
64 		next = node->next;
65 
66 		node->function(node->argument);
67 		free(node);
68 
69 		node = next;
70 	}
71 
72 	tls_set(TLS_ON_EXIT_THREAD_SLOT, NULL);
73 
74 	__gRuntimeLoader->destroy_thread_tls();
75 
76 	__pthread_destroy_thread();
77 }
78 
79 
80 void
81 __set_stack_protection(void)
82 {
83 	if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU) {
84 		area_info info;
85 		ssize_t cookie = 0;
86 
87 		while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
88 			if ((info.protection & B_STACK_AREA) != 0) {
89 				_kern_set_area_protection(info.area,
90 					B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA | B_STACK_AREA);
91 			}
92 		}
93 	}
94 }
95 
96 
97 // #pragma mark -
98 
99 
100 thread_id
101 spawn_thread(thread_func entry, const char *name, int32 priority, void *data)
102 {
103 	struct thread_creation_attributes attributes;
104 	pthread_thread* thread;
105 	thread_id id;
106 
107 	thread = __allocate_pthread(NULL, data);
108 	if (thread == NULL)
109 		return B_NO_MEMORY;
110 
111 	_single_threaded = false;
112 		// used for I/O locking - BeOS compatibility issue
113 
114 	__pthread_init_creation_attributes(NULL, thread, &thread_entry, entry,
115 		thread, name, &attributes);
116 	thread->flags |= THREAD_DETACHED;
117 
118 	attributes.priority = priority;
119 
120 	id = _kern_spawn_thread(&attributes);
121 	if (id < 0)
122 		free(thread);
123 	else {
124 		thread->id = id;
125 		__set_stack_protection();
126 	}
127 
128 	return id;
129 }
130 
131 
132 status_t
133 kill_thread(thread_id thread)
134 {
135 	return _kern_kill_thread(thread);
136 }
137 
138 
139 status_t
140 resume_thread(thread_id thread)
141 {
142 	return _kern_resume_thread(thread);
143 }
144 
145 
146 status_t
147 suspend_thread(thread_id thread)
148 {
149 	return _kern_suspend_thread(thread);
150 }
151 
152 
153 status_t
154 rename_thread(thread_id thread, const char *name)
155 {
156 	return _kern_rename_thread(thread, name);
157 }
158 
159 
160 status_t
161 set_thread_priority(thread_id thread, int32 priority)
162 {
163 	return _kern_set_thread_priority(thread, priority);
164 }
165 
166 
167 void
168 exit_thread(status_t status)
169 {
170 	_thread_do_exit_work();
171 	_kern_exit_thread(status);
172 }
173 
174 
175 status_t
176 wait_for_thread(thread_id thread, status_t *_returnCode)
177 {
178 	return _kern_wait_for_thread(thread, _returnCode);
179 }
180 
181 
182 status_t
183 on_exit_thread(void (*callback)(void *), void *data)
184 {
185 	callback_node **head = (callback_node **)tls_address(TLS_ON_EXIT_THREAD_SLOT);
186 
187 	callback_node *node = malloc(sizeof(callback_node));
188 	if (node == NULL)
189 		return B_NO_MEMORY;
190 
191 	node->function = callback;
192 	node->argument = data;
193 
194 	// add this node to the list
195 	node->next = *head;
196 	*head = node;
197 
198 	return B_OK;
199 }
200 
201 
202 status_t
203 _get_thread_info(thread_id thread, thread_info *info, size_t size)
204 {
205 	if (info == NULL || size != sizeof(thread_info))
206 		return B_BAD_VALUE;
207 
208 	return _kern_get_thread_info(thread, info);
209 }
210 
211 
212 status_t
213 _get_next_thread_info(team_id team, int32 *cookie, thread_info *info, size_t size)
214 {
215 	if (info == NULL || size != sizeof(thread_info))
216 		return B_BAD_VALUE;
217 
218 	return _kern_get_next_thread_info(team, cookie, info);
219 }
220 
221 
222 status_t
223 send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize)
224 {
225 	return _kern_send_data(thread, code, buffer, bufferSize);
226 }
227 
228 
229 int32
230 receive_data(thread_id *_sender, void *buffer, size_t bufferSize)
231 {
232 	return _kern_receive_data(_sender, buffer, bufferSize);
233 }
234 
235 
236 bool
237 has_data(thread_id thread)
238 {
239 	return _kern_has_data(thread);
240 }
241 
242 
243 status_t
244 snooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
245 {
246 	return _kern_snooze_etc(timeout, timeBase, flags, NULL);
247 }
248 
249 
250 status_t
251 snooze(bigtime_t timeout)
252 {
253 	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT,
254 		NULL);
255 }
256 
257 
258 status_t
259 snooze_until(bigtime_t timeout, int timeBase)
260 {
261 	return _kern_snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT, NULL);
262 }
263