|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2004,2005 David Decotigny 002 003 This program is free software; you can redistribute it and/or 004 modify it under the terms of the GNU General Public License 005 as published by the Free Software Foundation; either version 2 006 of the License, or (at your option) any later version. 007 008 This program is distributed in the hope that it will be useful, 009 but WITHOUT ANY WARRANTY; without even the implied warranty of 010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 011 GNU General Public License for more details. 012 013 You should have received a copy of the GNU General Public License 014 along with this program; if not, write to the Free Software 015 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 016 USA. 017 */ 018 #ifndef _SOS_THREAD_H_ 019 #define _SOS_THREAD_H_ 020 021 /** 022 * @file thread.h 023 * 024 * SOS Thread management API 025 */ 026 027 #include <sos/errno.h> 028 029 /* Forward declaration */ 030 struct sos_thread; 031 032 #include <hwcore/cpu_context.h> 033 #include <sos/sched.h> 034 #include <sos/kwaitq.h> 035 #include <sos/time.h> 036 #include <sos/process.h> 037 #include <sos/umem_vmm.h> 038 039 /** 040 * The possible states of a valid thread 041 */ 042 typedef enum { SOS_THR_CREATED, /**< Thread created, not fully initialized */ 043 SOS_THR_READY, /**< Thread fully initialized or 044 waiting for CPU after having been 045 blocked or preempted */ 046 SOS_THR_RUNNING, /**< Thread currently running on CPU */ 047 SOS_THR_BLOCKED, /**< Thread waiting for I/O (+ in at LEAST 048 one kwaitq) and/or sleeping (+ in NO 049 kwaitq) */ 050 SOS_THR_ZOMBIE, /**< Thread terminated execution, waiting to 051 be deleted by kernel */ 052 } sos_thread_state_t; 053 054 055 /** 056 * TCB (Thread Control Block): structure describing a thread. Don't 057 * access these fields directly: prefer using the accessor functions 058 * below. 059 */ 060 struct sos_thread 061 { 062 #define SOS_THR_MAX_NAMELEN 32 063 char name[SOS_THR_MAX_NAMELEN]; 064 065 sos_thread_state_t state; 066 sos_sched_priority_t priority; 067 068 /** 069 * The hardware context of the thread. 070 * 071 * It will reflect the CPU state of the thread: 072 * - From an interrupt handler: the state of the thread at the time 073 * of the OUTERMOST irq. An IRQ is not allowed to make context 074 * switches, so this context will remain valid from the begining of 075 * the outermost IRQ handler to the end of it, no matter if there 076 * are other IRQ handlers nesting in one another. You may safely 077 * use it from IRQ handlers to query the state of the interrupted 078 * thread, no matter if there has been other IRQ handlers 079 * executing meanwhile. 080 * - From normal kernel code, exceptions and syscall: the state of 081 * the thread the last time there was a context switch from this 082 * thread to another one. Thus this field WON'T reflect the 083 * current's thread cpu_state in these cases. So, in these cases, 084 * simply DO NOT USE IT outside thread.c ! Note: for syscall and 085 * exception handlers, the VALID state of the interrupted thread is 086 * passed as an argument to the handlers. 087 */ 088 struct sos_cpu_state *cpu_state; 089 090 /* Kernel stack parameters */ 091 sos_vaddr_t kernel_stack_base_addr; 092 sos_size_t kernel_stack_size; 093 094 /* Process this thread belongs to. Always NULL for a kernel 095 thread */ 096 struct sos_process *process; 097 098 /** 099 * Address space currently "squatted" by the thread, or used to be 100 * active when the thread was interrupted/preempted. This is the MMU 101 * configuration expected before the cpu_state of the thread is 102 * restored on CPU. 103 * - For kernel threads: should normally be NULL, meaning that the 104 * thread will squat the current mm_context currently set in the 105 * MMU. Might be NON NULL when a kernel thread squats a given 106 * process to manipulate its address space. 107 * - For user threads: should normally be NULL. More precisely: 108 * - in user mode: the thread->process.mm_context is ALWAYS 109 * set on MMU. squatted_mm_context is ALWAYS NULL in this 110 * situation, meaning that the thread in user mode uses its 111 * process-space as expected 112 * - in kernel mode: NULL means that we keep on using the 113 * mm_context currently set on MMU, which might be the 114 * mm_context of another process. This is natural since a 115 * thread in kernel mode normally only uses data in kernel 116 * space. BTW, this limits the number of TLB flushes. However, 117 * there are exceptions where this squatted_mm_context will 118 * NOT be NULL. One is the copy_from/to_user API, which can 119 * force the effective mm_context so that the MMU will be 120 * (re)configured upon every context to the thread to match 121 * the squatted_mm_context. Another exception is when a parent 122 * thread creates the address space of a child process, in 123 * which case the parent thread might temporarilly decide to 124 * switch to the child's process space. 125 * 126 * This is the SOS implementation of the Linux "Lazy TLB" and 127 * address-space loaning. 128 */ 129 struct sos_mm_context *squatted_mm_context; 130 131 /* Data specific to each state */ 132 union 133 { 134 struct 135 { 136 struct sos_sched_queue *rdy_queue; 137 struct sos_thread *rdy_prev, *rdy_next; 138 } ready; 139 140 struct 141 { 142 struct sos_time user_time_spent_in_slice; 143 } running; 144 }; /* Anonymous union (gcc extenion) */ 145 146 147 /** 148 * When a thread in kernel mode is accessing the user space, it may 149 * page fault in the usual way only if return_vaddr below is 150 * set. This structure holds information regarding what to do when a 151 * page fault from kernel into user space could not be resolved. 152 * 153 * @note the fields below should be considered read-only. @see 154 * sos_thread_prepare_user_space_access() and @see 155 * sos_thread_end_user_space_access() to modify them. 156 */ 157 struct 158 { 159 /** This is the address (in kernel code) to return to when a 160 user-space page fault from a kernel-mode thread could not be 161 resolved. @see sos_thread_prepare_user_space_access() */ 162 sos_vaddr_t return_vaddr; 163 164 /** This is the address of the user-space address that caused the 165 unresolved page fault (set by the page fault handler) */ 166 sos_uaddr_t faulted_uaddr; 167 } fixup_uaccess; 168 169 170 /* 171 * Data used by the kwaitq subsystem: list of kwaitqueues the thread 172 * is waiting for. 173 * 174 * @note: a RUNNING or READY thread might be in one or more 175 * waitqueues ! The only property we have is that, among these 176 * waitqueues (if any), _at least_ one has woken the thread. 177 */ 178 struct sos_kwaitq_entry *kwaitq_list; 179 180 181 /** 182 * Some statistics 183 */ 184 struct rusage 185 { 186 /* Updated by sched.c */ 187 struct sos_time ru_utime; /* Time spent in user mode */ 188 struct sos_time ru_stime; /* Time spent in kernel mode */ 189 } rusage; 190 191 192 /** 193 * Chaining pointers for the list of threads in the parent process 194 */ 195 struct sos_thread *prev_in_process, *next_in_process; 196 197 198 /** 199 * Chaining pointers for global ("gbl") list of threads (debug) 200 */ 201 struct sos_thread *gbl_prev, *gbl_next; 202 }; 203 204 205 /** 206 * Definition of the function executed by a kernel thread 207 */ 208 typedef void (*sos_kernel_thread_start_routine_t)(void *arg); 209 210 211 /** 212 * Initialize the subsystem responsible for thread management 213 * 214 * Initialize the primary kernel thread so that it can be handled the 215 * same way as an ordinary thread created by sos_thread_create(). 216 */ 217 sos_ret_t sos_thread_subsystem_setup(sos_vaddr_t init_thread_stack_base_addr, 218 sos_size_t init_thread_stack_size); 219 220 221 /** 222 * Create a new kernel thread 223 */ 224 struct sos_thread * 225 sos_create_kernel_thread(const char *name, 226 sos_kernel_thread_start_routine_t start_func, 227 void *start_arg, 228 sos_sched_priority_t priority); 229 230 231 /** 232 * Create a new user thread 233 */ 234 struct sos_thread * 235 sos_create_user_thread(const char *name, 236 struct sos_process *process, 237 sos_uaddr_t user_initial_PC, 238 sos_ui32_t user_start_arg1, 239 sos_ui32_t user_start_arg2, 240 sos_uaddr_t user_initial_SP, 241 sos_sched_priority_t priority); 242 243 244 /** 245 * Create a new user thread, copy of the given user thread with the 246 * given user context 247 */ 248 struct sos_thread * 249 sos_duplicate_user_thread(const char *name, 250 struct sos_process *process, 251 const struct sos_thread * model_thread, 252 const struct sos_cpu_state * model_uctxt, 253 sos_ui32_t retval); 254 255 256 /** 257 * Terminate the execution of the current thread. For kernel threads, 258 * it is called by default when the start routine returns. 259 */ 260 void sos_thread_exit() __attribute__((noreturn)); 261 262 263 /** 264 * Get the identifier of the thread currently running on CPU. Trivial 265 * function. 266 */ 267 struct sos_thread *sos_thread_get_current(); 268 269 270 /** 271 * If thr == NULL, set the priority of the current thread. Trivial 272 * function. 273 * 274 * @note NOT protected against interrupts 275 */ 276 sos_sched_priority_t sos_thread_get_priority(struct sos_thread *thr); 277 278 279 /** 280 * If thr == NULL, get the state of the current thread. Trivial 281 * function. 282 * 283 * @note NOT protected against interrupts 284 */ 285 sos_thread_state_t sos_thread_get_state(struct sos_thread *thr); 286 287 288 /** 289 * If thr == NULL, set the priority of the current thread 290 * 291 * @note NO context-switch ever occurs in this function ! 292 */ 293 sos_ret_t sos_thread_set_priority(struct sos_thread *thr, 294 sos_sched_priority_t priority); 295 296 297 /** 298 * Yield CPU to another ready thread. 299 * 300 * @note This is a BLOCKING FUNCTION 301 */ 302 sos_ret_t sos_thread_yield(); 303 304 305 /** 306 * Release the CPU for (at least) the given delay. 307 * 308 * @param delay The delay to wait for. If delay == NULL then wait 309 * forever that any event occurs. 310 * 311 * @return SOS_OK when delay expired (and delay is reset to zero), 312 * -SOS_EINTR otherwise (and delay contains the amount of time 313 * remaining). 314 * 315 * @note This is a BLOCKING FUNCTION 316 */ 317 sos_ret_t sos_thread_sleep(/* in/out */struct sos_time *delay); 318 319 320 /** 321 * Mark the given thread as READY (if not already ready) even if it is 322 * blocked in a kwaitq or in a sleep ! As a result, the interrupted 323 * kwaitq/sleep function call of the thread will return with 324 * -SOS_EINTR. 325 * 326 * @return -SOS_EINVAL if thread does not exist, or -SOS_EFATAL if 327 * marked ZOMBIE. 328 * 329 * @note As a result, the semaphore/mutex/conditions/... functions 330 * return values SHOULD ALWAYS be checked ! If they are != SOS_OK, 331 * then the caller should consider that the resource is not aquired 332 * because somebody woke the thread by some way. 333 */ 334 sos_ret_t sos_thread_force_unblock(struct sos_thread *thread); 335 336 /** 337 * Dump the backtrace of the current thread to console and/or bochs 338 */ 339 void sos_thread_dump_backtrace(sos_bool_t on_console, 340 sos_bool_t on_bochs); 341 342 343 /* ********************************************** 344 * Restricted functions 345 */ 346 347 348 /** 349 * Restricted function to indicate that we are to access the given 350 * user address space from inside the kernel. 351 * 352 * @param dest_as The address space we want to access, or NULL to 353 * access current thread's address space 354 * 355 * @param fixup_retvaddr When != 0, then dest_as MUST BE NULL (we 356 * don't allow controlled access from kernel into user space from a 357 * foreign thread). In this case, the page fault handler should accept 358 * page faults from the kernel in user space, and resolve them in the 359 * usual way. The value in retvaddr is where the page fault handler 360 * has to return to in case the page fault remains unresolved. The 361 * address of the faulting address is kept in 362 * éthread->fixup_uaccess.faulted_uaddr 363 * 364 * @note typical values for fixup_retvaddr are obtained by "Labels as 365 * values" (see gcc's doc: operator "&&"). See uaccess.c for example 366 * code. 367 */ 368 sos_ret_t 369 sos_thread_prepare_user_space_access(struct sos_umem_vmm_as * dest_as, 370 sos_vaddr_t fixup_retvaddr); 371 372 373 /** 374 * Restricted function to signal we are not accessing any user address 375 * space anymore 376 */ 377 sos_ret_t 378 sos_thread_end_user_space_access(void); 379 380 381 /** 382 * Restricted callback called when a syscall goes back in user mode, 383 * to reconfigure the MMU to match that of the current thread's 384 * process MMU context. 385 * 386 * @note The use of this function is RESERVED to the syscall wrapper 387 */ 388 void sos_thread_prepare_syscall_switch_back(struct sos_cpu_state *cpu_state); 389 390 391 /** 392 * Restricted callback called when an exception handler goes back to 393 * the interrupted thread to reconfigure the MMU to match that of the 394 * current thread's process MMU context. 395 * 396 * @note The use of this function is RESERVED to the exception wrappers 397 */ 398 void sos_thread_prepare_exception_switch_back(struct sos_cpu_state *cpu_state); 399 400 401 /** 402 * Restricted callback called when an IRQ is entered while the CPU was 403 * NOT already servicing any other IRQ (ie the outermost IRQ handler 404 * is entered). This callback simply updates the "cpu_state" field so 405 * that IRQ handlers always know the state of the interrupted thread, 406 * even if they are imbricated in other IRQ handlers. 407 * 408 * @note The use of this function is RESERVED to the irq wrappers 409 */ 410 void 411 sos_thread_prepare_irq_servicing(struct sos_cpu_state *interrupted_state); 412 413 414 /** 415 * Restricted callback called when the outermost IRQ handler returns, 416 * to select the thread to return to. This callbacks implements: 417 * - preemption of user threads in user mode (time sharing / FIFO) 418 * - non-preemption of user threads in kernel mode (interrupted thread 419 * is restored on CPU "as is") 420 * - non-preemption of kernel threads (same remark) 421 * The MMU is reconfigured correctly to match the address space of the 422 * selected thread. 423 * 424 * @return The CPU context of the thread to return to 425 * 426 * @note The use of this function is RESERVED to the irq wrappers 427 */ 428 struct sos_cpu_state * 429 sos_thread_prepare_irq_switch_back(void); 430 431 432 #endif /* _SOS_THREAD_H_ */
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |