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