xref: /haiku/src/system/libroot/os/thread.c (revision cbed190f71b8aff814bf95539c39a1bcfb953ed8)
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(thread_func entry, void* _thread)
36 {
37 	pthread_thread* thread = (pthread_thread*)_thread;
38 	status_t returnCode;
39 
40 	*tls_address(TLS_PTHREAD_SLOT) = thread;
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 	__pthread_destroy_thread();
75 }
76 
77 
78 // #pragma mark -
79 
80 
81 thread_id
82 spawn_thread(thread_func entry, const char *name, int32 priority, void *data)
83 {
84 	struct thread_creation_attributes attributes;
85 	pthread_thread* thread;
86 	thread_id id;
87 
88 	thread = __allocate_pthread(data);
89 	if (thread == NULL)
90 		return B_NO_MEMORY;
91 
92 	_single_threaded = false;
93 		// used for I/O locking - BeOS compatibility issue
94 
95 	attributes.entry = &thread_entry;
96 	attributes.name = name;
97 	attributes.priority = priority;
98 	attributes.args1 = entry;
99 	attributes.args2 = thread;
100 	attributes.stack_address = NULL;
101 	attributes.stack_size = 0;
102 
103 	id = _kern_spawn_thread(&attributes);
104 	if (id < 0)
105 		free(thread);
106 	else
107 		thread->id = id;
108 	return id;
109 }
110 
111 
112 status_t
113 kill_thread(thread_id thread)
114 {
115 	return _kern_kill_thread(thread);
116 }
117 
118 
119 status_t
120 resume_thread(thread_id thread)
121 {
122 	return _kern_resume_thread(thread);
123 }
124 
125 
126 status_t
127 suspend_thread(thread_id thread)
128 {
129 	return _kern_suspend_thread(thread);
130 }
131 
132 
133 status_t
134 rename_thread(thread_id thread, const char *name)
135 {
136 	return _kern_rename_thread(thread, name);
137 }
138 
139 
140 status_t
141 set_thread_priority(thread_id thread, int32 priority)
142 {
143 	return _kern_set_thread_priority(thread, priority);
144 }
145 
146 
147 void
148 exit_thread(status_t status)
149 {
150 	_thread_do_exit_work();
151 	_kern_exit_thread(status);
152 }
153 
154 
155 status_t
156 wait_for_thread(thread_id thread, status_t *_returnCode)
157 {
158 	return _kern_wait_for_thread(thread, _returnCode);
159 }
160 
161 
162 status_t
163 on_exit_thread(void (*callback)(void *), void *data)
164 {
165 	callback_node **head = (callback_node **)tls_address(TLS_ON_EXIT_THREAD_SLOT);
166 
167 	callback_node *node = malloc(sizeof(callback_node));
168 	if (node == NULL)
169 		return B_NO_MEMORY;
170 
171 	node->function = callback;
172 	node->argument = data;
173 
174 	// add this node to the list
175 	node->next = *head;
176 	*head = node;
177 
178 	return B_OK;
179 }
180 
181 
182 status_t
183 _get_thread_info(thread_id thread, thread_info *info, size_t size)
184 {
185 	if (info == NULL || size != sizeof(thread_info))
186 		return B_BAD_VALUE;
187 
188 	return _kern_get_thread_info(thread, info);
189 }
190 
191 
192 status_t
193 _get_next_thread_info(team_id team, int32 *cookie, thread_info *info, size_t size)
194 {
195 	if (info == NULL || size != sizeof(thread_info))
196 		return B_BAD_VALUE;
197 
198 	return _kern_get_next_thread_info(team, cookie, info);
199 }
200 
201 
202 status_t
203 send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize)
204 {
205 	return _kern_send_data(thread, code, buffer, bufferSize);
206 }
207 
208 
209 int32
210 receive_data(thread_id *_sender, void *buffer, size_t bufferSize)
211 {
212 	return _kern_receive_data(_sender, buffer, bufferSize);
213 }
214 
215 
216 bool
217 has_data(thread_id thread)
218 {
219 	return _kern_has_data(thread);
220 }
221 
222 
223 status_t
224 snooze_etc(bigtime_t timeout, int timeBase, uint32 flags)
225 {
226 	return _kern_snooze_etc(timeout, timeBase, flags);
227 }
228 
229 
230 status_t
231 snooze(bigtime_t timeout)
232 {
233 	return _kern_snooze_etc(timeout, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
234 }
235 
236 
237 status_t
238 snooze_until(bigtime_t timeout, int timeBase)
239 {
240 	return snooze_etc(timeout, timeBase, B_ABSOLUTE_TIMEOUT);
241 }
242 
243