diff --git a/headers/os/kernel/syscalls.h b/headers/os/kernel/syscalls.h index 2af0fb82f3..b1137b2fb2 100755 --- a/headers/os/kernel/syscalls.h +++ b/headers/os/kernel/syscalls.h @@ -62,6 +62,7 @@ status_t sys_get_next_team_info(int32 *cookie, team_info *info); int sys_kill(pid_t pid, int sig); int sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact); +bigtime_t sys_set_alarm(bigtime_t time, uint32 mode); region_id sys_vm_create_anonymous_region(const char *name, void **address, int addr_type, addr size, int wiring, int lock); diff --git a/headers/os/kernel/thread_types.h b/headers/os/kernel/thread_types.h index 743efde13c..125044e3e2 100644 --- a/headers/os/kernel/thread_types.h +++ b/headers/os/kernel/thread_types.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include #include extern spinlock_t thread_spinlock; @@ -96,6 +97,7 @@ struct thread { struct thread *all_next; struct thread *team_next; struct thread *q_next; + timer alarm; thread_id id; char name[SYS_MAX_OS_NAME_LEN]; int priority; diff --git a/headers/private/kernel/ksyscalls.h b/headers/private/kernel/ksyscalls.h index d64c88a34f..b546d76145 100755 --- a/headers/private/kernel/ksyscalls.h +++ b/headers/private/kernel/ksyscalls.h @@ -119,6 +119,8 @@ enum { SYSCALL_CREATE_INDEX, SYSCALL_READ_INDEX_STAT, SYSCALL_REMOVE_INDEX, + SYSCALL_SEND_SIGNAL, /* 110 */ + SYSCALL_SET_ALARM, }; int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret); diff --git a/src/kernel/apps/sig_test.c b/src/kernel/apps/sig_test.c index d2396be6de..30770001c0 100644 --- a/src/kernel/apps/sig_test.c +++ b/src/kernel/apps/sig_test.c @@ -11,8 +11,10 @@ void sig_handler(int); -void install_handler(int); +void alarm_handler(int); +void install_handler(int, __signal_func_ptr); int32 thread(void *); +void usage(void); void @@ -29,14 +31,21 @@ sig_handler(int sig) void -install_handler(int sig) +alarm_handler(int sig) +{ + printf("Alarm!\n"); +} + + +void +install_handler(int sig, __signal_func_ptr handler) { struct sigaction newa; struct sigaction olda; memset(&newa, 0, sizeof(newa)); - newa.sa_handler = sig_handler; + newa.sa_handler = handler; newa.sa_flags = SA_NOMASK | SA_RESTART; if (sys_sigaction(sig, &newa, &olda) < 0) { @@ -57,17 +66,42 @@ thread(void *data) } +void +usage() +{ + printf("usage: sig_test \n" + "where `mode' is one of:\n" + "\t1\tInstalls one handler for all signals\n" + "\t2\tSame as 1 but also spawns 5 threads with no active handlers\n" + "\t3\tSets an alarm via set_alarm\n" + "\n"); + exit(1); +} + + int main(int argc, char **argv) { int i; - printf("Installing signal handlers...\n"); - for (i=1; i<=NSIG; i++) - install_handler(i); - printf("Spawning some threads...\n"); - for (i=0; i<5; i++) - resume_thread(spawn_thread(thread, "sig_test aux thread", B_NORMAL_PRIORITY, NULL)); + if (argc != 2) + usage(); + + switch (argv[1][0]) { + case '1': + printf("Spawning some threads...\n"); + for (i=0; i<5; i++) + resume_thread(spawn_thread(thread, "sig_test aux thread", B_NORMAL_PRIORITY, NULL)); + case '2': + printf("Installing signal handlers...\n"); + for (i=1; i<=NSIG; i++) + install_handler(i, sig_handler); + break; + case '3': + install_handler(SIGALRM, alarm_handler); + sys_set_alarm(5000000, B_PERIODIC_ALARM); + break; + } printf("Done. Entering sleep mode...\n"); while (1) { if (sys_snooze(1000000000L) == B_INTERRUPTED) diff --git a/src/kernel/core/signal.c b/src/kernel/core/signal.c index 1a192db4b4..2500b558f0 100644 --- a/src/kernel/core/signal.c +++ b/src/kernel/core/signal.c @@ -4,6 +4,7 @@ ** Distributed under the terms of the OpenBeOS License. */ +#include #include #include #include @@ -183,9 +184,26 @@ has_signals_pending(struct thread *t) int -sys_kill(pid_t tid, int sig) +sys_kill(pid_t pid, int sig) { - return send_signal_etc(tid, sig, 0); + struct team *t; + int state; + thread_id tid = -1; + + // XXX check for permissions + + state = disable_interrupts(); + GRAB_THREAD_LOCK(); + t = team_get_team_struct_locked(pid); + if ((t) && (t->main_thread)) + tid = t->main_thread->id; + RELEASE_THREAD_LOCK(); + restore_interrupts(state); + + if (sig) + return send_signal_etc(tid, sig, 0); + else + return 0; } @@ -247,3 +265,36 @@ sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) return 0; } + +// Triggers a SIGALRM to the thread that issued the timer and reschedules +static int32 +alarm_event(timer *t) +{ + int tid = *((int *)((void *)t + sizeof(timer))); + + send_signal_etc(tid, SIGALRM, B_DO_NOT_RESCHEDULE); + + return B_INVOKE_SCHEDULER; +} + + +bigtime_t +sys_set_alarm(bigtime_t time, uint32 mode) +{ + struct thread *t = thread_get_current_thread(); + int state; + bigtime_t rv = 0; + + state = disable_interrupts(); + + if (t->alarm.period) + rv = (bigtime_t)t->alarm.entry.key - system_time(); + cancel_timer(&t->alarm); + if (time != B_INFINITE_TIMEOUT) + add_timer(&t->alarm, &alarm_event, time, mode); + + restore_interrupts(state); + + return rv; +} + diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c index 7f774a050f..8f030c4d61 100644 --- a/src/kernel/core/syscalls.c +++ b/src/kernel/core/syscalls.c @@ -395,6 +395,12 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re case SYSCALL_SIGACTION: *call_ret = user_sigaction((int)arg0, (const struct sigaction *)arg1, (struct sigaction *)arg2); break; + case SYSCALL_SEND_SIGNAL: + *call_ret = send_signal_etc((pid_t)arg0, (uint)arg1); + break; + case SYSCALL_SET_ALARM: + *call_ret = sys_set_alarm((bigtime_t)INT32TOINT64(arg0, arg1), (uint32)arg2); + break; default: *call_ret = -1; } diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index db85a2d130..6dd9d14678 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -971,6 +971,9 @@ thread_exit(int retcode) // boost our priority to get this over with thread_set_priority(t->id, B_FIRST_REAL_TIME_PRIORITY); + // Cancel previously installed alarm timer, if any + cancel_timer(&t->alarm); + // delete the user stack region first if (p->_aspace_id >= 0 && t->user_stack_region_id >= 0) { region_id rid = t->user_stack_region_id; diff --git a/src/kernel/libroot/os/syscalls.S b/src/kernel/libroot/os/syscalls.S index 89b2b3acdf..903a957470 100644 --- a/src/kernel/libroot/os/syscalls.S +++ b/src/kernel/libroot/os/syscalls.S @@ -154,4 +154,6 @@ SYSCALL2(sys_getenv, 80) SYSCALL0(sys_return_from_signal, 103) SYSCALL2(sys_kill, 104) SYSCALL3(sys_sigaction, 105) +SYSCALL2(sys_send_signal, 110) +SYSCALL3(sys_set_alarm, 111)