Feat: POSIX signal
This commit is contained in:
@@ -161,6 +161,9 @@ uint64_t _r_sp()
|
||||
// #define DEBUG_THREAD(val) DEBUG(val)
|
||||
#define DEBUG_THREAD(val) CLEAN
|
||||
|
||||
#define DEBUG_SIGNAL(val) DEBUG(val)
|
||||
// #define DEBUG_SIGNAL(val) CLEAN
|
||||
|
||||
extern char logger_buf[LOGGER_BUFLEN];
|
||||
extern char *logger_cur;
|
||||
extern char sp_buf[LOGGER_BUFLEN];
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct {
|
||||
uint64_t x0, x1;
|
||||
@@ -38,6 +40,13 @@ typedef struct process {
|
||||
void *mem;
|
||||
size_t mem_size;
|
||||
|
||||
void *sigstack;
|
||||
size_t sigstack_size;
|
||||
|
||||
bool sigstate[SIGNAL_NUM];
|
||||
int32_t current_signal;
|
||||
signal_handler_t sighandlers[SIGNAL_NUM];
|
||||
|
||||
trapframe_t *regs;
|
||||
} process_t;
|
||||
|
||||
@@ -51,3 +60,4 @@ int32_t run_process(uint64_t process);
|
||||
process_t *fork_process(const process_t *from);
|
||||
|
||||
extern int32_t global_pid_counter;
|
||||
extern vector_t *global_processes;
|
||||
|
||||
11
kernel/include/signal.h
Normal file
11
kernel/include/signal.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define SIGNAL_NUM 32
|
||||
|
||||
#define SIGKILL 9
|
||||
|
||||
typedef void (*signal_handler_t)();
|
||||
|
||||
void run_signal(int32_t SIGNAL);
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
|
||||
void syscall_handler(trapframe_t *regs);
|
||||
|
||||
@@ -12,4 +13,7 @@ int32_t sys_exec(const char *name, char *const argv[]);
|
||||
int32_t sys_fork(void);
|
||||
void sys_exit(int32_t status);
|
||||
int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox);
|
||||
void sys_kill(int32_t pid);
|
||||
void sys_kill_by_id(int32_t pid);
|
||||
void sys_signal(int32_t SIGNAL, signal_handler_t handler);
|
||||
void sys_kill(int32_t pid, int32_t SIGNAL);
|
||||
void sys_sigreturn(void);
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
int mbox_call(unsigned char ch, unsigned int *input)
|
||||
{
|
||||
unsigned int *_mbox = kmalloc((size_t)input[0] + 0xf), *mbox = ALIGN16(_mbox);
|
||||
LOG(_mbox); LOG(mbox); DEBUG((size_t)input[0]);
|
||||
LOG(_mbox); LOG(mbox); DEBUG_THREAD((size_t)input[0]);
|
||||
memcpy(mbox, input, (size_t)input[0]);
|
||||
unsigned int r = (unsigned long)mbox | (unsigned int)(ch&0xf);
|
||||
/* wait until we can write to the mailbox */
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
#include <interrupt.h>
|
||||
|
||||
int32_t global_pid_counter = 0;
|
||||
vector_t *global_processes = 0x0;
|
||||
|
||||
static inline
|
||||
process_t *_make_process(const char *filename)
|
||||
process_t *_make_process()
|
||||
{
|
||||
process_t *ret = kmalloc(sizeof(process_t));
|
||||
|
||||
file_node_t *file = initrd_get(initrd_root, filename);
|
||||
if (file == 0x0)
|
||||
panic(ERR_NOT_EXIST);
|
||||
|
||||
if (!global_processes)
|
||||
global_processes = make_vector(0);
|
||||
VEC_PUSH(global_processes, ret);
|
||||
|
||||
*ret = (process_t){
|
||||
.pid = global_pid_counter++,
|
||||
@@ -33,26 +34,46 @@ process_t *_make_process(const char *filename)
|
||||
.mem = allocate_page(256),
|
||||
.mem_size = 256 << 12,
|
||||
|
||||
.sigstack = allocate_page(256),
|
||||
.sigstack_size = 256 << 12,
|
||||
|
||||
.current_signal = 0,
|
||||
|
||||
.regs = kmalloc(sizeof(trapframe_t)),
|
||||
};
|
||||
memcpy(ret->mem, file->filecontent, file->filesize);
|
||||
|
||||
memset(ret->sigstate, 0x0, SIGNAL_NUM * sizeof(bool));
|
||||
memset(ret->sighandlers, 0x0, SIGNAL_NUM * sizeof(signal_handler_t));
|
||||
memset(ret->regs, 0x0, sizeof(trapframe_t));
|
||||
*ret->regs = (trapframe_t){
|
||||
.spsr_el1 = 0x0, // enable all interrupt
|
||||
.elr_el1 = (uint64_t)ret->mem,
|
||||
.sp_el0 = ((uint64_t)ret->stack + ret->stack_size - 64),
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
void _init_process(process_t *process, const char *filename)
|
||||
{
|
||||
file_node_t *file = initrd_get(initrd_root, filename);
|
||||
if (file == 0x0)
|
||||
panic(ERR_NOT_EXIST);
|
||||
|
||||
memcpy(process->mem, file->filecontent, file->filesize);
|
||||
*process->regs = (trapframe_t){
|
||||
.spsr_el1 = 0x0, // enable all interrupt
|
||||
.elr_el1 = (uint64_t)process->mem,
|
||||
.sp_el0 = ((uint64_t)process->stack + process->stack_size - 64),
|
||||
};
|
||||
}
|
||||
|
||||
// void run_process_by_name(const char *filename)
|
||||
int32_t run_process_by_name(uint64_t param)
|
||||
{
|
||||
const char *filename = (void *)param;
|
||||
thread_t *th = get_current();
|
||||
|
||||
th->process = _make_process(filename);
|
||||
if (!th->process)
|
||||
th->process = _make_process();
|
||||
_init_process(th->process, filename);
|
||||
|
||||
th->process->th = th;
|
||||
LOG("Run process by name"); DEBUG_THREAD(filename);
|
||||
LOG(th->process->stack); DEBUG_THREAD(th->process->regs->sp_el0);
|
||||
@@ -84,21 +105,7 @@ int32_t run_process(uint64_t param)
|
||||
|
||||
process_t *fork_process(const process_t *from)
|
||||
{
|
||||
process_t *ret = kmalloc(sizeof(process_t));
|
||||
*ret = (process_t){
|
||||
.pid = global_pid_counter++,
|
||||
.th = 0x0,
|
||||
|
||||
.exitcode = from->exitcode,
|
||||
|
||||
.stack = allocate_page(256),
|
||||
.stack_size = 256 << 12,
|
||||
|
||||
.mem = allocate_page(256),
|
||||
.mem_size = 256 << 12,
|
||||
|
||||
.regs = kmalloc(sizeof(trapframe_t)),
|
||||
};
|
||||
process_t *ret = _make_process();
|
||||
memcpy(ret->stack, from->stack, from->stack_size);
|
||||
memcpy(ret->mem, from->mem, from->mem_size);
|
||||
*ret->regs = (trapframe_t){
|
||||
|
||||
59
kernel/lib/signal.c
Normal file
59
kernel/lib/signal.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <signal.h>
|
||||
#include <logger.h>
|
||||
#include <string.h>
|
||||
#include <process.h>
|
||||
#include <thread.h>
|
||||
#include <kmalloc.h>
|
||||
#include <interrupt.h>
|
||||
#include <exec.h>
|
||||
|
||||
static inline
|
||||
void _sighandler_wrapper(signal_handler_t handler)
|
||||
{
|
||||
handler();
|
||||
asm volatile(
|
||||
"mov x8, #10" ENDL
|
||||
"svc 0"
|
||||
::: "x8"
|
||||
);
|
||||
}
|
||||
|
||||
static inline
|
||||
void _sigkill_default_handler()
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->status = THREAD_STATUS_ZOMBIE;
|
||||
}
|
||||
|
||||
void run_signal(int32_t SIGNAL)
|
||||
{
|
||||
LOG("run_signal"); DEBUG_SIGNAL(SIGNAL);
|
||||
process_t *process = get_current()->process;
|
||||
process->current_signal = SIGNAL;
|
||||
trapframe_t *regs = kmalloc(sizeof(trapframe_t));
|
||||
memcpy(regs, process->regs, sizeof(trapframe_t));
|
||||
|
||||
if (!process->sighandlers[SIGNAL]) {
|
||||
switch (SIGNAL) {
|
||||
case SIGKILL:
|
||||
_sigkill_default_handler();
|
||||
break;
|
||||
default:
|
||||
LOG("No default handler for this signal"); DEBUG_SIGNAL(SIGNAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*regs = (trapframe_t){
|
||||
.x0 = (uint64_t)process->sighandlers[SIGNAL],
|
||||
.elr_el1 = (uint64_t)_sighandler_wrapper,
|
||||
.sp_el0 = ((uint64_t)process->sigstack + process->sigstack_size - 64),
|
||||
};
|
||||
|
||||
disable_interrupt();
|
||||
process->current_signal = 0x0;
|
||||
process->sigstate[SIGNAL] = false;
|
||||
user_exec(regs);
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <thread.h>
|
||||
#include <process.h>
|
||||
#include <mbox.h>
|
||||
#include <exec.h>
|
||||
|
||||
void syscall_handler(trapframe_t *regs)
|
||||
{
|
||||
@@ -27,13 +28,22 @@ void syscall_handler(trapframe_t *regs)
|
||||
regs->x0 = sys_fork();
|
||||
break;
|
||||
case 5: // void exit(int32_t status)
|
||||
sys_exit((int)regs->x0);
|
||||
sys_exit((int32_t)regs->x0);
|
||||
break;
|
||||
case 6: // int32_t mbox_call(uint8_t ch, uint32_t *mbox)
|
||||
regs->x0 = sys_mbox_call((uint8_t)regs->x0, (uint32_t *)regs->x1);
|
||||
break;
|
||||
case 7: // void kill(int32_t pid)
|
||||
sys_kill((int)regs->x0);
|
||||
case 7: // void kill_by_id(int32_t pid)
|
||||
sys_kill_by_id((int32_t)regs->x0);
|
||||
break;
|
||||
case 8: // void signal(int32_t SIGNAL, signal_handler_t handler)
|
||||
sys_signal((int32_t)regs->x0, (signal_handler_t)regs->x1);
|
||||
break;
|
||||
case 9: // void kill(int32_t pid, int32_t SIGNAL)
|
||||
sys_kill((int32_t)regs->x0, (int32_t)regs->x1);
|
||||
break;
|
||||
case 10: // void sigreturn(void)
|
||||
sys_sigreturn();
|
||||
break;
|
||||
default:
|
||||
LOG("unsupported syscall"); ERROR(regs->x8);
|
||||
@@ -74,6 +84,34 @@ void sys_exit(int32_t status)
|
||||
int32_t sys_mbox_call(uint8_t ch, uint32_t *mbox)
|
||||
{ return mbox_call(ch, mbox); }
|
||||
|
||||
void sys_kill(int32_t pid)
|
||||
void sys_kill_by_id(int32_t pid)
|
||||
{
|
||||
if (!global_processes || global_processes->size <= (size_t)pid) {
|
||||
LOG("Process not exist"); INFOR(pid);
|
||||
return;
|
||||
}
|
||||
|
||||
process_t *process = VEC_AT(process_t, global_processes, pid);
|
||||
process->th->status = THREAD_STATUS_ZOMBIE;
|
||||
LOG("Process killed"); INFOR(pid);
|
||||
}
|
||||
|
||||
void sys_signal(int32_t SIGNAL, signal_handler_t handler)
|
||||
{
|
||||
thread_t *th = get_current();
|
||||
th->process->sighandlers[SIGNAL] = handler;
|
||||
LOG(handler); LOG(SIGNAL); DEBUG_SIGNAL("registered");
|
||||
}
|
||||
|
||||
void sys_kill(int32_t pid, int32_t SIGNAL)
|
||||
{
|
||||
process_t *process = VEC_AT(process_t, global_processes, pid);
|
||||
process->sigstate[SIGNAL] = true;
|
||||
}
|
||||
|
||||
void sys_sigreturn(void)
|
||||
{
|
||||
DEBUG_SIGNAL("sigreturn");
|
||||
thread_t *th = get_current();
|
||||
user_exec(th->process->regs);
|
||||
}
|
||||
|
||||
@@ -41,5 +41,11 @@ void timer_irq_handler(void)
|
||||
uint64_t cntfrq_el0;
|
||||
R_SYSREG(cntfrq_el0, cntfrq_el0);
|
||||
W_SYSREG(cntp_tval_el0, cntfrq_el0 >> 5);
|
||||
|
||||
thread_t *th = get_current();
|
||||
for (int32_t i = 0; i < SIGNAL_NUM; ++i) {
|
||||
if (th->process->sigstate[i])
|
||||
run_signal(i);
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user