Update markdown and tabs and stuff

This commit is contained in:
2016-10-22 17:07:50 +02:00
parent 67e817490e
commit a27daafa0a
39 changed files with 2249 additions and 2139 deletions

View File

@@ -17,15 +17,17 @@ I'll just look at `signal` and `kill` and ignore things like
First of all, in order to compile newlib with kernel supported signals,
you need the line
newlib_cflags="${newlib_cflags} -DSIGNAL_PROVIDED"
:::make
newlib_cflags="${newlib_cflags} -DSIGNAL_PROVIDED"
in your entry in `newlib/configure.host` as described in [the osdev
wiki](http://wiki.osdev.org/OS_Specific_Toolchain#Signal_handling).
Then you need the syscalls:
sig_t signal(int signum, sig_t handler);
int kill(int pid, int sig);
:::c
sig_t signal(int signum, sig_t handler);
int kill(int pid, int sig);
###Raising signals
@@ -38,31 +40,33 @@ as I go along later.
The way I chose to implement signals was through a list for each
process. When a signal is sent using `kill` or similar, a `signal_t`
typedef struct
{
uint32_t sig;
uint32_t sender;
list_head_t queue;
} signal_t;
:::c
typedef struct
{
uint32_t sig;
uint32_t sender;
list_head_t queue;
} signal_t;
is created and added to the processes list:
int signal_process(int pid, int signum)
{
process_t *p = get_process(pid);
...
signal_t *signal = calloc(1, sizeof(signal_t));
signal->sig = signum;
signal->sender = current->proc->pid;
init_list(signal->queue);
append_to_list(p->signal_queue, signal->queue);
:::c
int signal_process(int pid, int signum)
{
process_t *p = get_process(pid);
...
signal_t *signal = calloc(1, sizeof(signal_t));
signal->sig = signum;
signal->sender = current->proc->pid;
init_list(signal->queue);
append_to_list(p->signal_queue, signal->queue);
if(p == current->proc)
{
handle_signals(current);
}
return 0;
}
if(p == current->proc)
{
handle_signals(current);
}
return 0;
}
If the currently running thread is in the process being signalled, we
handle the signals immediately. Otherwise it can wait for a bit.
@@ -75,13 +79,14 @@ The `signal` syscall lets the process select how to handle a certain
signal. Each process also contains a table of `sig_t` and the `signal`
syscall calls the following function:
sig_t switch_handler(int signum, sig_t handler)
{
...
sig_t old = current->proc->signal_handler[signum];
current->proc->signal_handler[signum] = handler;
return old;
}
:::c
sig_t switch_handler(int signum, sig_t handler)
{
...
sig_t old = current->proc->signal_handler[signum];
current->proc->signal_handler[signum] = handler;
return old;
}
The cut out part of this function contains code to make sure the handler
of signal 9 (`SIGKILL`) is never changed from `SIG_DFL`.
@@ -94,24 +99,25 @@ as the process continues running should be soon enough.
I chose to hook into the my interrupt handler:
registers_t *idt_handler(registers_t *r)
{
...
if(int_handlers[r->int_no)
{
...
registers_t *ret = int_handlers[r->int_no](r);
if((ret->cs & 0x3) == 0x3)
{
ret = (registers_t *)handle_signals((thread_t *)ret);
...
}
...
return ret
}
...
}
:::c
registers_t *idt_handler(registers_t *r)
{
...
if(int_handlers[r->int_no)
{
...
registers_t *ret = int_handlers[r->int_no](r);
if((ret->cs & 0x3) == 0x3)
{
ret = (registers_t *)handle_signals((thread_t *)ret);
...
}
...
return ret
}
...
}
So, what does `handle_signals` actually do?
@@ -125,43 +131,45 @@ If the handler is set to `SIG_DFL` the function looks up the correct
default signal handler in a table and calls it. It may be one of the
following:
void sighandler_ignore(int num)
{
(void)num;
}
void sighandler_terminate(int num)
{
fprintf(stderr,, "Process %x terminated by signal %x\n", \
current->proc->pid, num);
_exit(num);
}
void sighandler_coredump(int num)
{ /* Same as above */ }
void sighandler_stop(int num)
{ /* Not implemented yet */ }
void sighandler_continue(int num)
{ /* Not implemented yet */ }
:::c
void sighandler_ignore(int num)
{
(void)num;
}
void sighandler_terminate(int num)
{
fprintf(stderr,, "Process %x terminated by signal %x\n", \
current->proc->pid, num);
_exit(num);
}
void sighandler_coredump(int num)
{ /* Same as above */ }
void sighandler_stop(int num)
{ /* Not implemented yet */ }
void sighandler_continue(int num)
{ /* Not implemented yet */ }
If the handler is a function a new thread is created to handle it:
...
sig_t handler = th->proc->signal_handler[signal->sig];
thread_t *h = new_thread((void (*)(void))handler, 1);
append_to_list(th->proc->threads, h->process_threads);
h->proc = th->proc;
uint32_t *stack = ((uint32_t *)th->r.useresp;
*--stack = signal->sig;
*--stack = SIGNAL_RETURN_ADDRESS;
h->r.useresp = h->r.ebp = (uint32_t)stack;
remove_from_list(signal->queue);
free(signal);
scheduler_remove(h);
scheduler_sleep(th, &h->waiting);
scheduler_cheat(h);
schedule();
}
:::c
...
sig_t handler = th->proc->signal_handler[signal->sig];
thread_t *h = new_thread((void (*)(void))handler, 1);
append_to_list(th->proc->threads, h->process_threads);
h->proc = th->proc;
uint32_t *stack = ((uint32_t *)th->r.useresp;
*--stack = signal->sig;
*--stack = SIGNAL_RETURN_ADDRESS;
h->r.useresp = h->r.ebp = (uint32_t)stack;
remove_from_list(signal->queue);
free(signal);
scheduler_remove(h);
scheduler_sleep(th, &h->waiting);
scheduler_cheat(h);
schedule();
}
This creates a new thread and pushes the signal number (as an argument)
and a return address to the threads stack. It then places the new thread