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