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