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