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