1 /* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 #ifndef _THREAD_H 10 #define _THREAD_H 11 12 13 #include <OS.h> 14 #include <thread_types.h> 15 #include <arch/thread.h> 16 17 // For the thread blocking inline functions only. 18 #include <kscheduler.h> 19 #include <ksignal.h> 20 21 22 struct kernel_args; 23 struct select_info; 24 struct thread_creation_attributes; 25 26 27 // thread notifications 28 #define THREAD_MONITOR '_tm_' 29 #define THREAD_ADDED 0x01 30 #define THREAD_REMOVED 0x02 31 #define THREAD_NAME_CHANGED 0x04 32 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif 37 38 void thread_enqueue(Thread *t, struct thread_queue *q); 39 Thread *thread_lookat_queue(struct thread_queue *q); 40 Thread *thread_dequeue(struct thread_queue *q); 41 Thread *thread_dequeue_id(struct thread_queue *q, thread_id id); 42 43 void thread_at_kernel_entry(bigtime_t now); 44 // called when the thread enters the kernel on behalf of the thread 45 void thread_at_kernel_exit(void); 46 void thread_at_kernel_exit_no_signals(void); 47 void thread_reset_for_exec(void); 48 49 status_t thread_init(struct kernel_args *args); 50 status_t thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum); 51 void thread_yield(bool force); 52 void thread_exit(void); 53 54 int32 thread_max_threads(void); 55 int32 thread_used_threads(void); 56 57 const char* thread_state_to_text(Thread* thread, int32 state); 58 59 int32 thread_get_io_priority(thread_id id); 60 void thread_set_io_priority(int32 priority); 61 62 #define thread_get_current_thread arch_thread_get_current_thread 63 64 Thread *thread_get_thread_struct(thread_id id); 65 Thread *thread_get_thread_struct_locked(thread_id id); 66 67 static thread_id thread_get_current_thread_id(void); 68 static inline thread_id 69 thread_get_current_thread_id(void) 70 { 71 Thread *thread = thread_get_current_thread(); 72 return thread ? thread->id : 0; 73 } 74 75 static inline bool 76 thread_is_idle_thread(Thread *thread) 77 { 78 return thread->entry == NULL; 79 } 80 81 typedef bool (*thread_iterator_callback)(Thread* thread, void* cookie); 82 Thread* thread_iterate_through_threads(thread_iterator_callback callback, 83 void* cookie); 84 85 thread_id allocate_thread_id(void); 86 thread_id peek_next_thread_id(void); 87 88 thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority, 89 void *args, team_id team, thread_id threadID); 90 status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, 91 status_t *_returnCode); 92 93 status_t select_thread(int32 object, struct select_info *info, bool kernel); 94 status_t deselect_thread(int32 object, struct select_info *info, bool kernel); 95 96 #define syscall_64_bit_return_value() arch_syscall_64_bit_return_value() 97 98 status_t thread_block(); 99 status_t thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout); 100 status_t thread_block_with_timeout_locked(uint32 timeoutFlags, 101 bigtime_t timeout); 102 void thread_unblock(status_t threadID, status_t status); 103 104 // used in syscalls.c 105 status_t _user_set_thread_priority(thread_id thread, int32 newPriority); 106 status_t _user_rename_thread(thread_id thread, const char *name); 107 status_t _user_suspend_thread(thread_id thread); 108 status_t _user_resume_thread(thread_id thread); 109 status_t _user_rename_thread(thread_id thread, const char *name); 110 thread_id _user_spawn_thread(struct thread_creation_attributes* attributes); 111 status_t _user_wait_for_thread(thread_id id, status_t *_returnCode); 112 status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags); 113 status_t _user_kill_thread(thread_id thread); 114 void _user_thread_yield(void); 115 void _user_exit_thread(status_t return_value); 116 bool _user_has_data(thread_id thread); 117 status_t _user_send_data(thread_id thread, int32 code, const void *buffer, size_t buffer_size); 118 status_t _user_receive_data(thread_id *_sender, void *buffer, size_t buffer_size); 119 thread_id _user_find_thread(const char *name); 120 status_t _user_get_thread_info(thread_id id, thread_info *info); 121 status_t _user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info); 122 123 status_t _user_block_thread(uint32 flags, bigtime_t timeout); 124 status_t _user_unblock_thread(thread_id thread, status_t status); 125 status_t _user_unblock_threads(thread_id* threads, uint32 count, 126 status_t status); 127 128 // ToDo: these don't belong here 129 struct rlimit; 130 int _user_getrlimit(int resource, struct rlimit * rlp); 131 int _user_setrlimit(int resource, const struct rlimit * rlp); 132 133 #ifdef __cplusplus 134 } 135 #endif 136 137 138 /*! 139 \a thread must be the current thread. 140 Thread lock can be, but doesn't need to be held. 141 */ 142 static inline bool 143 thread_is_interrupted(Thread* thread, uint32 flags) 144 { 145 return ((flags & B_CAN_INTERRUPT) 146 && (thread->sig_pending & ~thread->sig_block_mask) != 0) 147 || ((flags & B_KILL_CAN_INTERRUPT) 148 && (thread->sig_pending & KILL_SIGNALS)); 149 } 150 151 152 static inline bool 153 thread_is_blocked(Thread* thread) 154 { 155 return thread->wait.status == 1; 156 } 157 158 159 /*! 160 \a thread must be the current thread. 161 Thread lock can be, but doesn't need to be locked. 162 */ 163 static inline void 164 thread_prepare_to_block(Thread* thread, uint32 flags, uint32 type, 165 const void* object) 166 { 167 thread->wait.flags = flags; 168 thread->wait.type = type; 169 thread->wait.object = object; 170 atomic_set(&thread->wait.status, 1); 171 // Set status last to guarantee that the other fields are initialized 172 // when a thread is waiting. 173 } 174 175 176 static inline status_t 177 thread_block_locked(Thread* thread) 178 { 179 if (thread->wait.status == 1) { 180 // check for signals, if interruptable 181 if (thread_is_interrupted(thread, thread->wait.flags)) { 182 thread->wait.status = B_INTERRUPTED; 183 } else { 184 thread->next_state = B_THREAD_WAITING; 185 scheduler_reschedule(); 186 } 187 } 188 189 return thread->wait.status; 190 } 191 192 193 static inline void 194 thread_unblock_locked(Thread* thread, status_t status) 195 { 196 if (atomic_test_and_set(&thread->wait.status, status, 1) != 1) 197 return; 198 199 // wake up the thread, if it is sleeping 200 if (thread->state == B_THREAD_WAITING) 201 scheduler_enqueue_in_run_queue(thread); 202 } 203 204 205 static inline status_t 206 thread_interrupt(Thread* thread, bool kill) 207 { 208 if ((thread->wait.flags & B_CAN_INTERRUPT) != 0 209 || (kill && (thread->wait.flags & B_KILL_CAN_INTERRUPT) != 0)) { 210 thread_unblock_locked(thread, B_INTERRUPTED); 211 return B_OK; 212 } 213 214 return B_NOT_ALLOWED; 215 } 216 217 218 static inline void 219 thread_pin_to_current_cpu(Thread* thread) 220 { 221 thread->pinned_to_cpu++; 222 } 223 224 225 static inline void 226 thread_unpin_from_current_cpu(Thread* thread) 227 { 228 thread->pinned_to_cpu--; 229 } 230 231 232 #endif /* _THREAD_H */ 233