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