To ensure consistency, exit if a timeout is set and reached. Otherwise,
late messages may arrive in the queue, messing up subsequent calls:
1> {ok,P} = alcove_drv:start().
{ok,<0.45.0>}
2> catch alcove:call(P, [], getpid, [], 0).
{'EXIT',timeout}
3> alcove:version(P).
2897
4> flush().
Shell got {alcove_call,<0.45.0>,[],<<"0.6.1">>}
ok
Using timeouts might be needed if it is not known whether is still
running in the event loop.
Remove the cast functions, since they are dangerous and can be emulated
by using call/5.
Fix the code to match the documentation and add a call with timeout.
Simplify the alcove_drv module by removing the versions of call with
defaults. The alcove module does the work of setting default values.
Do not crash if the caller attempts to write to a non-existent process:
{ok, Drv} = alcove_drv:start(),
{ok, Fork} = alcove:fork(Drv),
ok = alcove:execvp(Drv, [Fork], "/bin/echo", ["/bin/echo", "test"]),
% will hang forever instead of crashing
ok = alcove:execvp(Drv, [Fork], "/bin/echo", ["/bin/echo", "test"]).
There are 2 common failure cases are:
* the PID is not found, pid_foreach() returns 1
* the write fails because the child has exited (EPIPE)
write(2) on Linux documents the following errno values:
* EAGAIN, EINTR: should be dealt with by using completing partial writes
* EBADF, EINVAL: since the event loop manages the fd's and the fd's
are not accessible by the caller, should be harmless to ignore errors
The issue is if the child process can end up in an inconsistent state.
If it is possible, then it is better for the parent process to crash.
This code looked fishy to me but I couldn't pinpoint why and it worked on
Ubuntu 12.04/armv7l, Ubuntu 12.04/amd64, OpenBSD 5.5/amd64 and FreeBSD
10/amd64. I forgot to test on Ubuntu 14.04/amd64 of course and
thankfully it failed there.
The code compares the number of bytes written by writev against each of
the iov_len fields in the iovec array and decrements the value
accordingly. So an iovec array that looks like:
iov[0].iov_len = 4
iov[1].iov_len = 6
number of bytes written = 10 bytes
Would be computed as follows:
count = 2
0: 10 >= iov[0].iov_len (4) -> 6
1: 6 >= iov[1].iov_len (6) -> 0
2: 0 >= iov[2].iov_len (undefined) -> ???
3: ...
Limit iteration to the size of the iovec array. Although this commit fixes
this issue, this code should either be further simplified or re-written.
Currently, alloc/2,3 tests functionality that only is needed for linux
(for seccomp mode). Run the tests on other plaforms like freebsd, so we
can catch any bugs.
Cleanup of the setopt function:
* use an unsigned integer for holding the arg
* add a typespec for setopt/3,4.
* change the return value to true/false
Previously, if an unknown option was passed to setopt, the process would
crash with badarg. Reserve badarg for wrong types and return a value to
the caller.
inet:getopts/setopts take a list of options. If any of the options are
invalid, {error,einval} is returned to the caller. The valid options are
not changed.
alcove:getopt/2,3 returns an unsigned integer or false if the option is
not supported.
alcove:getopt,setopt will (should?) never fail if a valid argument is
used. So replying with an ok tuple, like the inet functions, is not necessary.
So setopt could more exactly return 'ok' and 'invalid' or 'not_found'
(diverging from getopt) or it could follow getopt and return ok/false,
which, to be more consistent, should be a boolean.