#include <const.h>
#include <stdlib.h>
#include <string.h>
#include <arch/i386.h>
#include <arch/interrupt.h>
#include <arch/mem.h>
#include <arch/paging.h>
#include <arch/v86.h>
#include <kernel/console.h>
#include <kernel/clock.h>
#include <kernel/elf32.h>
#include <kernel/fat.h>
#include <kernel/kmalloc.h>
#include <kernel/queue.h>
#include <kernel/semaphore.h>
#include <kernel/shell.h>
#include <kernel/umalloc.h>
#include <kernel/task.h>
Go to the source code of this file.
Functions | |||||||||||||
void | do_idle () | ||||||||||||
Simply do nothing... | |||||||||||||
void | kpager () | ||||||||||||
This special kernel thread provides to free the memory space and resources owned by the zombie tasks. | |||||||||||||
pid_t | new_pid () | ||||||||||||
Create a new pid.
| |||||||||||||
pid_t | get_pid () | ||||||||||||
Return the current task pid if there is a curr_task.
| |||||||||||||
task_t * | get_curr_task () | ||||||||||||
Get the current task.
| |||||||||||||
char * | get_pname () | ||||||||||||
Return the current task name if there is a curr_task.
| |||||||||||||
task_t * | create_kthread (void *address, char *pname) | ||||||||||||
Create a new kernel thread.
| |||||||||||||
task_t * | create_process (void *address, void *buffer, size_t size, char *pname, int privilege) | ||||||||||||
Create a new process.
| |||||||||||||
size_t | new_vspace () | ||||||||||||
Create a new virtual space.
| |||||||||||||
uint32_t * | task_setup_stack (int argc, char **argv, addr_t stack_start, size_t stack_size, int privilege) | ||||||||||||
Initialize the stack for a new process.
| |||||||||||||
task_t * | new_task (char *filename, int argc, char **argv, int privilege) | ||||||||||||
Execute a file creating a new task.
| |||||||||||||
bool | kill (pid_t pid) | ||||||||||||
Kill a task by the pid.
| |||||||||||||
void | auto_kill (int n) | ||||||||||||
Kill the current running task.
| |||||||||||||
pid_t | waitpid (pid_t pid, int *status, int options) | ||||||||||||
Wait for the exit of a child.
| |||||||||||||
void | sleep_task (task_t *p) | ||||||||||||
Sleep a process if it is awake.
| |||||||||||||
void | wakeup_task (task_t *p) | ||||||||||||
Wakeup a process if it is sleeping.
| |||||||||||||
void | sched_enter_critical_region () | ||||||||||||
Disable the scheduling of the other tasks.
| |||||||||||||
void | sched_leave_critical_region () | ||||||||||||
Re-enable scheduling for the other tasks. | |||||||||||||
bool | is_sched_enabled () | ||||||||||||
Return if the scheduling is enabled or not. | |||||||||||||
__inline__ void | scheduler () | ||||||||||||
This is a simple round robin scheduler. | |||||||||||||
void | dispatcher () | ||||||||||||
The dispatcher. | |||||||||||||
void | init_multitasking () | ||||||||||||
Initialize the multitasking management. | |||||||||||||
void | ps () | ||||||||||||
Print the state of every process from the ready, wait and zombie queues. | |||||||||||||
Variables | |||||||||||||
size_t | K_PDBR [PAGE_SIZE/sizeof(size_t)] | ||||||||||||
Master page directory. | |||||||||||||
queue_t * | ready_queue = NULL | ||||||||||||
A pointer to ready queue. Declared in task.c. | |||||||||||||
queue_t * | wait_queue = NULL | ||||||||||||
Wait-queue: tasks are waiting for I/O. | |||||||||||||
queue_t * | zombie_queue = NULL | ||||||||||||
Zombie-queue: tasks are dying. | |||||||||||||
task_t * | curr_task = NULL | ||||||||||||
A pointer to the current running task structure. Declared in task.c. | |||||||||||||
task_t * | idle_task = NULL | ||||||||||||
IDLE task structure. Initialized in init_multitasking(). | |||||||||||||
task_t * | kpagd = NULL | ||||||||||||
KPager daemon. | |||||||||||||
atomic_t | last_pid | ||||||||||||
Last used pid. | |||||||||||||
semaphore_t | sched_enabled | ||||||||||||
A semaphore to enable or disable scheduling (used to manage critical regions). |
Definition in file task.c.
|
Kill the current running task.
This routine move the current task from the ready queue to the zombie queue. Then the kpager() daemon should provide to free the memory and resources owned by this task. Definition at line 949 of file task.c.
|
|
Create a new kernel thread.
This routine initialize a new kernel thread structure and add this thread to the ready queue. Definition at line 234 of file task.c.
00235 { 00236 task_t *new_task; 00237 byte *pl0_stack; 00238 00239 sched_enter_critical_region(); 00240 00241 // --- Create the task structure -------------------------------// 00242 //! 00243 //! IA-32 Intel(R) Architecture Software Developer's Manual 00244 //! Volume 3: System Programming Guide - Chapter 6 - reports: 00245 //! 00246 //! "If paging is used, care should be taken to avoid placing a 00247 //! page boundary within the part of the TSS that the processor 00248 //! reads during a task switch (the first 104 bytes). If a page 00249 //! boundary is placed within this part of the TSS, the pages on 00250 //! either side of the boundary must be present at the same time 00251 //! and contiguous in physical memory. 00252 //! 00253 //! The reason for this restriction is that when accessing a TSS 00254 //! during a task switch, the processor reads and writes into 00255 //! the first 104 bytes of each TSS from contiguous physical 00256 //! addresses beginning with the physical address of the first 00257 //! byte of the TSS. It may not perform address translation at a 00258 //! page boundary if one occurs within this area. So, after the 00259 //! TSS access begins, if a part of the 104 bytes is not both 00260 //! present and physically contiguous, the processor will access 00261 //! incorrect TSS information, without generating a page-fault 00262 //! exception. The reading of this incorrect information will 00263 //! generally lead to an unrecoverable exception later in the 00264 //! task switch process..." 00265 new_task = kmemalign(PAGE_SIZE, sizeof(task_t)); 00266 if (new_task == NULL) 00267 { 00268 // Out of virtual memory!!! // 00269 set_color(LIGHT_RED); 00270 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname); 00271 set_color(DEFAULT_COLOR); 00272 00273 sched_leave_critical_region(); 00274 return(NULL); 00275 } 00276 memset(new_task, 0, sizeof(task_t)); 00277 00278 // --- Create the pl0-stack --- // 00279 pl0_stack = kmalloc(STACK_SIZE); 00280 if (pl0_stack == NULL) 00281 { 00282 // Out of virtual memory!!! // 00283 set_color(LIGHT_RED); 00284 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname); 00285 set_color(DEFAULT_COLOR); 00286 // Free the previous allocated space // 00287 kfree((void *)new_task); 00288 00289 sched_leave_critical_region(); 00290 return(NULL); 00291 } 00292 // Null the stack to enforce the page mapping // 00293 memset(pl0_stack, 0, STACK_SIZE); 00294 // Setup the pl0-stack // 00295 new_task->tss.ss0 = new_task->tss.ss = KERNEL_STACK; 00296 new_task->tss.esp0 = new_task->tss.esp = new_task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t)); 00297 00298 // --- Setup the TSS --- // 00299 new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0); 00300 00301 // Setup the task PDBR => get the kernel PDBR // 00302 new_task->tss.cr3 = GET_PDBR(); 00303 00304 // Setup the IO port mapping // 00305 new_task->tss.io_map_addr = sizeof(tss_t); 00306 00307 // Setup general registers // 00308 new_task->tss.ds = new_task->tss.es = KERNEL_DATA; 00309 new_task->tss.fs = new_task->tss.gs = KERNEL_DATA; 00310 new_task->tss.eflags = EFLAGS_IF | 0x02; 00311 00312 // Initialize general purpose registers // 00313 new_task->tss.eax = new_task->tss.ebx = 00314 new_task->tss.ecx = new_task->tss.edx = 00315 new_task->tss.esi = new_task->tss.edi = 0; 00316 00317 // Initialize LDTR (Local Descriptor Table Register) // 00318 // No LDTs for now... 00319 new_task->tss.ldtr = 0; 00320 00321 // Initialize debug trap // 00322 // If set to 1 the processor generate a debug exception when a task switch to this task occurs... 00323 new_task->tss.trace = 0; 00324 00325 // Setup starting address // 00326 new_task->tss.cs = KERNEL_CODE; 00327 new_task->tss.eip = (dword)address; 00328 00329 // --- Get a pid --- // 00330 new_task->pid = new_pid(); 00331 00332 // --- Store the name --- // 00333 // The last character must be ever '\0' (end of string) // 00334 strncpy(new_task->name, pname, sizeof(new_task->name)-2); 00335 00336 // --- Set the type --- // 00337 new_task->type = KTHREAD_T; 00338 00339 // --- Set the parent process --- // 00340 new_task->father = curr_task; 00341 00342 // --- Set the console --- // 00343 new_task->console = curr_task->console; 00344 00345 // --- Insert the task into the ready queue --- // 00346 new_task->state = READY; 00347 add_queue(&ready_queue, new_task); 00348 00349 sched_leave_critical_region(); 00350 00351 return (new_task); 00352 } |
|
Create a new process.
This routine initializes the new task structure, copies the content of the buffer to the entry point address and then add the new task to the ready queue. Definition at line 374 of file task.c.
00375 { 00376 task_t *new_task; 00377 byte *pl0_stack; 00378 dword *PDBR; 00379 dword PDBR_frame, i; 00380 register dword cr3; 00381 00382 sched_enter_critical_region(); 00383 00384 // --- Create the task structure -------------------------------// 00385 //! 00386 //! IA-32 Intel(R) Architecture Software Developer's Manual 00387 //! Volume 3: System Programming Guide - Chapter 6 - reports: 00388 //! 00389 //! "If paging is used, care should be taken to avoid placing a 00390 //! page boundary within the part of the TSS that the processor 00391 //! reads during a task switch (the first 104 bytes). If a page 00392 //! boundary is placed within this part of the TSS, the pages on 00393 //! either side of the boundary must be present at the same time 00394 //! and contiguous in physical memory. 00395 //! 00396 //! The reason for this restriction is that when accessing a TSS 00397 //! during a task switch, the processor reads and writes into 00398 //! the first 104 bytes of each TSS from contiguous physical 00399 //! addresses beginning with the physical address of the first 00400 //! byte of the TSS. It may not perform address translation at a 00401 //! page boundary if one occurs within this area. So, after the 00402 //! TSS access begins, if a part of the 104 bytes is not both 00403 //! present and physically contiguous, the processor will access 00404 //! incorrect TSS information, without generating a page-fault 00405 //! exception. The reading of this incorrect information will 00406 //! generally lead to an unrecoverable exception later in the 00407 //! task switch process..." 00408 new_task = kmemalign(PAGE_SIZE, sizeof(task_t)); 00409 if (new_task == NULL) 00410 { 00411 // Out of virtual memory!!! // 00412 set_color(LIGHT_RED); 00413 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname); 00414 set_color(DEFAULT_COLOR); 00415 00416 sched_leave_critical_region(); 00417 return(NULL); 00418 } 00419 memset(new_task, 0, sizeof(task_t)); 00420 00421 // --- Create the pl0-stack --- // 00422 pl0_stack = kmalloc(STACK_SIZE); 00423 if (pl0_stack == NULL) 00424 { 00425 // Out of virtual memory!!! // 00426 set_color(LIGHT_RED); 00427 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname); 00428 set_color(DEFAULT_COLOR); 00429 // Free the previous allocated space // 00430 kfree((void *)new_task); 00431 00432 sched_leave_critical_region(); 00433 return(NULL); 00434 } 00435 // Null the stack to enforce the page mapping // 00436 memset(pl0_stack, 0, STACK_SIZE); 00437 // Setup the pl0-stack // 00438 new_task->tss.ss0 = KERNEL_STACK; 00439 new_task->tss.esp0 = new_task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t)); 00440 00441 // --- Setup the TSS --- // 00442 new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0); 00443 00444 // --- Create the virtual space of the task ------------------- // 00445 PDBR = (dword *)get_temp_page(); 00446 if ( PDBR == NULL ) 00447 { 00448 // Out of memory!!! Free the previous allocated memory. // 00449 set_color(LIGHT_RED); 00450 kprintf("\n\rOut memory!!! Cannot create task [%s]\n\r", pname); 00451 set_color(DEFAULT_COLOR); 00452 // Free the previous allocated space // 00453 kfree((void *)(pl0_stack)); 00454 kfree((void *)new_task); 00455 // Destroy the TSS // 00456 remove_GDT_entry(new_task->tss_sel); 00457 // Free the 00458 00459 sched_leave_critical_region(); 00460 return(NULL); 00461 } 00462 PDBR_frame = vir_to_phys( (dword)PDBR ); 00463 00464 // Initialize PDBR // 00465 memset(PDBR, 0, PAGE_SIZE); 00466 for (i=K_VIR_START/(PAGE_SIZE*1024); i<1024; i++) 00467 PDBR[i] = K_PDBR[i]; 00468 00469 // Map page directory into itself // 00470 PDBR[1023] = PDBR_frame | P_PRESENT | P_WRITE; 00471 00472 // Unmap the temporary page, without free the physical frame // 00473 free_temp_page(PDBR, FALSE); 00474 00475 // Temporary switch to the new address space // 00476 // // 00477 // QUESTION: cr3 is in the stack... if I switch into the new // 00478 // address space can I ever see the old cr3 value??? // 00479 // // 00480 // RE: Yes, but only if cr3 is stored into a register... // 00481 // And if the value should be stored into the stack, here we // 00482 // are at CPL0, so we're using the 0-privileged stack, so, // 00483 // since the 0-privileged stack space is shared between every // 00484 // task and also the kernel, we're ever able to see the stored // 00485 // cr3 value... // 00486 __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(cr3) : ); 00487 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR_frame)); 00488 00489 // --- Create the user space --- // 00490 00491 // Create the task stack // 00492 new_task->tss.ss = (privilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3; 00493 if ( privilege == KERNEL_PRIVILEGE ) 00494 new_task->tss.esp = new_task->pl0_stack; 00495 else 00496 new_task->tss.esp = (dword)(TASK_STACK_START-sizeof(size_t)); 00497 00498 // Map the user code and data space. // 00499 // ("address" is the virtual task space, "buffer" is the // 00500 // kernel space where the task-code is located). // 00501 if (address != buffer) 00502 { 00503 memcpy(address, buffer, size); 00504 } 00505 00506 // Restore the old address space // 00507 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(cr3)); 00508 00509 // Setup the task PDBR // 00510 new_task->tss.cr3 = PDBR_frame; 00511 00512 // Setup the IO port mapping // 00513 new_task->tss.io_map_addr = sizeof(tss_t); 00514 00515 // Setup general registers // 00516 if ( privilege == KERNEL_PRIVILEGE ) 00517 new_task->tss.ds = new_task->tss.es = 00518 new_task->tss.fs = new_task->tss.gs = KERNEL_DATA; 00519 else 00520 new_task->tss.ds = new_task->tss.es = 00521 new_task->tss.fs = new_task->tss.gs = USER_DATA | 3; 00522 00523 new_task->tss.eflags = EFLAGS_IF | 0x02; 00524 if ( privilege == USER_PRIVILEGE ) 00525 // User tasks must have the I/O privilege level // 00526 // at the lower level // 00527 new_task->tss.eflags |= EFLAGS_IOPL3; 00528 00529 // Initialize general purpose registers // 00530 new_task->tss.eax = new_task->tss.ebx = 00531 new_task->tss.ecx = new_task->tss.edx = 00532 new_task->tss.esi = new_task->tss.edi = 0; 00533 00534 // Initialize LDTR (Local Descriptor Table Register) // 00535 // No LDTs for now... 00536 new_task->tss.ldtr = 0; 00537 00538 // Initialize debug trap // 00539 // If set to 1 the processor generates a debug exception when a // 00540 // task switch to this task occurs... // 00541 new_task->tss.trace = 0; 00542 00543 // Setup starting address // 00544 new_task->tss.cs = (privilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3; 00545 new_task->tss.eip = (dword)address; 00546 00547 // --- Get a pid --- // 00548 new_task->pid = new_pid(); 00549 00550 // --- Store the name --- // 00551 // The last character must be ever '\0' (end of string) // 00552 strncpy(new_task->name, pname, sizeof(new_task->name)-2); 00553 00554 // --- Set the type --- // 00555 new_task->type = PROCESS_T; 00556 00557 // --- Set the parent process --- // 00558 new_task->father = curr_task; 00559 00560 // --- Set the console --- // 00561 if( curr_task ) 00562 new_task->console = curr_task->console; 00563 00564 // --- Insert the task into the ready queue --- // 00565 new_task->state = READY; 00566 add_queue(&ready_queue, new_task); 00567 00568 sched_leave_critical_region(); 00569 return (new_task); 00570 } |
|
The dispatcher.
This routine supplies to change the context of the tasks. It is invoked at every clock tick. Definition at line 1131 of file task.c.
01132 { 01133 task_t *prev_task; 01134 01135 // Call the clock task at every tick // 01136 clock_thread(); 01137 01138 // Can we switch to another process?! // 01139 if ( atomic_read(&sched_enabled) ) 01140 { 01141 // Store the previous task // 01142 prev_task = curr_task; 01143 // Select a new task // 01144 scheduler(); 01145 01146 if ( prev_task != curr_task ) 01147 { 01148 if ( prev_task->tss.cr3 != curr_task->tss.cr3 ) 01149 { 01150 // Update the page directory of the // 01151 // new task with the kernel page // 01152 // directory in the kernel memory area. // 01153 __asm__ __volatile__ ( 01154 "movl %%eax, %%cr3\n" 01155 "cld\n" 01156 "rep movsl\n" 01157 "movl %%ebx, %%cr3" : : 01158 "a"(curr_task->tss.cr3), 01159 "b"(prev_task->tss.cr3), 01160 "D"((dword *)PAGE_DIR_MAP+(K_VIR_START/(PAGE_SIZE*1024))), 01161 "S"((dword *)K_PDBR+(K_VIR_START/(PAGE_SIZE*1024))), 01162 "c"((PAGE_DIR_MAP/(PAGE_SIZE*1024)) - (K_VIR_START/(PAGE_SIZE*1024))) 01163 ); 01164 __asm__("" : : : "%eax", "%ebx", "%ecx", "%edi", "%esi"); 01165 } 01166 01167 // Re-enable master interrupt controller // 01168 outportb(PORT_8259_M, EOI); 01169 // Perform the task switch // 01170 jmp_to_tss(curr_task->tss_sel); 01171 } 01172 } 01173 } |
|
Simply do nothing... This is the default thread to execute when the system has to do nothing. Definition at line 73 of file task.c.
|
|
Get the current task.
Definition at line 203 of file task.c.
00204 {
00205 return( curr_task );
00206 }
|
|
Return the current task pid if there is a curr_task.
Definition at line 186 of file task.c.
|
|
Return the current task name if there is a curr_task.
Definition at line 210 of file task.c.
|
|
Initialize the multitasking management.
Definition at line 1185 of file task.c.
01186 { 01187 // Initialize pid counter. 01188 atomic_set(&last_pid, 0); 01189 01190 // Initialize scheduler critical region flag. 01191 INIT_MUTEX( &sched_enabled ); 01192 01193 // Create the "init" task. 01194 curr_task = create_process(NULL, NULL, 0, "init", KERNEL_PRIVILEGE); 01195 // Set the console. 01196 curr_task->console=1; 01197 // Set the type. 01198 curr_task->type = KTHREAD_T; 01199 01200 // Load task register. 01201 __asm__ __volatile__ ("ltr %%ax" : : "a" (curr_task->tss_sel)); 01202 __asm__ __volatile__ ("" : : : "ax"); 01203 01204 // Load virtual space. 01205 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(curr_task->tss.cr3)); 01206 01207 // Initialize the IDLE task. 01208 // The IDLE task is a special task, 01209 // it's always ready but never present in the ready queue. 01210 idle_task = create_kthread(&do_idle, "idle"); 01211 idle_task->console=0; 01212 rem_queue(&ready_queue, idle_task); 01213 01214 // Initialize KPager thread 01215 kpagd = create_kthread(&kpager, "kpagerd"); 01216 kpagd->console = 0; 01217 01218 // Install the dispatcher. 01219 install_irq_handler( TIMER_IRQ, (void *)&dispatcher ); 01220 } |
|
Return if the scheduling is enabled or not.
Definition at line 1070 of file task.c.
01071 { 01072 if( atomic_read(&sched_enabled) ) 01073 return( TRUE ); 01074 else 01075 return( FALSE ); 01076 } |
|
Kill a task by the pid.
This routine move the task having the pid from the ready queue to the zombie queue. Then the kpager() daemon should provide to free the memory and resources owned by this task. Definition at line 881 of file task.c.
00882 { 00883 // Queues where to search the processes // 00884 static queue_t **q[] = { &ready_queue, &wait_queue }; 00885 task_t *p = curr_task; 00886 bool retval = FALSE; 00887 register int i, j, n; 00888 00889 // No running processes(???) => quit! // 00890 if ( p==NULL ) 00891 return(FALSE); 00892 00893 sched_enter_critical_region(); 00894 00895 // Explore every task queue // 00896 for ( i=0; i<_countof(q); i++) 00897 for ( j=0, n=count_queue(q[i]); j<n; j++ ) 00898 { 00899 // Get the next task in the queue // 00900 p = pick_queue( q[i] ); 00901 00902 if ( p->pid == pid ) 00903 { 00904 // Move the task from the queue to the // 00905 // zombie queue // 00906 if ( rem_queue(q[i], p) ) 00907 { 00908 add_queue(&zombie_queue, p); 00909 p->state = ZOMBIE; 00910 // Wake-up the kpager daemon // 00911 wakeup_task( kpagd ); 00912 // Wake-up the father // 00913 if ( p->father != NULL ) 00914 wakeup_task( p->father ); 00915 // Task killed! // 00916 retval = TRUE; 00917 } 00918 } 00919 else 00920 { 00921 // If the process p is a child of the // 00922 // process to kill we have to set its // 00923 // father to NULL // 00924 if ( p->father != NULL ) 00925 if ( (p->father)->pid == pid ) 00926 p->father = NULL; 00927 } 00928 } 00929 00930 // Check if the task has killed itself // 00931 if (curr_task->pid == pid) 00932 { 00933 sched_leave_critical_region(); 00934 // Wait for the dispatcher // 00935 do_idle(); 00936 } 00937 00938 sched_leave_critical_region(); 00939 return( retval ); 00940 } |
|
Create a new pid.
This routine generate a pid using an atomic increment. Definition at line 178 of file task.c.
00179 { 00180 atomic_inc(&last_pid); 00181 return(atomic_read(&last_pid)); 00182 } |
|
Execute a file creating a new task.
This routine can execute only ELF32 files. The file is loaded in a temporary buffer, then the sections are copied into memory and the task structure is initialized. At the end of this the new task is putted into the ready queue. Definition at line 697 of file task.c.
00698 { 00699 uint32_t temp_PDBR; 00700 task_t *task; 00701 byte *pl0_stack; 00702 size_t PDBR, entry; 00703 void *filebuffer; 00704 int filesize = get_file_size(filename); 00705 00706 if ( filesize < 0 ) 00707 return(NULL); 00708 00709 // Load the ELF32 file into the buffer // 00710 filebuffer = kmalloc(filesize); 00711 if ( elf32_load_file(filename, filebuffer)<0 ) 00712 { 00713 kfree(filebuffer); 00714 return(NULL); 00715 } 00716 00717 sched_enter_critical_region(); 00718 00719 // Create the task structure // 00720 task = kmemalign(PAGE_SIZE, sizeof(task_t)); 00721 if ( task == NULL ) 00722 { 00723 sched_leave_critical_region(); 00724 kfree(filebuffer); 00725 return(NULL); 00726 } 00727 memset(task, 0, sizeof(task_t)); 00728 00729 // Create the PL0-stack // 00730 pl0_stack = kmalloc(STACK_SIZE); 00731 if (pl0_stack == NULL) 00732 { 00733 // Out of virtual memory!!! // 00734 // Free the previous allocated space // 00735 kfree((void *)task); 00736 kfree(filebuffer); 00737 00738 sched_leave_critical_region(); 00739 return(NULL); 00740 } 00741 // Null the stack to enforce the page mapping // 00742 memset(pl0_stack, 0, STACK_SIZE); 00743 00744 // Setup the PL0-stack // 00745 task->tss.ss0 = KERNEL_STACK; 00746 task->tss.esp0 = task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t)); 00747 00748 // Setup the TSS // 00749 task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(task->tss), TSS_SEG, 0); 00750 00751 // Create the new virtual space // 00752 PDBR = new_vspace(); 00753 if ( PDBR == NULL ) 00754 { 00755 // Out of memory !!! // 00756 00757 // Destroy the TSS // 00758 remove_GDT_entry(task->tss_sel); 00759 // Free the previous allocated space // 00760 kfree((void *)(pl0_stack)); 00761 kfree((void *)task); 00762 kfree(filebuffer); 00763 00764 sched_leave_critical_region(); 00765 return(NULL); 00766 } 00767 00768 // Temporary switch to the new address space // 00769 __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(temp_PDBR) : ); 00770 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR)); 00771 00772 // Copy the file sections into memory // 00773 entry = elf32_copy_sections(filebuffer); 00774 if ( entry == NULL ) 00775 { 00776 // Restore the old address space // 00777 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(temp_PDBR)); 00778 00779 // Free the PDBR frame // 00780 push_frame(PDBR/PAGE_SIZE); 00781 // Destroy the TSS // 00782 remove_GDT_entry(task->tss_sel); 00783 // Free the previous allocated space // 00784 kfree((void *)(pl0_stack)); 00785 kfree((void *)task); 00786 kfree(filebuffer); 00787 00788 sched_leave_critical_region(); 00789 return(NULL); 00790 } 00791 00792 // Create the task stack. 00793 task->tss.ss = (privilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3; 00794 if ( privilege == KERNEL_PRIVILEGE ) 00795 task->tss.esp = (uint32_t)task_setup_stack(argc, argv, task->pl0_stack, STACK_SIZE, privilege); 00796 else 00797 task->tss.esp = (uint32_t)task_setup_stack(argc, argv, TASK_STACK_START, STACK_SIZE, privilege); 00798 00799 // Initialize the user heap. 00800 umalloc_init( TASK_HEAP_START, TASK_HEAP_DEFAULT_SIZE ); 00801 00802 // Restore the old address space // 00803 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(temp_PDBR)); 00804 00805 // Setup the task PDBR // 00806 task->tss.cr3 = PDBR; 00807 00808 // Setup the IO port mapping // 00809 task->tss.io_map_addr = sizeof(tss_t); 00810 00811 // Setup general registers // 00812 if ( privilege == KERNEL_PRIVILEGE ) 00813 task->tss.ds = task->tss.es = 00814 task->tss.fs = task->tss.gs = KERNEL_DATA; 00815 else 00816 task->tss.ds = task->tss.es = 00817 task->tss.fs = task->tss.gs = USER_DATA | 3; 00818 00819 task->tss.eflags = EFLAGS_IF | 0x02; 00820 if ( privilege == USER_PRIVILEGE ) 00821 // User privilege must be the I/O privilege set to the // 00822 // lower level // 00823 task->tss.eflags |= EFLAGS_IOPL3; 00824 00825 // Initialize general purpose registers // 00826 task->tss.eax = task->tss.ebx = 00827 task->tss.ecx = task->tss.edx = 00828 task->tss.esi = task->tss.edi = 0; 00829 00830 // Initialize LDTR (Local Descriptor Table Register) // 00831 // No LDTs for now... 00832 task->tss.ldtr = 0; 00833 00834 // Initialize debug trap // 00835 // If set to 1 the processor generate a debug exception when a task switch to this task occurs... 00836 task->tss.trace = 0; 00837 00838 // Setup starting address // 00839 task->tss.cs = (privilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3; 00840 task->tss.eip = entry; 00841 00842 // Get a pid // 00843 task->pid = new_pid(); 00844 00845 // Store the name // 00846 // The last character must be ever '\0' (end of string) // 00847 strncpy(task->name, filename, sizeof(task->name)-2); 00848 00849 // Set the type // 00850 task->type = PROCESS_T; 00851 00852 // Set the parent process // 00853 task->father = curr_task; 00854 00855 // Set the console // 00856 task->console = curr_task->console; 00857 00858 // Insert the task into the ready queue // 00859 task->state = READY; 00860 add_queue(&ready_queue, task); 00861 00862 // Well done! // 00863 kfree(filebuffer); 00864 sched_leave_critical_region(); 00865 00866 return( task ); 00867 } |
|
Print the state of every process from the ready, wait and zombie queues.
Definition at line 1234 of file task.c.
01235 { 01236 task_t *p; 01237 int count, i; 01238 01239 if ((p = curr_task)==NULL) return; 01240 01241 // Header // 01242 kprintf("\n\rPID STATE CONSOLE CMD"); 01243 01244 sched_enter_critical_region(); 01245 01246 // Ready processes // 01247 for(i=0, count=count_queue(&ready_queue); i<count; i++) 01248 { 01249 // Get the next task in the ready queue // 01250 p = pick_queue(&ready_queue); 01251 01252 // Print process informations // 01253 kprintf("\n\r%u", p->pid); 01254 gotoxy(12, -1); 01255 kputchar('R'); 01256 gotoxy(22, -1); 01257 if (p->console) 01258 kprintf("tty%u", p->console); 01259 else 01260 kputchar('?'); 01261 gotoxy(34, -1); 01262 kprintf("%s", p->name); 01263 } 01264 01265 // Wait processes // 01266 for(i=0, count=count_queue(&wait_queue); i<count; i++) 01267 { 01268 // Get the next task in the wait queue // 01269 p = pick_queue(&wait_queue); 01270 01271 // Print process informations // 01272 kprintf("\n\r%u", p->pid); 01273 gotoxy(12, -1); 01274 kputchar('W'); 01275 gotoxy(22, -1); 01276 if (p->console) 01277 kprintf("tty%u", p->console); 01278 else 01279 kputchar('?'); 01280 gotoxy(34, -1); 01281 kprintf("%s", p->name); 01282 } 01283 01284 // Zombie processes // 01285 for(i=0, count=count_queue(&zombie_queue); i<count; i++) 01286 { 01287 // Get the next task in the zombie queue // 01288 p = pick_queue(&zombie_queue); 01289 01290 // Print process informations // 01291 kprintf("\n\r%u", p->pid); 01292 gotoxy(12, -1); 01293 kputchar('Z'); 01294 gotoxy(22, -1); 01295 if (p->console) 01296 kprintf("tty%u", p->console); 01297 else 01298 kputchar('?'); 01299 gotoxy(34, -1); 01300 kprintf("%s", p->name); 01301 } 01302 01303 sched_leave_critical_region(); 01304 01305 kprintf("\n\r"); 01306 } |
|
Disable the scheduling of the other tasks.
Definition at line 1055 of file task.c.
01056 { 01057 DOWN( &sched_enabled ); 01058 } |
|
Re-enable scheduling for the other tasks.
Definition at line 1061 of file task.c.
01062 { 01063 UP( &sched_enabled ); 01064 } |
|
Sleep a process if it is awake.
Definition at line 1024 of file task.c.
|
|
Wait for the exit of a child.
Definition at line 966 of file task.c.
00967 { 00968 // Queues where to search the processes // 00969 static queue_t **q[] = { &ready_queue, &wait_queue }; 00970 task_t *p; 00971 int i, j, n; 00972 bool found = FALSE; 00973 dword IF = GET_IF(); 00974 00975 // A task can't wait for yourself! // 00976 if (curr_task->pid == pid) return(0); 00977 00978 repeat: 00979 sched_enter_critical_region(); 00980 // Search into every task queue // 00981 for( i=0; i<_countof(q); i++ ) 00982 { 00983 for( j=0, n = count_queue( q[i] ); j<n; j++ ) 00984 { 00985 p = pick_queue( q[i] ); 00986 if ( (p->father == curr_task) && ((pid==-1) || (p->pid==pid)) ) 00987 { 00988 // Found! // 00989 found = TRUE; 00990 00991 // Update the pid of the child that we // 00992 // are waiting (when pid is -1). // 00993 pid = p->pid; 00994 00995 // Move the current task (father) into // 00996 // the wait queue and wait // 00997 if ( rem_queue(&ready_queue, curr_task) ) 00998 { 00999 add_queue(&wait_queue, curr_task); 01000 curr_task->state = WAIT; 01001 } 01002 sched_leave_critical_region(); 01003 01004 // Sleeped! // 01005 // Now wait for the dispatcher // 01006 enable(); 01007 idle(); 01008 // Task waked-up! Check if the child // 01009 // that we are waiting is dead // 01010 goto repeat; 01011 } 01012 } 01013 01014 } 01015 sched_leave_critical_region(); 01016 SET_IF(IF); 01017 01018 // Return the child pid or -1 if the process has not been found // 01019 return( (found) ? pid : -1 ); 01020 } |
|
Wakeup a process if it is sleeping.
Definition at line 1031 of file task.c.
|
|
Master page directory.
|