diff options
Diffstat (limited to 'src/kernel/task.c')
-rw-r--r-- | src/kernel/task.c | 203 |
1 files changed, 184 insertions, 19 deletions
diff --git a/src/kernel/task.c b/src/kernel/task.c index 942d1c4..ab08e6b 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,6 +1,8 @@ +#include "paging.h" #include "panic.h" +#include "pmap.h" #include "task.h" -#include "paging.h" +#include "util.h" #include "log.h" struct tss { @@ -42,7 +44,7 @@ struct tss { #define MAX_TASKS 64 -static struct task_state tasks[MAX_TASKS]; +struct task_state tasks[MAX_TASKS]; struct task_state *active_task; void init_tasks() { @@ -68,31 +70,68 @@ uint32_t new_task(struct task_state state) { for (uint8_t n = 0; n < MAX_TASKS; ++n) if (!tasks[n].page_directory) { tasks[n] = state; + tasks[n].waiting = false; + for (uint8_t i = 0; i < MAX_WAITS; ++i) + tasks[n].waits[i].mode = NONE; return n + 1; } PANIC("Maximum number of tasks reached."); } +static void tmp_halt() { +//logf(LOG_INFO, "scheduler halting"); + TSS->esp0 = 0x0003c000; + asm("sti\n" + "hlt\n" + "cli"); + TSS->esp0 = 0x00040000; +//logf(LOG_INFO, "scheduler resumed"); +} + void advance_active_task() { - do +//logf(LOG_INFO, "entered scheduler from \"%s\"", active_task->name); + struct task_state *old_task = active_task; + while (1) { if (++active_task == tasks + MAX_TASKS) active_task = tasks; - while (!active_task->page_directory || active_task->wait_mode); + if (active_task->page_directory && !active_task->waiting) { + //logf(LOG_INFO, "exiting scheduler to \"%s\"", active_task->name); + return; + } + if (active_task == old_task) + tmp_halt(); + } } void make_sure_tasks() { for (uint8_t n = 0; n < MAX_TASKS; ++n) if (tasks[n].page_directory) - while (1) { - for (uint8_t n = 0; n < MAX_TASKS; ++n) - if (tasks[n].page_directory && !tasks[n].wait_mode) - return; - asm ("hlt"); - } - set_log_mode(LOG_SYSTEM); - logsz("No tasks, halting."); + return; + logf(LOG_INFO, "No tasks, halting."); while (1) - asm ("hlt"); + asm("hlt"); +} + +//IPC stuff isn't fully implemented, or tested in this version. +//i'm planning to finish and make use of it in the next version, +//making the terminal its own application instead of a library. + +#define MAX_IPC_PIPES 1024 +#define IPC_BUFFER_PAGES 1 + +struct ipc_pipe { + void *buffer; + void *buffer_next_send; + const void *buffer_next_read; + + uint32_t sender_handle; + uint32_t reader_handle; + bool delete_when_empty; +} ipc_pipes[MAX_IPC_PIPES]; + +void delete_pipe(struct ipc_pipe *pipe) { + free_pages(pipe->buffer, IPC_BUFFER_PAGES); + pipe->buffer = 0; } void delete_task(struct task_state *state) { @@ -101,10 +140,136 @@ void delete_task(struct task_state *state) { switch_to_task_cr3(); state->page_directory = 0; - uint32_t handle = state - tasks + 1; - for (uint8_t n = 0; n < MAX_TASKS; ++n) - if (tasks[n].page_directory && - (tasks[n].wait_mode == PROCESS_END) && - (tasks[n].wait_arg == handle)) - tasks[n].wait_mode = NONE; + unwait_any((struct wait){.mode = PROCESS_END, .task = state}); + unwait_any((struct wait){.mode = IPC_RECEIVE, .task = state}); + unwait_any((struct wait){.mode = IPC_SEND, .task = state}); + + const uint32_t handle = active_task - tasks + 1; + for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe) + if (pipe->buffer) { + if (pipe->reader_handle == handle) + delete_pipe(pipe); + else if (pipe->sender_handle == handle) { + if (pipe->buffer_next_read == pipe->buffer_next_send) + delete_pipe(pipe); + else + pipe->delete_when_empty = true; + } + } +} + +uint32_t find_unread_ipc() { + const uint32_t r_handle = active_task - tasks + 1; + for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe) + if (pipe->buffer && (pipe->reader_handle == r_handle) && + (pipe->buffer_next_read != pipe->buffer_next_send)) + return pipe->sender_handle; + return 0; +} + +struct ipc_pipe *get_existing_pipe(uint32_t sender_handle, uint32_t reader_handle) { + for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i) + if (i->buffer && (i->sender_handle == sender_handle) && + (i->reader_handle == reader_handle)) + return i; + return 0; +} + +uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) { + if (!reader_handle || !tasks[reader_handle - 1].page_directory) + return -1; + + const uint32_t our_handle = active_task - tasks + 1; + struct ipc_pipe *pipe = get_existing_pipe(our_handle, reader_handle); + if (!pipe) { + for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i) + if (!i->buffer) { + i->buffer = allocate_kernel_pages(IPC_BUFFER_PAGES); + i->buffer_next_read = i->buffer; + i->buffer_next_send = i->buffer; + i->reader_handle = reader_handle; + i->sender_handle = our_handle; + i->delete_when_empty = false; + pipe = i; + break; + } + if (!pipe) + PANIC("out of ipc pipes"); + } + + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE, .task = active_task}); + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE_ANY}); + + uint32_t send_left = pipe->buffer_next_read - pipe->buffer_next_send - 1; + if (send_left < 0) + send_left += 4096 * IPC_BUFFER_PAGES; + if (count > send_left) + count = send_left; + + if (pipe->buffer_next_send + count < pipe->buffer + 4096 * IPC_BUFFER_PAGES) { + memcpy(pipe->buffer_next_send, buffer, count); + pipe->buffer_next_send += count; + return count; + } + + const uint32_t first_batch = pipe->buffer + 4096 * IPC_BUFFER_PAGES - pipe->buffer_next_send; + memcpy(pipe->buffer_next_send, buffer, first_batch); + memcpy(pipe->buffer, buffer + first_batch, count - first_batch); + pipe->buffer_next_send += count - 4096; + return count; +} + +uint32_t ipc_read(uint32_t sender_handle, uint32_t count, void *buffer) { + if (!sender_handle || !tasks[sender_handle - 1].page_directory) + return -1; + + const uint32_t our_handle = active_task - tasks + 1; + struct ipc_pipe *pipe = get_existing_pipe(sender_handle, our_handle); + if (!pipe) + return 0; + + unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_SEND, .task = active_task}); + + //TODO +} + +void add_wait(struct wait wait) { + for (uint8_t i = 0; i < MAX_WAITS; ++i) + if (!active_task->waits[i].mode) { + active_task->waits[i] = wait; + active_task->waiting = true; + return; + } + PANIC("Out of waits for task."); +} + +void unwait_any(struct wait wait) { + for (uint8_t i = 0; i < MAX_TASKS; ++i) + if (tasks[i].page_directory) + unwait(tasks + i, wait); +} + +void unwait(struct task_state *task, struct wait wait) { + if (!task->waiting) + return; + for (uint8_t i = 0; i < MAX_WAITS; ++i) { + if (task->waits[i].mode != wait.mode) + continue; + switch (wait.mode) { + case PROCESS_END: + case IPC_RECEIVE: + if (task->waits[i].task != wait.task) + continue; + break; + case WINDOW_ACTION: + case IPC_RECEIVE_ANY: + break; + default: + PANIC("Unwait matched with unrecognized wait mode."); + } + for (uint8_t i = 0; i < MAX_WAITS; ++i) + task->waits[i].mode = NONE; + task->waiting = false; + return; + } }
\ No newline at end of file |