Tasklets; fix dead sleep; kernel serial console

- Tasklets are essentially kernel threads. Still working on passing
  arguments to them, but they essentially just run functions and have
  special names like [[kttydebug]]. Eventually, I want disk scheduling
  and various (non-interrupt-driven) drivers running on these, but I'm
  still not sure how stable they are.
- Fix the scheduler so it supports not having anything to run. This took
  some tracking of what's running, and then inserting some liberal
  sleeps. Doesn't appear to break anything. Makes the system work when
  you try to sleep with only one process "running", so that's good.
- Start working on reimplementing the old kernel shell, but this time as
  a tasklet running in the background over serial. Probably going to try
  to add all the same features as before (tab completion, history, rich
  editing), but it may take some time to get it all in there. This
  console is mostly focused on helping with debugging EXT2 and other
  future stuff.
This commit is contained in:
Kevin Lange 2013-11-27 19:11:58 -08:00
parent 8dfd4ff20a
commit 10f4cc6811
5 changed files with 161 additions and 4 deletions

View File

@ -90,6 +90,7 @@ typedef struct process {
sig_table_t signals; /* Signal table */
uint8_t finished; /* Status indicator */
uint8_t started;
uint8_t running;
struct regs * syscall_registers; /* Registers at interrupt */
list_t * wait_queue;
list_t * shm_mappings; /* Shared memory chunk mappings */
@ -98,6 +99,7 @@ typedef struct process {
char * signal_kstack;
node_t sched_node;
node_t sleep_node;
uint8_t is_tasklet;
} process_t;
typedef struct {
@ -132,4 +134,7 @@ volatile process_t * current_process;
list_t * process_list;
typedef void (*tasklet_t) (void *);
int create_kernel_tasklet(tasklet_t tasklet, char * name);
#endif

View File

@ -163,6 +163,9 @@ int main(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) {
}
}
/* Start shell instead */
debug_shell_start();
/* Prepare to run /bin/init */
char * argv[] = {
"/bin/init",

70
kernel/misc/debug_shell.c Normal file
View File

@ -0,0 +1,70 @@
/*
* Kernel Debug Shell
*/
#include <system.h>
#include <fs.h>
#include <logging.h>
#include <process.h>
#include <version.h>
void fs_printf(fs_node_t * device, char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[1024];
vasprintf(buffer, fmt, args);
va_end(args);
write_fs(device, 0, strlen(buffer), (uint8_t *)buffer);
}
int debug_shell_readline(fs_node_t * dev, char * linebuf, int max) {
int read = 0;
while (read < max) {
uint8_t buf[1];
int r = read_fs(dev, 0, 1, (unsigned char *)buf);
if (!r) {
debug_print(WARNING, "Read nothing?");
continue;
}
linebuf[read] = buf[0];
if (buf[0] == 13) {
fs_printf(dev, "\n");
linebuf[read] = 0;
break;
} else if (buf[0] == 0x7F) {
if (read > 0) {
fs_printf(dev, "\010 \010");
read--;
linebuf[read] = 0;
}
continue;
}
fs_printf(dev, "%c", buf[0]);
read += r;
}
return read;
}
void debug_shell_run(void * data) {
fs_node_t * tty = kopen("/dev/ttyS0", 0);
char version_number[1024];
sprintf(version_number, __kernel_version_format,
__kernel_version_major,
__kernel_version_minor,
__kernel_version_lower,
__kernel_version_suffix);
while (1) {
char command[512];
fs_printf(tty, "%s-%s %s# ", __kernel_name, version_number, current_process->wd_name);
int r = debug_shell_readline(tty, command, 511);
fs_printf(tty, "Entry[%d]: %s\n", r, command);
}
}
int debug_shell_start(void) {
int i = create_kernel_tasklet(debug_shell_run, "[kttydebug]");
debug_print(NOTICE, "Started tasklet with pid=%d", i);
return 0;
}

View File

@ -188,6 +188,7 @@ process_t * spawn_init(void) {
/* Process is not finished */
init->finished = 0;
init->started = 1;
init->running = 1;
init->wait_queue = list_create();
init->shm_mappings = list_create();
init->signal_queue = list_create();
@ -201,6 +202,8 @@ process_t * spawn_init(void) {
init->sleep_node.next = NULL;
init->sleep_node.value = init;
init->is_tasklet = 0;
set_process_environment(init, current_directory);
/* What the hey, let's also set the description on this one */
@ -304,6 +307,7 @@ process_t * spawn_process(volatile process_t * parent) {
proc->status = 0;
proc->finished = 0;
proc->started = 0;
proc->running = 0;
memset(proc->signals.functions, 0x00, sizeof(uintptr_t) * NUMSIGNALS);
proc->wait_queue = list_create();
proc->shm_mappings = list_create();
@ -318,6 +322,8 @@ process_t * spawn_process(volatile process_t * parent) {
proc->sleep_node.next = NULL;
proc->sleep_node.value = proc;
proc->is_tasklet = 0;
/* Insert the process into the process tree as a child
* of the parent process. */
tree_node_t * entry = tree_node_create(proc);

View File

@ -163,6 +163,8 @@ clone_table(
return table;
}
uintptr_t frozen_stack = 0;
/*
* Install multitasking functionality.
*/
@ -182,6 +184,8 @@ void tasking_install(void) {
/* Switch to the kernel directory */
switch_page_directory(current_process->thread.page_directory);
frozen_stack = (uintptr_t)valloc(KERNEL_STACK_SIZE);
/* Reenable interrupts */
IRQ_RES;
}
@ -259,6 +263,51 @@ uint32_t fork(void) {
return new_proc->id;
}
int create_kernel_tasklet(tasklet_t tasklet, char * name) {
IRQ_OFF;
uintptr_t esp, ebp;
current_process->syscall_registers->eax = 0;
page_directory_t * directory = kernel_directory;
/* Spawn a new process from this one */
process_t * new_proc = spawn_process(current_process);
assert(new_proc && "Could not allocate a new process!");
/* Set the new process' page directory to the original process' */
set_process_environment(new_proc, directory);
directory->ref_count++;
/* Read the instruction pointer */
struct regs r;
memcpy(&r, current_process->syscall_registers, sizeof(struct regs));
new_proc->syscall_registers = &r;
esp = new_proc->image.stack;
ebp = esp;
new_proc->syscall_registers->eax = 0;
new_proc->is_tasklet = 1;
new_proc->name = name;
PUSH(esp, struct regs, r);
new_proc->thread.esp = esp;
new_proc->thread.ebp = ebp;
new_proc->thread.eip = (uintptr_t)tasklet;
/* Add the new process to the ready queue */
make_process_ready(new_proc);
IRQ_RES;
/* Return the child PID */
return new_proc->id;
}
/*
* clone the current thread and create a new one in the same
* memory space with the given pointer as its new stack.
@ -347,15 +396,28 @@ uint32_t getpid(void) {
* This is called from the interrupt handler for the interval timer to
* perform standard task switching.
*/
void
switch_task(uint8_t reschedule) {
void switch_task(uint8_t reschedule) {
int pause_after = 0;
if (!current_process) {
/* Tasking is not yet installed. */
return;
}
if (!process_available()) {
/* There is no process available in the queue, do not bother switching */
return;
if (!current_process->running) {
while (1) {
IRQ_RES;
PAUSE;
}
}
if (!reschedule) {
pause_after = 1;
} else {
return;
}
}
if (!current_process->running) {
switch_next();
}
/* Collect the current kernel stack and instruction pointers */
@ -391,6 +453,7 @@ switch_task(uint8_t reschedule) {
current_process->thread.eip = eip;
current_process->thread.esp = esp;
current_process->thread.ebp = ebp;
current_process->running = 0;
/* Save floating point state */
switch_fpu();
@ -398,6 +461,12 @@ switch_task(uint8_t reschedule) {
if (reschedule) {
/* And reinsert it into the ready queue */
make_process_ready((process_t *)current_process);
} else if (pause_after) {
set_kernel_stack(frozen_stack);
while (1) {
IRQ_RES;
PAUSE;
}
}
/* Switch to the next task */
@ -414,6 +483,8 @@ void switch_next(void) {
/* Get the next available process */
while (!process_available()) {
/* Uh, no. */
IRQ_RES;
PAUSE;
return;
}
current_process = next_ready_process();
@ -424,7 +495,7 @@ void switch_next(void) {
/* Validate */
if ((eip < (uintptr_t)&code) || (eip > (uintptr_t)&end)) {
debug_print(WARNING, "Skipping broken process %d!", current_process->id);
debug_print(WARNING, "Skipping broken process %d! [eip=0x%x <0x%x or >0x%x]", current_process->id, eip, &code, &end);
switch_next();
}
@ -453,6 +524,8 @@ void switch_next(void) {
current_process->started = 1;
}
current_process->running = 1;
/* Jump, baby, jump */
asm volatile (
"mov %0, %%ebx\n"