Use atoms to represent signals

Accept and return signals as names. For example, if a signal is trapped,
the process will receive:

    {signal,'SIGCHLD'}

Versus:

    {signal,17} % on linux

Benefits:

* similar to the way errno is returned, e.g., {errno,enametoolong}

* better portability: integer values differ by platform

* library user does not need lookup the signal value before calling
  sigaction/3,4 or pattern matching the process mailbox

Problems:

* sigaction/3,4 will throw badarg if the name is unknown

  Probably it should return an error ({error,einval}).

* not all functions dealing with signals have been changed to use atoms,
  e.g., kill/3,4

* all functions with mapping of constants -> integers should take
  constants:

    clone_define
    mount_define
    file_define
    prctl_define
    rlimit_define
    syscall_define

  If this is done, alcove:define/2,3 and the *_define/*_constant functions
  should be removed.

* should the constants be upper or lower case atoms?

  atoms are typically lowercased, e.g., {error,ebadf} not
  {error,'EBADF'}

  For example:

    PR_SET_PDEATHSIG -> pr_set_pdeathsig

* if the interface accepts constants, should support for integers be
  removed?

  1. No way to pass in a "raw" signum if the signal does not have a name

  2. Signals without a name will be sent to the process mailbox as:

        {signal,unknown}

     If the caller has trapped 58 and 59, there won't be a way to
     distinguish these signals.
This commit is contained in:
Michael Santos
2014-09-14 10:46:14 -04:00
parent b89012b12c
commit 84c7d2aed1
8 changed files with 31 additions and 32 deletions

View File

@@ -225,9 +225,7 @@ true
% If we check the parent for events, we can see the child has exited
10> alcove:event(P).
{signal,17}
11> alcove:signal_constant(P, 17).
'SIGCHLD'
{signal,'SIGCHLD'}
```
Creating a Container Using Linux Namespaces
@@ -440,14 +438,12 @@ probably confuse the process.
environ(7) : return the process environment variables
event(Drv) -> {Tag, Val} | false
event(Drv, Pids) -> {Tag, Val} | false
Types Tag = signal
Val = integer()
event(Drv) -> term()
event(Drv, Pids) -> term()
event/1,2 is used to retrieve async messages returned from the
port, such as trapped signals.
port, such as trapped signals, the exit status or the termination
signal.
execve(Drv, Arg0, [Arg0, Args], Env) -> ok | {error, posix()}
execve(Drv, Pids, Arg0, [Arg0, Args], Env) -> ok | {error, posix()}
@@ -542,7 +538,7 @@ probably confuse the process.
Sets the maximum length of the fork path.
termisg : 1 | 0 : 0
termsig : 1 | 0 : 0
If a child process exits because of a signal, notify
the controlling Erlang process.
@@ -796,7 +792,7 @@ probably confuse the process.
sigaction(Drv, Signum, Handler) -> ok | {error, posix()}
sigaction(Drv, Pids, Signum, Handler) -> ok | {error, posix()}
Types Signum = integer()
Types Signum = integer() | atom()
Handler = dfl | ign | trap
sigaction(2) : set process behaviour for signals

View File

@@ -536,8 +536,8 @@ specs() ->
-spec setuid(alcove_drv:ref(),non_neg_integer()) -> 'ok' | {'error', file:posix()}.
-spec setuid(alcove_drv:ref(),fork_path(),non_neg_integer()) -> 'ok' | {'error', file:posix()}.
-spec sigaction(alcove_drv:ref(),integer(),atom()) -> 'ok' | {'error', file:posix()}.
-spec sigaction(alcove_drv:ref(),fork_path(),integer(),atom()) -> 'ok' | {'error', file:posix()}.
-spec sigaction(alcove_drv:ref(),integer() | atom(),atom()) -> 'ok' | {'error', file:posix()}.
-spec sigaction(alcove_drv:ref(),fork_path(),integer() | atom(),atom()) -> 'ok' | {'error', file:posix()}.
-spec signal_constant(alcove_drv:ref(),non_neg_integer()) -> 'unknown' | atom().
-spec signal_constant(alcove_drv:ref(),fork_path(),non_neg_integer()) -> 'unknown' | atom().

View File

@@ -583,7 +583,7 @@ exited_pid(alcove_state_t *ap, alcove_child_t *c, void *arg1, void *arg2)
if (WIFSIGNALED(*status) && (ap->opt & alcove_opt_termsig)) {
ALCOVE_TUPLE2(t, &index,
"termsig",
ei_encode_long(t, &index, WTERMSIG(*status))
alcove_signal_name(t, sizeof(t), &index, WTERMSIG(*status))
);
if (alcove_call_fake_reply(c->pid, ALCOVE_MSG_EVENT, t, index) < 0)
@@ -745,7 +745,7 @@ alcove_handle_signal(alcove_state_t *ap) {
ALCOVE_TUPLE2(reply, &index,
"signal",
ei_encode_long(reply, &index, signum)
alcove_signal_name(reply, sizeof(reply), &index, signum)
);
if (alcove_call_reply(ALCOVE_MSG_EVENT, reply, index) < 0)

View File

@@ -162,6 +162,8 @@ int pid_foreach(alcove_state_t *ap, pid_t pid, void *arg1, void *arg2,
int pid_equal(pid_t p1, pid_t p2);
int pid_not_equal(pid_t p1, pid_t p2);
ssize_t alcove_signal_name(char *, size_t, int *, int);
int alcove_get_type(const char *, size_t, const int *, int *, int *);
int alcove_decode_int(const char *, size_t, int *, int *);
int alcove_decode_uint(const char *, size_t, int *, u_int32_t *);

View File

@@ -161,3 +161,10 @@ alcove_signal_constant(alcove_state_t *ap, const char *arg, size_t len,
return rindex;
}
ssize_t
alcove_signal_name(char *buf, size_t len, int *index, int signum)
{
return alcove_encode_constant(buf, len, index, signum,
alcove_signal_constants);
}

View File

@@ -1,7 +1,7 @@
{application, alcove,
[
{description, "Erlang application container/sandbox"},
{vsn, "0.8.1"},
{vsn, "0.9.0"},
{registered, []},
{applications, [
kernel,

View File

@@ -62,8 +62,6 @@ stop(#state{pid = Drv}) ->
alcove_drv:stop(Drv).
kill(#state{pid = Drv}) ->
SIGSYS = alcove:define(Drv, 'SIGSYS'),
{ok, Pid} = alcove:fork(Drv),
enforce(Drv, [Pid], ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_KILL)),
% Allowed: cached by process
@@ -80,7 +78,7 @@ kill(#state{pid = Drv}) ->
[
?_assertEqual(Pid, Reply0),
?_assertEqual({termsig, SIGSYS}, Event),
?_assertEqual({termsig, 'SIGSYS'}, Event),
?_assertEqual({error, esrch}, Reply3)
].
@@ -99,10 +97,8 @@ allow(#state{pid = Drv}) ->
].
trap(#state{pid = Drv}) ->
SIGSYS = alcove:define(Drv, 'SIGSYS'),
{ok, Pid} = alcove:fork(Drv),
ok = alcove:sigaction(Drv, [Pid], SIGSYS, trap),
ok = alcove:sigaction(Drv, [Pid], 'SIGSYS', trap),
enforce(Drv, [Pid], ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_TRAP)),
@@ -125,7 +121,7 @@ trap(#state{pid = Drv}) ->
[
?_assertEqual(Pid, Reply0),
?_assertEqual(true, Reply1),
?_assertEqual({signal, SIGSYS}, Event),
?_assertEqual({signal, 'SIGSYS'}, Event),
?_assertEqual(ok, Reply3)
].

View File

@@ -78,8 +78,7 @@ start() ->
{ok, Drv} = alcove_drv:start([{exec, Exec}, {maxchild, 8}]),
SIGCHLD = alcove:define(Drv, 'SIGCHLD'),
ok = alcove:sigaction(Drv, SIGCHLD, trap),
ok = alcove:sigaction(Drv, 'SIGCHLD', trap),
case {Use_fork, os:type()} of
{false, {unix,linux} = OS} ->
@@ -399,14 +398,14 @@ badpid(#state{pid = Drv}) ->
signal(#state{pid = Drv}) ->
{ok, Child1} = alcove:fork(Drv),
TERM = alcove:signal_define(Drv, 'SIGTERM'),
SIGTERM = alcove:signal_define(Drv, 'SIGTERM'),
SA0 = alcove:sigaction(Drv, [Child1], TERM, ign),
Kill0 = alcove:kill(Drv, Child1, TERM),
SA0 = alcove:sigaction(Drv, [Child1], SIGTERM, ign),
Kill0 = alcove:kill(Drv, Child1, SIGTERM),
Pid0 = alcove:getpid(Drv, [Child1]),
SA1 = alcove:sigaction(Drv, [Child1], TERM, dfl),
Kill1 = alcove:kill(Drv, Child1, TERM),
SA1 = alcove:sigaction(Drv, [Child1], 'SIGTERM', dfl),
Kill1 = alcove:kill(Drv, Child1, SIGTERM),
waitpid(Drv, [], Child1),
alcove:kill(Drv, Child1, 0),
Search = alcove:kill(Drv, Child1, 0),
@@ -613,9 +612,8 @@ getenv(Name, Default) ->
end.
waitpid(Drv, Pids, Child) ->
SIGCHLD = alcove:signal_define(Drv, 'SIGCHLD'),
case alcove:event(Drv, Pids, 5000) of
{signal, SIGCHLD} ->
{signal, 'SIGCHLD'} ->
waitpid_1(Drv, Pids, Child);
false ->
false