From 0b58e505ee7a298433cb781d3f5a86a6a10a3b88 Mon Sep 17 00:00:00 2001 From: tionis Date: Sun, 14 May 2023 15:16:27 +0200 Subject: [PATCH 1/7] os/proc-kill now accepts an optional signal to send --- src/core/os.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/src/core/os.c b/src/core/os.c index 64a03470..0c348466 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -624,12 +624,96 @@ JANET_CORE_FN(os_proc_wait, #endif } +#ifndef JANET_WINDOWS +struct keyword_signal { + const char *keyword; + int signal; +}; +static const struct keyword_signal signal_keywords[] = { + {"kill", SIGKILL}, + {"int", SIGINT}, + {"abrt", SIGABRT}, + {"fpe", SIGFPE}, + {"ill", SIGILL}, + {"segv", SIGSEGV}, +#ifdef SIGTERM + {"term", SIGTERM}, +#endif +#ifdef SIGARLM + {"alrm", SIGALRM}, +#endif +#ifdef SIGHUP + {"hup", SIGHUP}, +#endif +#ifdef SIGPIPE + {"pipe", SIGPIPE}, + #endif +#ifdef SIGQUIT + {"quit", SIGQUIT}, +#endif +#ifdef SIGUSR1 + {"usr1", SIGUSR1}, +#endif +#ifdef SIGUSR2 + {"usr2", SIGUSR2}, +#endif +#ifdef SIGCHLD + {"chld", SIGCHLD}, +#endif +#ifdef SIGCONT + {"cont", SIGCONT}, +#endif +#ifdef SIGSTOP + {"stop", SIGSTOP}, +#endif +#ifdef SIGTSTP + {"tstp", SIGTSTP}, +#endif +#ifdef SIGTTIN + {"ttin", SIGTTIN}, +#endif +#ifdef SIGTTOU + {"ttou", SIGTTOU}, +#endif +#ifdef SIGBUS + {"bus", SIGBUS}, +#endif +#ifdef SIGPOLL + {"poll", SIGPOLL}, +#endif +#ifdef SIGPROF + {"prof", SIGPROF}, +#endif +#ifdef SIGSYS + {"sys", SIGSYS}, +#endif +#ifdef SIGTRAP + {"trap", SIGTRAP}, +#endif +#ifdef SIGURG + {"urg", SIGURG}, +#endif +#ifdef SIGVTALRM + {"vtlarm", SIGVTALRM}, +#endif +#ifdef SIGXCPU + {"xcpu", SIGXCPU}, +#endif +#ifdef SIGXFSZ + {"xfsz", SIGXFSZ}, +#endif + {NULL, 0}, +}; +#endif + JANET_CORE_FN(os_proc_kill, - "(os/proc-kill proc &opt wait)", + "(os/proc-kill proc &opt wait signal)", "Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process " "handle on windows. If `wait` is truthy, will wait for the process to finish and " - "returns the exit code. Otherwise, returns `proc`.") { - janet_arity(argc, 1, 2); + "returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead." + "Signal is ignored on windows. Signal keywords are named after their C counterparts but in" + "lowercase with the leading `SIG` stripped") { + janet_arity(argc, 1, 3); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); if (proc->flags & JANET_PROC_WAITED) { janet_panicf("cannot kill process that has already finished"); @@ -643,7 +727,23 @@ JANET_CORE_FN(os_proc_kill, CloseHandle(proc->pHandle); CloseHandle(proc->tHandle); #else - int status = kill(proc->pid, SIGKILL); + int signal = SIGKILL; + if(argc == 3){ + int signal = -1; + JanetKeyword signal_kw = janet_getkeyword(argv, 2); + const struct keyword_signal *ptr = signal_keywords; + while (ptr->keyword){ + if(!janet_cstrcmp(signal_kw, ptr->keyword)){ + signal = ptr->signal; + break; + } + ptr++; + } + if(signal == -1){ + janet_panic("undefined signal"); + } + } + int status = kill(proc->pid, signal); if (status) { janet_panic(strerror(errno)); } From 71d51c160d784e9c83d1e77434b9efe80c42924e Mon Sep 17 00:00:00 2001 From: tionis Date: Tue, 16 May 2023 13:27:52 +0200 Subject: [PATCH 2/7] added simple test for signal handling in os/proc-kill using :kill --- test/suite0009.janet | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/suite0009.janet b/test/suite0009.janet index 6b61797a..1d4368b9 100644 --- a/test/suite0009.janet +++ b/test/suite0009.janet @@ -52,6 +52,11 @@ (def retval (os/proc-wait p)) (assert (not= retval 24) "Process was *not* terminated by parent")) +(let [p (os/spawn [janet "-e" `(do (ev/sleep 30) (os/exit 24)`] :p)] + (os/proc-kill p false :kill) + (def retval (os/proc-wait p)) + (assert (not= retval 24) "Process was *not* terminated by parent")) + # Parallel subprocesses (defn calc-1 From 56d72ec4c5d49f4e5bd8d6af8e59cadf421fcef9 Mon Sep 17 00:00:00 2001 From: tionis Date: Tue, 16 May 2023 16:58:42 +0200 Subject: [PATCH 3/7] support sending signals to processes on windows --- src/core/os.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/core/os.c b/src/core/os.c index 0c348466..425785b0 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -624,7 +624,6 @@ JANET_CORE_FN(os_proc_wait, #endif } -#ifndef JANET_WINDOWS struct keyword_signal { const char *keyword; int signal; @@ -704,29 +703,19 @@ static const struct keyword_signal signal_keywords[] = { #endif {NULL, 0}, }; -#endif JANET_CORE_FN(os_proc_kill, "(os/proc-kill proc &opt wait signal)", "Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process " "handle on windows. If `wait` is truthy, will wait for the process to finish and " "returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead." - "Signal is ignored on windows. Signal keywords are named after their C counterparts but in" - "lowercase with the leading `SIG` stripped") { + "Signal keywords are named after their C counterparts but in lowercase with the leading " + "`SIG` stripped") { janet_arity(argc, 1, 3); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); if (proc->flags & JANET_PROC_WAITED) { janet_panicf("cannot kill process that has already finished"); } -#ifdef JANET_WINDOWS - if (proc->flags & JANET_PROC_CLOSED) { - janet_panicf("cannot close process handle that is already closed"); - } - proc->flags |= JANET_PROC_CLOSED; - TerminateProcess(proc->pHandle, 1); - CloseHandle(proc->pHandle); - CloseHandle(proc->tHandle); -#else int signal = SIGKILL; if(argc == 3){ int signal = -1; @@ -743,6 +732,22 @@ JANET_CORE_FN(os_proc_kill, janet_panic("undefined signal"); } } +#ifdef JANET_WINDOWS + if (proc->flags & JANET_PROC_CLOSED) { + janet_panicf("cannot close process handle that is already closed"); + } + proc->flags |= JANET_PROC_CLOSED; + if(signal == SIGKILL){ + TerminateProcess(proc->pHandle, 1); + }else{ + int status = kill(proc->pid, signal); + if (status) { + janet_panic(strerror(errno)); + } + } + CloseHandle(proc->pHandle); + CloseHandle(proc->tHandle); +#else int status = kill(proc->pid, signal); if (status) { janet_panic(strerror(errno)); From 0f35acade1d9c4958f711fd3d84b4eb55736b14f Mon Sep 17 00:00:00 2001 From: tionis Date: Tue, 16 May 2023 18:47:38 +0200 Subject: [PATCH 4/7] use SIGTERM for os/proc-kill signal test --- src/core/os.c | 8 +++++--- test/suite0009.janet | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/os.c b/src/core/os.c index 425785b0..c1ab5622 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -629,7 +629,9 @@ struct keyword_signal { int signal; }; static const struct keyword_signal signal_keywords[] = { +#ifdef SIGKILL {"kill", SIGKILL}, +#endif {"int", SIGINT}, {"abrt", SIGABRT}, {"fpe", SIGFPE}, @@ -716,9 +718,8 @@ JANET_CORE_FN(os_proc_kill, if (proc->flags & JANET_PROC_WAITED) { janet_panicf("cannot kill process that has already finished"); } - int signal = SIGKILL; + int signal = -1; if(argc == 3){ - int signal = -1; JanetKeyword signal_kw = janet_getkeyword(argv, 2); const struct keyword_signal *ptr = signal_keywords; while (ptr->keyword){ @@ -737,7 +738,7 @@ JANET_CORE_FN(os_proc_kill, janet_panicf("cannot close process handle that is already closed"); } proc->flags |= JANET_PROC_CLOSED; - if(signal == SIGKILL){ + if(signal == -1){ TerminateProcess(proc->pHandle, 1); }else{ int status = kill(proc->pid, signal); @@ -748,6 +749,7 @@ JANET_CORE_FN(os_proc_kill, CloseHandle(proc->pHandle); CloseHandle(proc->tHandle); #else + if(signal == -1){signal=SIGKILL;} int status = kill(proc->pid, signal); if (status) { janet_panic(strerror(errno)); diff --git a/test/suite0009.janet b/test/suite0009.janet index 1d4368b9..99f5232e 100644 --- a/test/suite0009.janet +++ b/test/suite0009.janet @@ -53,7 +53,7 @@ (assert (not= retval 24) "Process was *not* terminated by parent")) (let [p (os/spawn [janet "-e" `(do (ev/sleep 30) (os/exit 24)`] :p)] - (os/proc-kill p false :kill) + (os/proc-kill p false :term) (def retval (os/proc-wait p)) (assert (not= retval 24) "Process was *not* terminated by parent")) From e53c03028fbf9ba832bb6f51cdbd7e6daa7f91d4 Mon Sep 17 00:00:00 2001 From: tionis Date: Sun, 21 May 2023 15:44:02 +0200 Subject: [PATCH 5/7] ignoring signals on windows in os/proc-kill again --- src/core/os.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/core/os.c b/src/core/os.c index c1ab5622..55c4c7d3 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -628,6 +628,8 @@ struct keyword_signal { const char *keyword; int signal; }; + +#ifndef JANET_WINDOWS static const struct keyword_signal signal_keywords[] = { #ifdef SIGKILL {"kill", SIGKILL}, @@ -705,6 +707,7 @@ static const struct keyword_signal signal_keywords[] = { #endif {NULL, 0}, }; +#endif JANET_CORE_FN(os_proc_kill, "(os/proc-kill proc &opt wait signal)", @@ -712,12 +715,21 @@ JANET_CORE_FN(os_proc_kill, "handle on windows. If `wait` is truthy, will wait for the process to finish and " "returns the exit code. Otherwise, returns `proc`. If signal is specified send it instead." "Signal keywords are named after their C counterparts but in lowercase with the leading " - "`SIG` stripped") { + "`SIG` stripped. Signals are ignored on windows.") { janet_arity(argc, 1, 3); JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); if (proc->flags & JANET_PROC_WAITED) { janet_panicf("cannot kill process that has already finished"); } +#ifdef JANET_WINDOWS + if (proc->flags & JANET_PROC_CLOSED) { + janet_panicf("cannot close process handle that is already closed"); + } + proc->flags |= JANET_PROC_CLOSED; + TerminateProcess(proc->pHandle, 1); + CloseHandle(proc->pHandle); + CloseHandle(proc->tHandle); +#else int signal = -1; if(argc == 3){ JanetKeyword signal_kw = janet_getkeyword(argv, 2); @@ -733,24 +745,7 @@ JANET_CORE_FN(os_proc_kill, janet_panic("undefined signal"); } } -#ifdef JANET_WINDOWS - if (proc->flags & JANET_PROC_CLOSED) { - janet_panicf("cannot close process handle that is already closed"); - } - proc->flags |= JANET_PROC_CLOSED; - if(signal == -1){ - TerminateProcess(proc->pHandle, 1); - }else{ - int status = kill(proc->pid, signal); - if (status) { - janet_panic(strerror(errno)); - } - } - CloseHandle(proc->pHandle); - CloseHandle(proc->tHandle); -#else - if(signal == -1){signal=SIGKILL;} - int status = kill(proc->pid, signal); + int status = kill(proc->pid, signal == -1 ? SIGKILL : signal); if (status) { janet_panic(strerror(errno)); } From 4dfc869b8a17ff16d0290daac021e6479cb62db3 Mon Sep 17 00:00:00 2001 From: tionis Date: Sun, 21 May 2023 15:55:11 +0200 Subject: [PATCH 6/7] fixed formatting in src/core/os.c --- src/core/os.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/os.c b/src/core/os.c index 8f076cbc..4d3a3448 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -650,7 +650,7 @@ static const struct keyword_signal signal_keywords[] = { #endif #ifdef SIGPIPE {"pipe", SIGPIPE}, - #endif +#endif #ifdef SIGQUIT {"quit", SIGQUIT}, #endif @@ -731,17 +731,17 @@ JANET_CORE_FN(os_proc_kill, CloseHandle(proc->tHandle); #else int signal = -1; - if(argc == 3){ + if (argc == 3) { JanetKeyword signal_kw = janet_getkeyword(argv, 2); const struct keyword_signal *ptr = signal_keywords; - while (ptr->keyword){ - if(!janet_cstrcmp(signal_kw, ptr->keyword)){ + while (ptr->keyword) { + if (!janet_cstrcmp(signal_kw, ptr->keyword)) { signal = ptr->signal; break; } ptr++; } - if(signal == -1){ + if (signal == -1) { janet_panic("undefined signal"); } } From 63353b98cd114e33ba4816cec642fe262f803d71 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Sun, 21 May 2023 20:18:32 +0200 Subject: [PATCH 7/7] improved error messages for special forms --- src/core/specials.c | 12 ++++++------ src/core/value.c | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/core/specials.c b/src/core/specials.c index 8f40cdd7..b9bfc748 100644 --- a/src/core/specials.c +++ b/src/core/specials.c @@ -264,7 +264,7 @@ static const Janet *janetc_make_sourcemap(JanetCompiler *c) { static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv) { if (argn != 2) { - janetc_cerror(opts.compiler, "expected 2 arguments"); + janetc_cerror(opts.compiler, "expected 2 arguments to set"); return janetc_cslot(janet_wrap_nil()); } JanetFopts subopts = janetc_fopts_default(opts.compiler); @@ -335,11 +335,11 @@ static JanetTable *handleattr(JanetCompiler *c, int32_t argn, const Janet *argv) return tab; } -static JanetSlot dohead(JanetCompiler *c, JanetFopts opts, Janet *head, int32_t argn, const Janet *argv) { +static JanetSlot dohead(const char *kind, JanetCompiler *c, JanetFopts opts, Janet *head, int32_t argn, const Janet *argv) { JanetFopts subopts = janetc_fopts_default(c); JanetSlot ret; if (argn < 2) { - janetc_cerror(c, "expected at least 2 arguments"); + janetc_error(c, janet_formatc("expected at least 2 arguments to %s", kind)); return janetc_cslot(janet_wrap_nil()); } *head = argv[0]; @@ -404,7 +404,7 @@ static JanetSlot janetc_var(JanetFopts opts, int32_t argn, const Janet *argv) { JanetCompiler *c = opts.compiler; Janet head; JanetTable *attr_table = handleattr(c, argn, argv); - JanetSlot ret = dohead(c, opts, &head, argn, argv); + JanetSlot ret = dohead("var", c, opts, &head, argn, argv); if (c->result.status == JANET_COMPILE_ERROR) return janetc_cslot(janet_wrap_nil()); destructure(c, argv[0], ret, varleaf, attr_table); @@ -454,7 +454,7 @@ static JanetSlot janetc_def(JanetFopts opts, int32_t argn, const Janet *argv) { Janet head; opts.flags &= ~JANET_FOPTS_HINT; JanetTable *attr_table = handleattr(c, argn, argv); - JanetSlot ret = dohead(c, opts, &head, argn, argv); + JanetSlot ret = dohead("def", c, opts, &head, argn, argv); if (c->result.status == JANET_COMPILE_ERROR) return janetc_cslot(janet_wrap_nil()); destructure(c, argv[0], ret, defleaf, attr_table); @@ -708,7 +708,7 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv) uint8_t ifnjmp = JOP_JUMP_IF_NOT; if (argn < 2) { - janetc_cerror(c, "expected at least 2 arguments"); + janetc_cerror(c, "expected at least 2 arguments to while"); return janetc_cslot(janet_wrap_nil()); } diff --git a/src/core/value.c b/src/core/value.c index 36e381cd..423b1714 100644 --- a/src/core/value.c +++ b/src/core/value.c @@ -439,20 +439,21 @@ int janet_compare(Janet x, Janet y) { return status - 2; } -static int32_t getter_checkint(Janet key, int32_t max) { +static int32_t getter_checkint(JanetType type, Janet key, int32_t max) { if (!janet_checkint(key)) goto bad; int32_t ret = janet_unwrap_integer(key); if (ret < 0) goto bad; if (ret >= max) goto bad; return ret; bad: - janet_panicf("expected integer key in range [0, %d), got %v", max, key); + janet_panicf("expected integer key for %s in range [0, %d), got %v", janet_type_names[type], max, key); } /* Gets a value and returns. Can panic. */ Janet janet_in(Janet ds, Janet key) { Janet value; - switch (janet_type(ds)) { + JanetType type = janet_type(ds); + switch (type) { default: janet_panicf("expected %T, got %v", JANET_TFLAG_LENGTHABLE, ds); break; @@ -464,19 +465,19 @@ Janet janet_in(Janet ds, Janet key) { break; case JANET_ARRAY: { JanetArray *array = janet_unwrap_array(ds); - int32_t index = getter_checkint(key, array->count); + int32_t index = getter_checkint(type, key, array->count); value = array->data[index]; break; } case JANET_TUPLE: { const Janet *tuple = janet_unwrap_tuple(ds); int32_t len = janet_tuple_length(tuple); - value = tuple[getter_checkint(key, len)]; + value = tuple[getter_checkint(type, key, len)]; break; } case JANET_BUFFER: { JanetBuffer *buffer = janet_unwrap_buffer(ds); - int32_t index = getter_checkint(key, buffer->count); + int32_t index = getter_checkint(type, key, buffer->count); value = janet_wrap_integer(buffer->data[index]); break; } @@ -484,7 +485,7 @@ Janet janet_in(Janet ds, Janet key) { case JANET_SYMBOL: case JANET_KEYWORD: { const uint8_t *str = janet_unwrap_string(ds); - int32_t index = getter_checkint(key, janet_string_length(str)); + int32_t index = getter_checkint(type, key, janet_string_length(str)); value = janet_wrap_integer(str[index]); break; } @@ -752,13 +753,14 @@ void janet_putindex(Janet ds, int32_t index, Janet value) { } void janet_put(Janet ds, Janet key, Janet value) { - switch (janet_type(ds)) { + JanetType type = janet_type(ds); + switch (type) { default: janet_panicf("expected %T, got %v", JANET_TFLAG_ARRAY | JANET_TFLAG_BUFFER | JANET_TFLAG_TABLE, ds); case JANET_ARRAY: { JanetArray *array = janet_unwrap_array(ds); - int32_t index = getter_checkint(key, INT32_MAX - 1); + int32_t index = getter_checkint(type, key, INT32_MAX - 1); if (index >= array->count) { janet_array_setcount(array, index + 1); } @@ -767,7 +769,7 @@ void janet_put(Janet ds, Janet key, Janet value) { } case JANET_BUFFER: { JanetBuffer *buffer = janet_unwrap_buffer(ds); - int32_t index = getter_checkint(key, INT32_MAX - 1); + int32_t index = getter_checkint(type, key, INT32_MAX - 1); if (!janet_checkint(value)) janet_panicf("can only put integers in buffers, got %v", value); if (index >= buffer->count) {