-
-
Notifications
You must be signed in to change notification settings - Fork 605
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch adds support for the Linux kill(2) function. The next patch will add alarm(2) support, which uses kill(2). To be honest, we sort-of implement kill(). This implementation is compatible with the API, but the semantics are somewhat different: While in Linux kill() causes the signal handler to run on one of the existing threads, in this implementation, the signal handler is run in a *new* thread. Implementing the exact Linux semantics in OSv would require tracking when OSv runs kernel code (i.e., code in the main executable, not a shared object) so we can delay running the signal handler until returning to the user code. Moreover, we'll need to be able to interrupt sleeping kernel code. This is complicated and adds overhead even if signals aren't used (and they aren't used in most modern code). I expect that this code will be "good enough" in many use cases. This code will *not* be good in enough in programs that expect one of the following: 1. A program that by using Posix Thread's "signal masks" tried to ensure that the signal is delivered to one specific thread, and not to an arbitrary thread. 2. A program that used kill() or alarm() not intending to run a signal handler, but rather intending to interrupt a sleeping system call like sleep() or read(). Our kill() does not interrupt sleeping OSv function calls, which will continue to sleep on the thread they run on. The support in this patch (and see next patch, for alarm()) is good enough for netperf's use of alarm(). P.S. kill() can be used only to send a signal to the current process, the only process we have in OSv (you can also use pid=0 and pid=-1 to achieve the same results). This patch also adds a test for kill() and alarm(). The alarm() test will fail until the next patch :-) Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
- Loading branch information
Showing
4 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright (C) 2013 Cloudius Systems, Ltd. | ||
* | ||
* This work is open source software, licensed under the terms of the | ||
* BSD license as described in the LICENSE file in the top-level directory. | ||
*/ | ||
|
||
// Test for kill() and alarm() approximations in libc/signal.cc | ||
|
||
#include <sys/types.h> | ||
#include <signal.h> | ||
|
||
#include "debug.hh" | ||
|
||
int tests = 0, fails = 0; | ||
|
||
static void report(bool ok, const char* msg) | ||
{ | ||
++tests; | ||
fails += !ok; | ||
debug("%s: %s\n", (ok ? "PASS" : "FAIL"), msg); | ||
} | ||
|
||
int global = 0; | ||
|
||
void handler1(int sig) { | ||
debug("handler1 called, sig=%d\n", sig); | ||
global = 1; | ||
} | ||
|
||
int main(int ac, char** av) | ||
{ | ||
// Test kill() of current process: | ||
report (global == 0, "'global' initially 0"); | ||
auto sr = signal(SIGUSR1, handler1); | ||
report(sr != SIG_ERR, "set SIGUSR1 handler"); | ||
int r; | ||
r = kill(0, SIGUSR1); | ||
report(r == 0, "kill SIGUSR1 succeeds"); | ||
for (int i=0; i<100; i++) { | ||
if (global == 1) break; | ||
usleep(10000); | ||
} | ||
report(global == 1, "'global' is now 1"); | ||
// Test various edge cases for kill(): | ||
r = kill(0, 0); | ||
report(r == 0, "kill with signal 0 succeeds (and does nothing)"); | ||
r = kill(-1, 0); | ||
report(r == 0, "kill of pid -1 is also fine"); | ||
r = kill(17, 0); | ||
report(r == -1 && errno == ESRCH, "kill of non-existant process"); | ||
r = kill(0, -2); | ||
report(r == -1 && errno == EINVAL, "kill with invalid signal number"); | ||
r = kill(0, 12345); | ||
report(r == -1 && errno == EINVAL, "kill with invalid signal number"); | ||
|
||
// Test alarm(); | ||
global = 0; | ||
sr = signal(SIGALRM, handler1); | ||
report(sr != SIG_ERR, "set SIGALRM handler"); | ||
auto ar = alarm(1); | ||
report(ar == 0, "set alarm for 1 second - no previous alarm"); | ||
usleep(500000); | ||
report(global == 0, "after 0.5 seconds - still global==0"); | ||
sleep(1); | ||
report(global == 1, "after 1 more second - now global==1"); | ||
|
||
// Test cancel of alarm(); | ||
global = 0; | ||
ar = alarm(1); | ||
report(ar == 0, "set alarm for 1 second - no previous alarm"); | ||
usleep(500000); | ||
report(global == 0, "after 0.5 seconds - still global==0"); | ||
ar = alarm(0); | ||
sleep(1); | ||
report(global == 0, "1 more second after cancelling alarm - still global==0"); | ||
|
||
debug("SUMMARY: %d tests, %d failures\n", tests, fails); | ||
} | ||
|
||
|