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