diff --git a/init/main.c b/init/main.c index 88e32b6..402987b 100644 --- a/init/main.c +++ b/init/main.c @@ -129,13 +129,21 @@ char load_task(uint32_t datapos,char* initrd) { // return 1; // } +void thread() { + for (;;) yield(); +} int main() { serial_print("IN INIT\n"); + new_thread(thread); blockTask(TASK_BLOCKED); - for (int i=0;i<4;i++) { + for (int i=0;i<5;i++) { + serial_print("YIELDING\n"); yield(); + serial_print("YIELDED\n"); } + serial_print("EXITING\n"); + exit(0); // long size=initrd_sz(); // char* initrd=malloc(size); // initrd_get(initrd); diff --git a/kernel/cpu/i386/isr.c b/kernel/cpu/i386/isr.c index cf18b1d..c5d08e2 100644 --- a/kernel/cpu/i386/isr.c +++ b/kernel/cpu/i386/isr.c @@ -17,8 +17,6 @@ void irq_handler(registers_t* r); static isr_t interrupt_handlers[256]; -extern Task* currentTask; - /* Can't do this with a loop because we need the address * of the function names */ void isr_install() { @@ -131,47 +129,47 @@ __attribute__((unused)) static char *exception_messages[] = { void isr_handler(registers_t* r) { if (r->int_no!=80 && r->int_no!=14) { - vga_write_string(exception_messages[r->int_no]); + serial_write_string(exception_messages[r->int_no]); } switch (r->int_no) { case 14: { serial_write_string("PAGE FAULT\n"); uint32_t addr; asm("movl %%cr2,%0": "=r"(addr)); - vga_write_string("In PID "); + // serial_write_string("In PID "); char str[11]; - int_to_ascii(getPID(),str); - vga_write_string(str); - vga_write_string(" and address "); + // int_to_ascii(getPID(),str); + // serial_write_string(str); + serial_write_string(" and address "); str[0]='\0'; hex_to_ascii(r->eip,str); - vga_write_string(str); + serial_write_string(str); if (r->err_code==0) { - vga_write_string(", kernel process tried to read a non-present page entry at address "); + serial_write_string(", kernel process tried to read a non-present page entry at address "); } else if (r->err_code==1) { - vga_write_string(", kernel process tried to read a page and caused a protection fault at address "); + serial_write_string(", kernel process tried to read a page and caused a protection fault at address "); } else if (r->err_code==2) { - vga_write_string(", kernel process tried to write to a non-present page entry at address "); + serial_write_string(", kernel process tried to write to a non-present page entry at address "); } else if (r->err_code==3) { - vga_write_string(", kernel process tried to write a page and caused a protection fault at address "); + serial_write_string(", kernel process tried to write a page and caused a protection fault at address "); } else if (r->err_code==4) { - vga_write_string(", user process tried to read a non-present page entry at address "); + serial_write_string(", user process tried to read a non-present page entry at address "); } else if (r->err_code==5) { - vga_write_string(", user process tried to read a page and caused a protection fault at address "); + serial_write_string(", user process tried to read a page and caused a protection fault at address "); } else if (r->err_code==6) { - vga_write_string(", user process tried to write to a non-present page entry at address "); + serial_write_string(", user process tried to write to a non-present page entry at address "); } else if (r->err_code==7) { - vga_write_string(", user process tried to write a page and caused a protection fault at address "); + serial_write_string(", user process tried to write a page and caused a protection fault at address "); } str[0]='\0'; hex_to_ascii(addr,str); - vga_write_string(str); - vga_write_string("."); - vga_write_string(" Stack is at "); + serial_write_string(str); + serial_write_string("."); + serial_write_string(" Stack is at "); str[0]='\0'; hex_to_ascii(r->useresp,str); - vga_write_string(str); - vga_write_string(".\n"); + serial_write_string(str); + serial_write_string(".\n"); // if ((r->err_code&1)==0) { // // int dir_entry=(addr&0xFFC00000)>>22; // // int table_entry=(addr&0x3FF000)>12; @@ -194,16 +192,16 @@ void isr_handler(registers_t* r) { case 80: switch (r->eax) { case SYSCALL_CREATEPROC: - tasking_createTaskCr3KmodeParam((void*)r->ebx,(void*)r->ecx,0,r->edx,r->esi,r->edx,r->edi); + tasking_createTask((void*)r->ebx,(void*)r->ecx,0,r->edx,r->esi,r->edx,r->edi,0); break; case SYSCALL_YIELD: - tasking_yield(r->ebx); + tasking_yield(); break; case SYSCALL_BLOCK: tasking_block(r->ebx); break; case SYSCALL_UNBLOCK: - tasking_unblock(r->ebx); + tasking_unblock(r->ebx,r->ecx); break; case SYSCALL_EXIT: tasking_exit((uint8_t)r->ebx); @@ -222,7 +220,7 @@ void isr_handler(registers_t* r) { } break; case SYSCALL_PRIV_MAP_PAGES: - if (!currentTask->priv) { + if (tasking_isPrivleged()) { r->ebx=0; return; } @@ -252,6 +250,9 @@ void isr_handler(registers_t* r) { serial_printf("Copying initrd\n"); memcpy((char*)r->ebx,initrd,initrd_sz); break; + case SYSCALL_NEW_THREAD: + tasking_new_thread((void*)r->ebx); + break; default: break; } diff --git a/kernel/cpu/i386/paging.c b/kernel/cpu/i386/paging.c index 9acd9a8..9e7c41f 100644 --- a/kernel/cpu/i386/paging.c +++ b/kernel/cpu/i386/paging.c @@ -9,11 +9,11 @@ static uint32_t page_directory[1024] __attribute__((aligned(4096))); static uint32_t kern_page_tables[NUM_KERN_DIRS*1024] __attribute__((aligned(4096))); -static uint32_t kstack_page_tables[32*1024] __attribute__((aligned(4096))); +static uint32_t kstack_page_tables[218*1024] __attribute__((aligned(4096))); static uint32_t kmalloc_page_tables[4*1024] __attribute__((aligned(4096))); static uint32_t smap_page_tables[2048] __attribute__((aligned(4096))); static uint32_t* smap=(uint32_t*)0xFF800000; - +static uint32_t kstack_bmap[(218*1024)/8]; static char is_page_present(int page) { int table=page>>10; page=page&0x3FF; @@ -50,10 +50,42 @@ void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,ch } } -void map_kstack(uint32_t pid) { - if (!(kstack_page_tables[pid]&0x1)) { - kstack_page_tables[pid]=(uint32_t)pmem_alloc(1)|0x3; + +static char get_bmap_bit(uint32_t index) { + uint32_t byte=index/8; + uint32_t bit=index%8; + char entry=kstack_bmap[byte]; + return (entry&(1<0; +} + +static void set_bmap_bit(uint32_t index) { + uint32_t byte=index/8; + uint32_t bit=index%8; + kstack_bmap[byte]=kstack_bmap[byte]|(1< #include "paging_helpers.h" -#define NUM_KERN_DIRS 1 +#define NUM_KERN_DIRS 4 void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,char wr); -void map_kstack(uint32_t pid); +int new_kstack(); void unmap_pages(void* start_virt,uint32_t num_pages); void* alloc_pages(int num_pages); void alloc_pages_virt(int num_pages,void* addr); @@ -16,6 +16,7 @@ void* paging_new_address_space(); void load_address_space(uint32_t cr3); void* virt_to_phys(void* virt_addr); void* find_free_pages(int num_pages); +void* find_free_pages_wstart(int num_pages,int start_page); void load_smap(uint32_t cr3); char make_protector(int page); char is_in_protector(uint32_t* addr); diff --git a/kernel/cpu/i386/tasking.c b/kernel/cpu/i386/tasking.c index 65d0786..e903c9b 100644 --- a/kernel/cpu/i386/tasking.c +++ b/kernel/cpu/i386/tasking.c @@ -1,254 +1,358 @@ -#include "tasking_helpers.h" #include "tasking.h" #include "../tasking.h" -#include "isr.h" -#include -#include -#include "kmalloc.h" -#include "memory.h" -#include "gdt.h" -#include "paging.h" -#include -#include -#include "../halt.h" -#include "serial.h" -#include "../../vga_err.h" #include -#define STACK_PAGES 2 - -extern void task_init(); -static uint32_t* kstacks=(uint32_t*)0xF6800000; - - +#include "kmalloc.h" +#include "serial.h" +#include "../halt.h" +#include "paging.h" +#include "tasking_helpers.h" +#define MAX_PROCS 32768 +#define HAS_UNBLOCKED_THREADS(proc) (proc->numThreads!=proc->numThreadsBlocked) +#define NUM_UNBLOCKED_THREADS(proc) (proc->numThreads-proc->numThreadsBlocked) +#define SAME_PROC(thread1,thread2) (thread1->process->pid==thread2->process->pid) +#define SAME_THREAD(thread1,thread2) (thread1->process->pid==thread2->process->pid&&thread1->tid==thread2->tid) uint32_t next_pid=0; -uint32_t running_blocked_tasks=0; -Task* currentTask=NULL; -static Task* readyToRunHead=NULL; -static Task* readyToRunTail=NULL; -static Task* exitedTasksHead=NULL; -static Task* exitedTasksTail=NULL; -static Task* tasks[32768]; -Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg); +uint32_t num_procs=0; +Process* processes[MAX_PROCS]; +char proc_schedule_bmap[MAX_PROCS/8]; +Thread* currentThread; +static Thread* readyToRunHead=NULL; +static Thread* readyToRunTail=NULL; +static uint32_t* kstacks=(uint32_t*)0xC8000000; -void tasking_init(void* esp) { - tasking_createTaskCr3KmodeParam(NULL,paging_new_address_space(),1,0,0,0,0); +static char is_proc_scheduled(uint32_t index) { + uint32_t byte=index/8; + uint32_t bit=index%8; + char entry=proc_schedule_bmap[byte]; + return (entry&(1<0; } -Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg) { - if (next_pid>1024*32) { - serial_printf("Failed to create a task, as 32k tasks have been created already.\n"); - halt(); //Cannot ever create more than 32k tasks, as I don't currently reuse PIDs. +static void mark_proc_scheduled(uint32_t index) { + if (is_proc_scheduled(index)) { + serial_printf("Attempt to schedule a thread in a process with a scheduled thread! (PID %d)\n",index); + halt(); + } + uint32_t byte=index/8; + uint32_t bit=index%8; + proc_schedule_bmap[byte]=proc_schedule_bmap[byte]|(1<MAX_PROCS && !isThread) { + serial_printf("Failed to create a process, as 32k processes have been created already.\n"); + halt(); //Cannot ever create more than 32k processes, as I don't currently reuse PIDs. + } + uint32_t param1; + if (param1_exists) { + param1=param1_arg; + } else { + param1=1; + } + uint32_t param2; + if (param2_exists) { + if (isThread) { + serial_printf("Param2 in Thread!\n"); + halt(); } - Task* task=kmalloc(sizeof(Task)); - map_kstack(next_pid); - uint32_t param1; - if (param1_exists) { - param1=param1_arg; + param2=param2_arg; + } else { + param2=2; + } + Process* proc; + Thread* thread=kmalloc(sizeof(Thread)); + if (isThread) { + proc=processes[(pid_t)param2_arg]; + proc->numThreads++; + thread->cr3=proc->firstThread->cr3; + } else { + proc=kmalloc(sizeof(Process)); + if (currentThread) { + proc->priv=currentThread->process->priv; } else { - param1=1; + proc->priv=1; } - uint32_t param2; - if (param2_exists) { - param2=param2_arg; - } else { - param2=2; - } - task->cr3=(uint32_t)cr3; - uint32_t old_cr3; - asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(old_cr3)::"%eax"); - load_address_space(task->cr3); - if (kmode) { - uint32_t top_idx=(1024*(next_pid+1)); - task->kernel_esp=((uint32_t)(&kstacks[top_idx-5])); - task->kernel_esp_top=task->kernel_esp; - kstacks[top_idx-5]=0; - kstacks[top_idx-4]=0; - kstacks[top_idx-3]=0; - kstacks[top_idx-2]=0; - kstacks[top_idx-1]=(uint32_t)eip; - } else { - uint32_t top_idx=(1024*(next_pid+1)); - task->kernel_esp=((uint32_t)(&kstacks[top_idx-7])); - task->kernel_esp_top=task->kernel_esp; - kstacks[top_idx-7]=0; - kstacks[top_idx-6]=0; - kstacks[top_idx-5]=0; - kstacks[top_idx-4]=0; - kstacks[top_idx-3]=(uint32_t)task_init; - uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(2))+0x2000); - int buffer_pg_num=(((uint32_t)user_stack)-0x2000)>>12; - make_protector(buffer_pg_num); - // uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(1))+0x1000); - user_stack-=2; - user_stack[0]=param1; - user_stack[1]=param2; - kstacks[top_idx-2]=(uint32_t)user_stack; - kstacks[top_idx-1]=(uint32_t)eip; - } - load_address_space(old_cr3); - task->next=NULL; - task->pid=next_pid; - task->priv=0; - task->errno=0; - if (currentTask) { - task->priv=currentTask->priv; - } - if (task->pid==1) { - task->priv=1; - } - task->prev=NULL; - task->next=NULL; - if (readyToRunTail) { - task->state=TASK_READY; - readyToRunTail->next=task; - task->prev=readyToRunTail; - readyToRunTail=task; - } else if (currentTask) { - task->state=TASK_READY; - readyToRunHead=task; - readyToRunTail=task; - } else { - task->state=TASK_RUNNING; - currentTask=task; - } - tasks[next_pid]=task; + proc->pid=next_pid; next_pid++; - running_blocked_tasks++; - if (task->pid!=0) { - serial_printf("Created task with PID %d.\n",task->pid); + proc->next_tid=0; + proc->numThreads=1; + proc->numThreadsBlocked=0; + proc->firstThread=thread; + processes[proc->pid]=proc; + thread->cr3=cr3; + } + thread->process=proc; + thread->errno=0; + thread->tid=proc->next_tid; + proc->next_tid++; + void* old_cr3; + asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(old_cr3)::"%eax"); + uint32_t kstack_num=new_kstack(); + load_address_space((uint32_t)thread->cr3); + if (kmode) { + uint32_t top_idx=(1024*(kstack_num+1)); + thread->kernel_esp=((uint32_t)(&kstacks[top_idx-5])); + thread->kernel_esp_top=thread->kernel_esp; + kstacks[top_idx-1]=(uint32_t)eip; + } else { + uint32_t top_idx=(1024*(kstack_num+1)); + thread->kernel_esp=((uint32_t)(&kstacks[top_idx-7])); + thread->kernel_esp_top=thread->kernel_esp; + kstacks[top_idx-3]=(uint32_t)task_init; + uint32_t* user_stack=(uint32_t*)(((uint32_t)alloc_pages(2))+0x2000); + int buffer_pg_num=(((uint32_t)user_stack)-0x2000)>>12; + make_protector(buffer_pg_num); + user_stack-=2; + user_stack[0]=param1; + user_stack[1]=param2; + kstacks[top_idx-2]=(uint32_t)user_stack; + kstacks[top_idx-1]=(uint32_t)eip; + } + load_address_space((uint32_t)old_cr3); + thread->prevReadyToRun=NULL; + thread->nextReadyToRun=NULL; + if (isThread) { + thread->nextThreadInProcess=proc->firstThread; + thread->prevThreadInProcess=NULL; + thread->state=THREAD_READY; + proc->firstThread->prevThreadInProcess=thread; + proc->firstThread=thread; + } else { + thread->nextThreadInProcess=NULL; + thread->prevThreadInProcess=NULL; + if (!is_proc_scheduled(proc->pid)) { + if (readyToRunTail) { + thread->state=THREAD_READY; + readyToRunTail->nextReadyToRun=thread; + thread->prevReadyToRun=readyToRunTail; + readyToRunTail=thread; + mark_proc_scheduled(proc->pid); + } else if (currentThread) { + thread->state=THREAD_READY; + readyToRunHead=thread; + readyToRunTail=thread; + mark_proc_scheduled(proc->pid); + } else { + thread->state=THREAD_RUNNING; + currentThread=thread; + } } - return task; + } + if (!isThread) { + num_procs++; + } + serial_printf("Created thread with PID %d and TID %d.\n",proc->pid,thread->tid); +} + +void tasking_init() { + void* cr3; + asm volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(cr3)::"%eax"); + tasking_createTask(NULL,cr3,1,0,0,0,0,0); +} + +char tasking_isPrivleged() { + return currentThread->process->priv; +} + +pid_t getPID() { + return currentThread->process->pid; } int* tasking_get_errno_address() { - return &(currentTask->errno); -} -char isPrivleged(uint32_t pid) { - for (Task* task=readyToRunHead;task!=NULL;task=task->next) { - if (task->pid==pid) { - return task->priv; - } - } - return 0; + return ¤tThread->errno; } -Task* tasking_createTask(void* eip) { - return tasking_createTaskCr3KmodeParam(eip,paging_new_address_space(),0,0,0,0,0); +void tasking_new_thread(void* start) { + tasking_createTask(start,NULL,0,0,0,0,getPID(),1); } -void switch_to_task(Task* task) { - if (task!=readyToRunHead) { - // Unlink it from the doubly-linked list of ready-to-run tasks - task->prev->next=task->next; - if (task->next) { - task->next->prev=task->prev; +void switch_to_thread(Thread* thread) { + // Unlink the thread from the list of ready-to-run threads + if (thread!=readyToRunHead) { + thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun; + if (thread->nextReadyToRun) { + thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun; } } else { - // Unlink the task from the list by advancing the ready to run pointer to the next task - readyToRunHead=task->next; - // If the task did not have a next task, also clear the ready to run tail pointer + readyToRunHead=thread->nextReadyToRun; if (readyToRunHead==NULL) { readyToRunTail=NULL; } } - task->prev=NULL; - task->next=NULL; - task->state=TASK_RUNNING; - if (currentTask->state==TASK_RUNNING) { - currentTask->state=TASK_READY; - // Link the task onto the list of ready to run tasks - if (readyToRunTail) { - currentTask->prev=readyToRunTail; - readyToRunTail->next=currentTask; - readyToRunTail=currentTask; - } else { - readyToRunHead=currentTask; - readyToRunTail=currentTask; + unmark_proc_scheduled(thread->process->pid); + thread->prevReadyToRun=NULL; + thread->nextReadyToRun=NULL; + if (currentThread->state==THREAD_RUNNING) { + currentThread->state=THREAD_READY; + } + Thread* currentThreadNextReady=currentThread->nextThreadInProcess; + while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) { + currentThreadNextReady=currentThreadNextReady->nextThreadInProcess; + } + if (!currentThreadNextReady) { + currentThreadNextReady=currentThread->process->firstThread; + while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) { + currentThreadNextReady=currentThreadNextReady->nextThreadInProcess; } } - serial_printf("Yielding to PID %d.\n",task->pid); - load_smap(task->cr3); - switch_to_task_asm(task); -} - -void tasking_yield(pid_t pid) { - if (pid==0) { - if (!readyToRunHead) { - if (currentTask->state!=TASK_RUNNING) { - //This indicates either all tasks are bloked or the os has shutdown. Check which one it is - if (running_blocked_tasks==0) { - serial_printf("All tasks exited, halting\n"); - halt(); //never returns, so we dont need an else - } - serial_printf("All tasks blocked, waiting for interrupt to unblock task\n"); - // All tasks blocked - // Stop running the current task by setting currentTask to null, though put it in a local variable to keep track of it. - Task* task=currentTask; - currentTask=NULL; - // Wait for an IRQ whose handler unblocks a task - do { - asm volatile("sti"); - asm volatile("hlt"); - asm volatile("cli"); - } while (readyToRunHead==NULL); - currentTask=task; - } else { - serial_printf("Yield failed, no other ready tasks\n"); - return; + if (!currentThreadNextReady) { + //This process is fully blocked, try the process of the thread we're yielding to + currentThreadNextReady=thread->nextThreadInProcess; + while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) { + currentThreadNextReady=currentThreadNextReady->nextThreadInProcess; + } + if (!currentThreadNextReady) { + currentThreadNextReady=thread->process->firstThread; + while ((currentThreadNextReady&¤tThreadNextReady->state!=THREAD_READY)||(currentThreadNextReady&&SAME_THREAD(thread,currentThreadNextReady))) { + currentThreadNextReady=currentThreadNextReady->nextThreadInProcess; } } - switch_to_task(readyToRunHead); - } else { - serial_printf("Attempting to yield to PID %d",pid); - Task* task=tasks[pid]; - if (!task) { - serial_printf("PID %d does not exist.\n",pid); - return; - } - if (task->state!=TASK_READY) { - serial_printf("PID %d is blocked"); - return; - } - switch_to_task(task); } -} -void tasking_exit(uint8_t code) { - serial_printf("PID %d is exiting with code %d.\n",currentTask->pid,code); - currentTask->state=TASK_EXITED; - if (exitedTasksHead) { - exitedTasksTail->next=currentTask; - currentTask->prev=exitedTasksHead; - exitedTasksTail=currentTask; - } else { - exitedTasksHead=currentTask; - exitedTasksTail=currentTask; - } - running_blocked_tasks--; - tasking_yield(0); -} - -uint32_t getPID() { - return currentTask->pid; -} - -void tasking_block(TaskState newstate) { - if (newstate==TASK_RUNNING || newstate==TASK_READY || newstate==TASK_EXITED) { - serial_printf("Attempted to block task using a new state of running/ready/exited. This is an error.\n"); - return; - } - serial_printf("Blocking PID %d with state %d\n",currentTask->pid,currentTask->state); - currentTask->state = newstate; - tasking_yield(0); -} - -void tasking_unblock(pid_t pid) { - serial_printf("Unblocking PID %d\n",pid); - tasks[pid]->state=TASK_READY; - if(readyToRunHead) { - readyToRunTail->next=tasks[pid]; - readyToRunTail=tasks[pid]; + if (currentThreadNextReady && !is_proc_scheduled(currentThread->process->pid)) { + // Link the task onto the list of ready to run tasks + if (readyToRunTail) { + currentThreadNextReady->prevReadyToRun=readyToRunTail; + readyToRunTail->nextThreadInProcess=currentThreadNextReady; + readyToRunTail=currentThreadNextReady; } else { - readyToRunHead=tasks[pid]; - readyToRunTail=tasks[pid]; + readyToRunHead=currentThreadNextReady; + readyToRunTail=currentThreadNextReady; } + mark_proc_scheduled(currentThread->process->pid); + } + serial_printf("Switching to PID %d TID %d.\n",thread->process->pid,thread->tid); + load_smap((uint32_t)thread->cr3); + switch_to_thread_asm(thread); +} + +void tasking_yield() { + serial_printf("Attempting to yield\n"); + if (readyToRunHead) { + serial_printf("Attempting to switch to PID %d TID %d\n",readyToRunHead->process->pid,readyToRunHead->tid); + switch_to_thread(readyToRunHead); + } else { + if (NUM_UNBLOCKED_THREADS(currentThread->process)>1) { + serial_printf("The ready to run list is empty, and the current process has other unblocked threads? This is an invalid state! Halting!\n"); + halt(); + } else if (NUM_UNBLOCKED_THREADS(currentThread->process)==1) { + serial_printf("Yield failed, no other ready processes\n"); + return; + } else { + if (num_procs==0) { + serial_printf("All processes exited, halting\n"); + halt(); + } else { + serial_printf("All threads in all processes blocked, waiting for an IRQ which unblocks a thread\n"); + // All threads in all processes blocked, so wait for an IRQ whose handler unblocks a thread. + do { + asm volatile("sti"); //As interrupts are stopped, re-enable them. + asm volatile("hlt"); //Wait for an interrupt handler to run and return. + asm volatile("cli"); //Clear interrupts, as tasking code must not be interrupted. + } while (readyToRunHead==NULL); + } + serial_printf("Attempting to switch to PID %d TID %d\n",readyToRunHead->process->pid,readyToRunHead->tid); + switch_to_thread(readyToRunHead); + } + } +} + +void tasking_block(ThreadState newstate) { + if (readyToRunHead&&SAME_THREAD(readyToRunHead,currentThread)) { + readyToRunHead=readyToRunHead->nextReadyToRun; + if (readyToRunHead==NULL) { + readyToRunTail=NULL; + } + } + if (readyToRunTail&&SAME_THREAD(readyToRunTail,currentThread)) { + readyToRunTail=readyToRunTail->prevReadyToRun; + if (readyToRunTail==NULL) { + readyToRunHead=NULL; + } + } + if (readyToRunHead&&readyToRunHead->nextReadyToRun) { + for (Thread* thread=readyToRunHead->nextReadyToRun;thread!=NULL;thread=thread->nextReadyToRun) { + if (SAME_THREAD(thread,currentThread)) { + thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun; + if (thread->nextReadyToRun) { + thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun; + } + break; + } + } + } + for (Thread* thread=currentThread->process->firstThread;thread!=NULL;thread=thread->nextThreadInProcess) { + if (thread->tid==currentThread->tid) { + thread->state=newstate; + } + } +} +void tasking_unblock(pid_t pid,uint32_t tid) { + serial_printf("Unblocking PID %d TID %d\n",pid,tid); + if (!processes[pid]) { + serial_printf("PID %d does not exist!\n",pid); + } + Thread* thread=processes[pid]->firstThread; + for (;thread!=NULL;thread=thread->nextThreadInProcess) { + if (thread->tid==tid) { + break; + } + } + if (!thread) { + serial_printf("PID %d TID %d does not exist!\n",pid,thread); + } + if (thread->tid!=tid) { + serial_printf("Error! Got wrong thread! (Wanted TID %d, got TID %d)\n",tid,thread->tid); + halt(); + } + thread->state=THREAD_READY; + if (!is_proc_scheduled(thread->process->pid)) { + // Link the task onto the list of ready to run tasks + if (readyToRunTail) { + thread->prevReadyToRun=readyToRunTail; + readyToRunTail->nextThreadInProcess=thread; + readyToRunTail=thread; + } else { + readyToRunHead=thread; + readyToRunTail=thread; + } + mark_proc_scheduled(thread->process->pid); + } +} + +void tasking_exit(uint8_t code) { + serial_printf("PID %d is exiting with code %d.\n",currentThread->process->pid,code); + if (readyToRunHead&&SAME_PROC(readyToRunHead,currentThread)) { + readyToRunHead=readyToRunHead->nextReadyToRun; + if (readyToRunHead==NULL) { + readyToRunTail=NULL; + } + } + if (readyToRunTail&&SAME_PROC(readyToRunTail,currentThread)) { + readyToRunTail=readyToRunTail->prevReadyToRun; + if (readyToRunTail==NULL) { + readyToRunHead=NULL; + } + } + if (readyToRunHead&&readyToRunHead->nextReadyToRun) { + for (Thread* thread=readyToRunHead->nextReadyToRun;thread!=NULL;thread=thread->nextReadyToRun) { + if (SAME_PROC(thread,currentThread)) { + thread->prevReadyToRun->nextReadyToRun=thread->nextReadyToRun; + if (thread->nextReadyToRun) { + thread->nextReadyToRun->prevReadyToRun=thread->prevReadyToRun; + } + break; + } + } + } + for (Thread* thread=currentThread->process->firstThread;thread!=NULL;thread=thread->nextThreadInProcess) { + thread->state=THREAD_EXITED; + } + currentThread->process->numThreadsBlocked=currentThread->process->numThreads; + num_procs--; + tasking_yield(); } diff --git a/kernel/cpu/i386/tasking.h b/kernel/cpu/i386/tasking.h index f2c1d2d..8fe7f7c 100644 --- a/kernel/cpu/i386/tasking.h +++ b/kernel/cpu/i386/tasking.h @@ -4,24 +4,37 @@ #include #ifndef TASKING_H -typedef enum TaskState { - TASK_RUNNING, - TASK_READY, - TASK_EXITED, - TASK_BLOCKED -} TaskState; +typedef enum ThreadState { + THREAD_RUNNING, + THREAD_READY, + THREAD_EXITED, + THREAD_BLOCKED +} ThreadState; #endif -typedef struct Task { + +struct Thread; + +typedef struct Process { + char priv; + uint32_t pid; + uint32_t next_tid; + int numThreads; + int numThreadsBlocked; + struct Thread* firstThread; +} Process; + +typedef struct Thread { uint32_t kernel_esp; uint32_t kernel_esp_top; - uint32_t cr3; - uint32_t user_esp; - char priv; + void* cr3; //In thread to make the task switch asm easier + uint32_t tid; + ThreadState state; int errno; - uint32_t pid; - struct Task* prev; - struct Task* next; - TaskState state; -} Task; + struct Thread* nextThreadInProcess; + struct Thread* prevThreadInProcess; + struct Thread* nextReadyToRun; + struct Thread* prevReadyToRun; + Process* process; +} Thread; #endif diff --git a/kernel/cpu/i386/tasking_helpers.asm b/kernel/cpu/i386/tasking_helpers.asm index 0d44e3e..f44bd0b 100644 --- a/kernel/cpu/i386/tasking_helpers.asm +++ b/kernel/cpu/i386/tasking_helpers.asm @@ -1,10 +1,10 @@ section .text -global switch_to_task_asm -extern currentTask +global switch_to_thread_asm +extern currentThread extern tss ;WARNING: Caller is expected to disable IRQs before calling, and enable IRQs again after function returns -switch_to_task_asm: +switch_to_thread_asm: ;Save previous task's state @@ -19,13 +19,13 @@ switch_to_task_asm: push edi push ebp - mov edi,[currentTask] ;edi = address of the previous task's data structure + mov edi,[currentThread] ;edi = address of the previous task's data structure mov [edi],esp ;Save ESP for the task's kernel stack in the task's data structure ;Load next task's state mov esi,[esp+(4+1)*4] ;esi = address of the next task's data structure - mov [currentTask],esi ;Current task's task data is the next task thread data + mov [currentThread],esi ;Current task's task data is the next task thread data mov esp,[esi] ;Load ESP for next task's kernel stack from the task's data structure mov eax,[esi+8] ;eax = address of page directory for next task diff --git a/kernel/cpu/i386/tasking_helpers.h b/kernel/cpu/i386/tasking_helpers.h index 1b172fe..70a2fc1 100644 --- a/kernel/cpu/i386/tasking_helpers.h +++ b/kernel/cpu/i386/tasking_helpers.h @@ -3,6 +3,7 @@ #include "tasking.h" -void switch_to_task_asm(Task* task); +void switch_to_thread_asm(Thread* thread); +void task_init(); #endif diff --git a/kernel/cpu/tasking.h b/kernel/cpu/tasking.h index 567f607..930afbc 100644 --- a/kernel/cpu/tasking.h +++ b/kernel/cpu/tasking.h @@ -4,16 +4,17 @@ #include "i386/tasking.h" #include "i386/isr.h" #include +#include "../rpc.h" +void tasking_createTask(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg,char isThread); void tasking_init(); -void tasking_yield(pid_t pid); //set pid to 0 for normal scheduling -Task* tasking_createTask(void* eip); -Task* tasking_createTaskCr3KmodeParam(void* eip,void* cr3,char kmode,char param1_exists,uint32_t param1_arg,char param2_exists,uint32_t param2_arg); -char isPrivleged(uint32_t pid); -uint32_t getPID(); -void tasking_exit(uint8_t code); -void tasking_block(TaskState newstate); -void tasking_unblock(pid_t pid); +char tasking_isPrivleged(); +pid_t getPID(); int* tasking_get_errno_address(); +void tasking_new_thread(void* start); +void tasking_exit(uint8_t code); +void tasking_block(ThreadState newstate); +void tasking_unblock(pid_t pid,uint32_t tid); +void tasking_yield(); #endif diff --git a/kernel/kernel.c b/kernel/kernel.c index 2cc7c11..c257cb5 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -106,7 +106,7 @@ void kmain(struct multiboot_boot_header_tag* hdr) { for (int i=0;i<4;i++) { yield(); } - unblockTask(1); + unblockTask(1,0); for (int i=0;i<4;i++) { yield(); } diff --git a/kernel/rpc.c b/kernel/rpc.c index f7ce7f4..4240c69 100644 --- a/kernel/rpc.c +++ b/kernel/rpc.c @@ -1,8 +1,37 @@ -#include "cpu/tasking.h" -#include -#include "rpc.h" -void rpc_init_struct(TaskRPCStruct* info) { - info->pendingrpc = 0; - info->callingpid = 0; -} +// #include "cpu/tasking.h" +// #include +// #include "rpc.h" +// #include "cpu/i386/serial.h" +// #include "cpu/halt.h" +// void rpc_init_struct(TaskRPCStruct* info) { +// for (size_t i = 0; i < 32; i++) { +// info->funcs[i].code=NULL; +// memset(info->funcs[i].name,'\0',32); +// } +// info->rpc_response=NULL; +// info->next_func=0; +// } +// void rpc_reg_func(void* (*code)(void*),char* name) { +// if (strlen(name)>31) { +// serial_printf("Max length for RPC function name is 31!\n"); +// halt(); +// } +// TaskRPCStruct* info=tasking_get_rpc_struct(0); +// if (info->next_func==32) { +// serial_printf("Maximum # of RPC functions registered\n"); +// halt(); +// } +// info->funcs[info->next_func].code=code; +// strcpy(info->funcs[info->next_func].name,name); +// info->next_func++; +// } + +// void rpc_call(char* name,pid_t pid,void* data) { +// if (strlen(name)>31) { +// serial_printf("Max length for RPC function name is 31!\n"); +// halt(); +// } +// TaskRPCStruct* info=tasking_get_rpc_struct(pid); +// int func_idx; +// } diff --git a/kernel/rpc.h b/kernel/rpc.h index 597168c..9a5cd39 100644 --- a/kernel/rpc.h +++ b/kernel/rpc.h @@ -3,15 +3,16 @@ typedef struct RPCFuncInfo { char name[32]; - char* (*code)(char*); + void* (*code)(void*); } RPCFuncInfo; typedef struct TaskRPCStruct { - int pendingrpc; - int callingpid; -} TaskRPCStruct; + RPCFuncInfo funcs[32]; + int next_func; + void* rpc_response; +} ThreadRPCStruct; -void rpc_init_struct(TaskRPCStruct* info); +void rpc_init_struct(ThreadRPCStruct* info); #endif diff --git a/libc/dbg.c b/libc/dbg.c index a745174..6004188 100644 --- a/libc/dbg.c +++ b/libc/dbg.c @@ -1,6 +1,11 @@ +#include + +#define QUAUX(X) #X +#define QU(X) QUAUX(X) + void serial_print(char* str) { asm volatile(" \ - mov $16, %%eax; \ + mov $" QU(SYSCALL_SERIAL_PRINT) ", %%eax; \ int $80; \ "::"b"(str)); } diff --git a/libc/tasking.c b/libc/tasking.c index bd773fc..1ea4dd5 100644 --- a/libc/tasking.c +++ b/libc/tasking.c @@ -51,9 +51,16 @@ void blockTask(TaskState state) { "::"b"(state)); } -void unblockTask(pid_t pid) { +void unblockTask(pid_t pid,uint32_t tid) { asm volatile(" \ mov $" QU(SYSCALL_UNBLOCK) ", %%eax; \ int $80; \ - "::"b"(pid)); + "::"b"(pid),"c"(tid)); +} + +void new_thread(void* start) { + asm volatile(" \ + mov $" QU(SYSCALL_NEW_THREAD) ", %%eax; \ + int $80; \ + "::"b"(start)); } diff --git a/sysroot/usr/include/sys/syscalls.h b/sysroot/usr/include/sys/syscalls.h index a3d642b..425ec5d 100644 --- a/sysroot/usr/include/sys/syscalls.h +++ b/sysroot/usr/include/sys/syscalls.h @@ -9,6 +9,7 @@ #define SYSCALL_EXIT 4 #define SYSCALL_GET_ERRNO_ADDR 5 #define SYSCALL_GET_PID 6 +#define SYSCALL_NEW_THREAD 14 #define SYSCALL_ALLOC_MEM 7 #define SYSCALL_PRIV_MAP_PAGES 8 diff --git a/sysroot/usr/include/tasking.h b/sysroot/usr/include/tasking.h index 7e6f6d8..07e5538 100644 --- a/sysroot/usr/include/tasking.h +++ b/sysroot/usr/include/tasking.h @@ -20,7 +20,7 @@ void createTaskCr3(void* task,void* cr3); void createTaskCr3Param(void* task,void* cr3,uint32_t param1,uint32_t param2); char isPrivleged(uint32_t pid); void blockTask(TaskState state); -void unblockTask(pid_t pid); +void unblockTask(pid_t pid,uint32_t tid); #endif