mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
Noux: add basic 'Ctrl-C' support
This patch implements the POSIX signal functionality needed to interrupt a running Noux GDB by pressing 'Ctrl-C'. It allows to register a signal handler for the 'SIGINT' signal, which gets executed after 'Ctrl-C' is received from the terminal. With the current state of the implementation, the signal handler only gets executed when the Noux application calls a 'read()', 'write()', 'ftruncate()' or 'select()' syscall. Fixes #923.
This commit is contained in:
parent
cf040e2833
commit
047d851fb6
@ -19,6 +19,7 @@
|
||||
#define _INCLUDE__NOUX_SESSION__SYSIO_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/ring_buffer.h>
|
||||
#include <util/misc_math.h>
|
||||
|
||||
|
||||
@ -33,16 +34,14 @@ namespace Noux {
|
||||
|
||||
struct Sysio
|
||||
{
|
||||
/*
|
||||
* Information about pending signals
|
||||
*/
|
||||
enum { SIG_MAX = 32 };
|
||||
bool sig_mask[SIG_MAX];
|
||||
/* signal numbers must match with libc signal numbers */
|
||||
enum Signal {
|
||||
SIG_INT = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of pending signals
|
||||
*/
|
||||
int sig_cnt;
|
||||
enum { SIGNAL_QUEUE_SIZE = 32 };
|
||||
Ring_buffer<enum Signal, SIGNAL_QUEUE_SIZE,
|
||||
Ring_buffer_unsynchronized> pending_signals;
|
||||
|
||||
enum { MAX_PATH_LEN = 512 };
|
||||
typedef char Path[MAX_PATH_LEN];
|
||||
@ -295,10 +294,12 @@ namespace Noux {
|
||||
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
|
||||
enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS };
|
||||
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
|
||||
enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS };
|
||||
enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS,
|
||||
FTRUNCATE_ERR_INTERRUPT };
|
||||
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
|
||||
OPEN_ERR_EXISTS };
|
||||
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
|
||||
enum Select_error { SELECT_ERR_INTERRUPT };
|
||||
enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
|
||||
enum Readlink_error { READLINK_ERR_NO_ENTRY };
|
||||
enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,
|
||||
@ -310,10 +311,12 @@ namespace Noux {
|
||||
SYMLINK_ERR_NAME_TOO_LONG};
|
||||
|
||||
enum Read_error { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
|
||||
READ_ERR_INVALID, READ_ERR_IO };
|
||||
READ_ERR_INVALID, READ_ERR_IO,
|
||||
READ_ERR_INTERRUPT };
|
||||
|
||||
enum Write_error { WRITE_ERR_AGAIN, WRITE_ERR_WOULD_BLOCK,
|
||||
WRITE_ERR_INVALID, WRITE_ERR_IO };
|
||||
WRITE_ERR_INVALID, WRITE_ERR_IO,
|
||||
WRITE_ERR_INTERRUPT };
|
||||
|
||||
enum Ioctl_error { IOCTL_ERR_INVALID, IOCTL_ERR_NOTTY };
|
||||
|
||||
@ -361,6 +364,7 @@ namespace Noux {
|
||||
Ftruncate_error ftruncate;
|
||||
Open_error open;
|
||||
Execve_error execve;
|
||||
Select_error select;
|
||||
Unlink_error unlink;
|
||||
Readlink_error readlink;
|
||||
Rename_error rename;
|
||||
|
103
ports/run/noux_signals.run
Normal file
103
ports/run/noux_signals.run
Normal file
@ -0,0 +1,103 @@
|
||||
set build_components {
|
||||
core init drivers/timer drivers/uart
|
||||
noux/minimal
|
||||
test/noux_signals
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
# create tar archive
|
||||
exec tar cfv bin/noux_signals.tar -h -C bin test-noux_signals
|
||||
|
||||
create_boot_directory
|
||||
|
||||
append config {
|
||||
<config verbose="yes">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="LOG"/>
|
||||
<service name="CAP"/>
|
||||
<service name="RAM"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="PD"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <any-child/> <parent/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="uart_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Terminal"/></provides>
|
||||
<config>
|
||||
<policy label="noux" uart="1"/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="noux">
|
||||
<resource name="RAM" quantum="1G"/>
|
||||
<config verbose="yes">
|
||||
<fstab> <tar name="noux_signals.tar" /> </fstab>
|
||||
<start name="test-noux_signals"> </start>
|
||||
</config>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
set boot_modules {
|
||||
core init timer ld.lib.so noux libc.lib.so
|
||||
uart_drv libc_noux.lib.so noux_signals.tar
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
#
|
||||
# Redirect the LOG session output of Noux into a file
|
||||
#
|
||||
set noux_output_file "noux_signals.log"
|
||||
|
||||
append qemu_args " -nographic"
|
||||
append qemu_args " -serial file:$noux_output_file"
|
||||
append qemu_args " -serial mon:stdio"
|
||||
|
||||
run_genode_until "test ready" 10
|
||||
|
||||
# send Ctrl-C
|
||||
send \003
|
||||
|
||||
run_genode_until "test finished" 10 $spawn_id
|
||||
|
||||
set error_occured 0
|
||||
|
||||
if {![regexp {0: signal handler for signal 2 called} $output]} {
|
||||
set error_occured 1
|
||||
}
|
||||
|
||||
if {![regexp {1: signal handler for signal 2 called} $output]} {
|
||||
set error_occured 1
|
||||
}
|
||||
|
||||
if {![regexp {0: 'read\(\)' returned with error EINTR} $output]} {
|
||||
set error_occured 1
|
||||
}
|
||||
|
||||
if {![regexp {1: 'read\(\)' returned with error EINTR} $output]} {
|
||||
set error_occured 1
|
||||
}
|
||||
|
||||
if { $error_occured == 1 } {
|
||||
puts "output not as expected"
|
||||
exit -1
|
||||
}
|
||||
|
||||
exec rm bin/noux_signals.tar
|
||||
exec rm $noux_output_file
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <libc_mem_alloc.h>
|
||||
|
||||
enum { verbose = false };
|
||||
enum { verbose_signals = false };
|
||||
|
||||
|
||||
void *operator new (size_t, void *ptr) { return ptr; }
|
||||
@ -89,6 +90,34 @@ Noux::Session *noux() { return noux_connection()->session(); }
|
||||
Noux::Sysio *sysio() { return noux_connection()->sysio(); }
|
||||
|
||||
|
||||
/* Array of signal handlers */
|
||||
static struct sigaction signal_action[SIGRTMAX+1];
|
||||
|
||||
|
||||
static bool noux_syscall(Noux::Session::Syscall opcode)
|
||||
{
|
||||
bool ret = noux()->syscall(opcode);
|
||||
|
||||
/* handle signals */
|
||||
while (!sysio()->pending_signals.empty()) {
|
||||
Noux::Sysio::Signal signal = sysio()->pending_signals.get();
|
||||
if (signal_action[signal].sa_flags & SA_SIGINFO) {
|
||||
/* TODO: pass siginfo_t struct */
|
||||
signal_action[signal].sa_sigaction(signal, 0, 0);
|
||||
} else {
|
||||
if (signal_action[signal].sa_handler == SIG_DFL) {
|
||||
/* do nothing */
|
||||
} else if (signal_action[signal].sa_handler == SIG_IGN) {
|
||||
/* do nothing */
|
||||
} else
|
||||
signal_action[signal].sa_handler(signal);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
enum { FS_BLOCK_SIZE = 1024 };
|
||||
|
||||
|
||||
@ -124,7 +153,7 @@ extern "C" struct passwd *getpwuid(uid_t uid)
|
||||
sysio()->userinfo_in.uid = uid;
|
||||
sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_ALL;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_USERINFO)) {
|
||||
return (struct passwd *)0;
|
||||
}
|
||||
|
||||
@ -144,7 +173,7 @@ extern "C" uid_t getgid()
|
||||
{
|
||||
sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_GID;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO))
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_USERINFO))
|
||||
return 0;
|
||||
|
||||
uid_t gid = sysio()->userinfo_out.gid;
|
||||
@ -162,7 +191,7 @@ extern "C" uid_t getuid()
|
||||
{
|
||||
sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_UID;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO))
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_USERINFO))
|
||||
return 0;
|
||||
|
||||
uid_t uid = sysio()->userinfo_out.uid;
|
||||
@ -364,11 +393,10 @@ extern "C" int select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
/*
|
||||
* Perform syscall
|
||||
*/
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SELECT)) {
|
||||
PWRN("select syscall failed");
|
||||
// switch (sysio()->error.select) {
|
||||
// case Noux::Sysio::SELECT_NONEXISTENT: errno = ENOENT; break;
|
||||
// }
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SELECT)) {
|
||||
switch (sysio()->error.select) {
|
||||
case Noux::Sysio::SELECT_ERR_INTERRUPT: errno = EINTR; break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -444,7 +472,7 @@ extern "C" pid_t fork(void)
|
||||
sysio()->fork_in.sp = (Genode::addr_t)(&stack[STACK_SIZE]);
|
||||
sysio()->fork_in.parent_cap_addr = (Genode::addr_t)(&new_parent);
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_FORK)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_FORK)) {
|
||||
PERR("fork error %d", sysio()->error.general);
|
||||
}
|
||||
|
||||
@ -458,7 +486,7 @@ extern "C" pid_t vfork(void) { return fork(); }
|
||||
|
||||
extern "C" pid_t getpid(void)
|
||||
{
|
||||
noux()->syscall(Noux::Session::SYSCALL_GETPID);
|
||||
noux_syscall(Noux::Session::SYSCALL_GETPID);
|
||||
return sysio()->getpid_out.pid;
|
||||
}
|
||||
|
||||
@ -493,7 +521,7 @@ extern "C" pid_t _wait4(pid_t pid, int *status, int options,
|
||||
{
|
||||
sysio()->wait4_in.pid = pid;
|
||||
sysio()->wait4_in.nohang = !!(options & WNOHANG);
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_WAIT4)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_WAIT4)) {
|
||||
PERR("wait4 error %d", sysio()->error.general);
|
||||
return -1;
|
||||
}
|
||||
@ -545,7 +573,7 @@ extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_CLOCK_GETTIME)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_CLOCK_GETTIME)) {
|
||||
switch (sysio()->error.clock) {
|
||||
case Noux::Sysio::CLOCK_ERR_INVALID: errno = EINVAL; break;
|
||||
default: errno = 0; break;
|
||||
@ -563,7 +591,7 @@ extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
|
||||
extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_GETTIMEOFDAY)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_GETTIMEOFDAY)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -577,7 +605,7 @@ extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
|
||||
extern "C" int utimes(const char* path, const struct timeval *times)
|
||||
{
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_UTIMES)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_UTIMES)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -604,20 +632,30 @@ extern "C" int _sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
}
|
||||
|
||||
|
||||
extern "C" int _sigaction(int, const struct sigaction *, struct sigaction *)
|
||||
extern "C" int _sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
|
||||
{
|
||||
/* XXX todo */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (verbose_signals)
|
||||
PDBG("signum = %d, handler = %p", signum, act ? act->sa_handler : 0);
|
||||
|
||||
if ((signum < 0) || (signum > SIGRTMAX)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oldact)
|
||||
*oldact = signal_action[signum];
|
||||
|
||||
if (act)
|
||||
signal_action[signum] = *act;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int sigaction(int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
{
|
||||
/* XXX todo */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return _sigaction(signum, act, oldact);
|
||||
}
|
||||
|
||||
|
||||
@ -771,7 +809,7 @@ namespace {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_EXECVE)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_EXECVE)) {
|
||||
PWRN("exec syscall failed for path \"%s\"", filename);
|
||||
switch (sysio()->error.execve) {
|
||||
case Noux::Sysio::EXECVE_NONEXISTENT: errno = ENOENT; break;
|
||||
@ -800,7 +838,7 @@ namespace {
|
||||
|
||||
Genode::strncpy(sysio()->stat_in.path, path, sizeof(sysio()->stat_in.path));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_STAT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_STAT)) {
|
||||
if (verbose)
|
||||
PWRN("stat syscall failed for path \"%s\"", path);
|
||||
switch (sysio()->error.stat) {
|
||||
@ -826,7 +864,7 @@ namespace {
|
||||
while (!opened) {
|
||||
Genode::strncpy(sysio()->open_in.path, pathname, sizeof(sysio()->open_in.path));
|
||||
sysio()->open_in.mode = flags;
|
||||
if (noux()->syscall(Noux::Session::SYSCALL_OPEN))
|
||||
if (noux_syscall(Noux::Session::SYSCALL_OPEN))
|
||||
opened = true;
|
||||
else
|
||||
switch (sysio()->error.open) {
|
||||
@ -838,7 +876,7 @@ namespace {
|
||||
/* O_CREAT is set, so try to create the file */
|
||||
Genode::strncpy(sysio()->open_in.path, pathname, sizeof(sysio()->open_in.path));
|
||||
sysio()->open_in.mode = flags | O_EXCL;
|
||||
if (noux()->syscall(Noux::Session::SYSCALL_OPEN))
|
||||
if (noux_syscall(Noux::Session::SYSCALL_OPEN))
|
||||
opened = true;
|
||||
else
|
||||
switch (sysio()->error.open) {
|
||||
@ -878,7 +916,7 @@ namespace {
|
||||
|
||||
Genode::strncpy(sysio()->symlink_in.oldpath, oldpath, sizeof(sysio()->symlink_in.oldpath));
|
||||
Genode::strncpy(sysio()->symlink_in.newpath, newpath, sizeof(sysio()->symlink_in.newpath));
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SYMLINK)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SYMLINK)) {
|
||||
PERR("symlink error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -910,12 +948,13 @@ namespace {
|
||||
sysio()->write_in.count = curr_count;
|
||||
Genode::memcpy(sysio()->write_in.chunk, src, curr_count);
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_WRITE)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_WRITE)) {
|
||||
switch (sysio()->error.write) {
|
||||
case Noux::Sysio::WRITE_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::WRITE_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
|
||||
case Noux::Sysio::WRITE_ERR_INVALID: errno = EINVAL; break;
|
||||
case Noux::Sysio::WRITE_ERR_IO: errno = EIO; break;
|
||||
case Noux::Sysio::WRITE_ERR_INTERRUPT: errno = EINTR; break;
|
||||
default:
|
||||
if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID)
|
||||
errno = EBADF;
|
||||
@ -944,12 +983,14 @@ namespace {
|
||||
sysio()->read_in.fd = noux_fd(fd->context);
|
||||
sysio()->read_in.count = curr_count;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_READ)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_READ)) {
|
||||
|
||||
switch (sysio()->error.read) {
|
||||
case Noux::Sysio::READ_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::READ_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
|
||||
case Noux::Sysio::READ_ERR_INVALID: errno = EINVAL; break;
|
||||
case Noux::Sysio::READ_ERR_IO: errno = EIO; break;
|
||||
case Noux::Sysio::READ_ERR_INTERRUPT: errno = EINTR; break;
|
||||
default:
|
||||
if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID)
|
||||
errno = EBADF;
|
||||
@ -982,7 +1023,7 @@ namespace {
|
||||
int Plugin::close(Libc::File_descriptor *fd)
|
||||
{
|
||||
sysio()->close_in.fd = noux_fd(fd->context);
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_CLOSE)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_CLOSE)) {
|
||||
PERR("close error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -1080,7 +1121,7 @@ namespace {
|
||||
}
|
||||
|
||||
/* perform syscall */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_IOCTL)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_IOCTL)) {
|
||||
switch (sysio()->error.ioctl) {
|
||||
case Noux::Sysio::IOCTL_ERR_INVALID: errno = EINVAL; break;
|
||||
case Noux::Sysio::IOCTL_ERR_NOTTY: errno = ENOTTY; break;
|
||||
@ -1118,7 +1159,7 @@ namespace {
|
||||
int Plugin::pipe(Libc::File_descriptor *pipefd[2])
|
||||
{
|
||||
/* perform syscall */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_PIPE)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_PIPE)) {
|
||||
PERR("pipe error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -1137,7 +1178,7 @@ namespace {
|
||||
sysio()->dup2_in.fd = noux_fd(fd->context);
|
||||
sysio()->dup2_in.to_fd = -1;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_DUP2)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_DUP2)) {
|
||||
PERR("dup error");
|
||||
/* XXX set errno */
|
||||
return 0;
|
||||
@ -1160,7 +1201,7 @@ namespace {
|
||||
sysio()->dup2_in.to_fd = noux_fd(new_fd->context);
|
||||
|
||||
/* perform syscall */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_DUP2)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_DUP2)) {
|
||||
PERR("dup2 error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -1173,7 +1214,7 @@ namespace {
|
||||
int Plugin::fstat(Libc::File_descriptor *fd, struct stat *buf)
|
||||
{
|
||||
sysio()->fstat_in.fd = noux_fd(fd->context);
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_FSTAT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_FSTAT)) {
|
||||
PERR("fstat error");
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -1196,9 +1237,10 @@ namespace {
|
||||
{
|
||||
sysio()->ftruncate_in.fd = noux_fd(fd->context);
|
||||
sysio()->ftruncate_in.length = length;
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_FTRUNCATE)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_FTRUNCATE)) {
|
||||
switch (sysio()->error.ftruncate) {
|
||||
case Noux::Sysio::FTRUNCATE_ERR_NO_PERM: errno = EPERM; break;
|
||||
case Noux::Sysio::FTRUNCATE_ERR_INTERRUPT: errno = EINTR; break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -1271,10 +1313,16 @@ namespace {
|
||||
};
|
||||
|
||||
/* invoke system call */
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_FCNTL)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_FCNTL)) {
|
||||
PWRN("fcntl failed (libc_fd= %d, cmd=%x)", fd->libc_fd, cmd);
|
||||
/* XXX read error code from sysio */
|
||||
errno = EINVAL;
|
||||
switch (sysio()->error.fcntl) {
|
||||
case Noux::Sysio::FCNTL_ERR_CMD_INVALID: errno = EINVAL; break;
|
||||
default:
|
||||
switch (sysio()->error.general) {
|
||||
case Noux::Sysio::ERR_FD_INVALID: errno = EINVAL; break;
|
||||
case Noux::Sysio::NUM_GENERAL_ERRORS: break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1296,7 +1344,7 @@ namespace {
|
||||
struct dirent *dirent = (struct dirent *)buf;
|
||||
Genode::memset(dirent, 0, sizeof(struct dirent));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_DIRENT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_DIRENT)) {
|
||||
switch (sysio()->error.general) {
|
||||
|
||||
case Noux::Sysio::ERR_FD_INVALID:
|
||||
@ -1343,7 +1391,7 @@ namespace {
|
||||
case SEEK_END: sysio()->lseek_in.whence = Noux::Sysio::LSEEK_END; break;
|
||||
}
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_LSEEK)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_LSEEK)) {
|
||||
switch (sysio()->error.general) {
|
||||
|
||||
case Noux::Sysio::ERR_FD_INVALID:
|
||||
@ -1363,7 +1411,7 @@ namespace {
|
||||
{
|
||||
Genode::strncpy(sysio()->unlink_in.path, path, sizeof(sysio()->unlink_in.path));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_UNLINK)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_UNLINK)) {
|
||||
PWRN("unlink syscall failed for path \"%s\"", path);
|
||||
switch (sysio()->error.unlink) {
|
||||
case Noux::Sysio::UNLINK_ERR_NO_ENTRY: errno = ENOENT; break;
|
||||
@ -1384,7 +1432,7 @@ namespace {
|
||||
Genode::strncpy(sysio()->readlink_in.path, path, sizeof(sysio()->readlink_in.path));
|
||||
sysio()->readlink_in.bufsiz = bufsiz;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_READLINK)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_READLINK)) {
|
||||
PWRN("readlink syscall failed for \"%s\"", path);
|
||||
/* XXX set errno */
|
||||
return -1;
|
||||
@ -1406,7 +1454,7 @@ namespace {
|
||||
Genode::strncpy(sysio()->rename_in.from_path, from_path, sizeof(sysio()->rename_in.from_path));
|
||||
Genode::strncpy(sysio()->rename_in.to_path, to_path, sizeof(sysio()->rename_in.to_path));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_RENAME)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_RENAME)) {
|
||||
PWRN("rename syscall failed for \"%s\" -> \"%s\"", from_path, to_path);
|
||||
switch (sysio()->error.rename) {
|
||||
case Noux::Sysio::RENAME_ERR_NO_ENTRY: errno = ENOENT; break;
|
||||
@ -1425,7 +1473,7 @@ namespace {
|
||||
{
|
||||
Genode::strncpy(sysio()->mkdir_in.path, path, sizeof(sysio()->mkdir_in.path));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_MKDIR)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_MKDIR)) {
|
||||
PWRN("mkdir syscall failed for \"%s\" mode=0x%x", path, (int)mode);
|
||||
switch (sysio()->error.mkdir) {
|
||||
case Noux::Sysio::MKDIR_ERR_EXISTS: errno = EEXIST; break;
|
||||
@ -1486,7 +1534,7 @@ namespace {
|
||||
sysio()->socket_in.type = type;
|
||||
sysio()->socket_in.protocol = protocol;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SOCKET))
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SOCKET))
|
||||
return 0;
|
||||
|
||||
Libc::Plugin_context *context = noux_context(sysio()->socket_out.fd);
|
||||
@ -1507,7 +1555,7 @@ namespace {
|
||||
Genode::memset(sysio()->getsockopt_in.optval, 0,
|
||||
sizeof (sysio()->getsockopt_in.optval));
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_GETSOCKOPT))
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_GETSOCKOPT))
|
||||
return -1;
|
||||
|
||||
Genode::memcpy(optval, sysio()->setsockopt_in.optval,
|
||||
@ -1532,7 +1580,7 @@ namespace {
|
||||
|
||||
Genode::memcpy(sysio()->setsockopt_in.optval, optval, optlen);
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SETSOCKOPT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SETSOCKOPT)) {
|
||||
/* XXX */
|
||||
return -1;
|
||||
}
|
||||
@ -1555,7 +1603,7 @@ namespace {
|
||||
sysio()->accept_in.addrlen = 0;
|
||||
}
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_ACCEPT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_ACCEPT)) {
|
||||
switch (sysio()->error.accept) {
|
||||
case Noux::Sysio::ACCEPT_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::ACCEPT_ERR_NO_MEMORY: errno = ENOMEM; break;
|
||||
@ -1585,7 +1633,7 @@ namespace {
|
||||
Genode::memcpy(&sysio()->bind_in.addr, addr, sizeof (struct sockaddr));
|
||||
sysio()->bind_in.addrlen = addrlen;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_BIND)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_BIND)) {
|
||||
switch (sysio()->error.bind) {
|
||||
case Noux::Sysio::BIND_ERR_ACCESS: errno = EACCES; break;
|
||||
case Noux::Sysio::BIND_ERR_ADDR_IN_USE: errno = EADDRINUSE; break;
|
||||
@ -1608,7 +1656,7 @@ namespace {
|
||||
Genode::memcpy(&sysio()->connect_in.addr, addr, sizeof (struct sockaddr));
|
||||
sysio()->connect_in.addrlen = addrlen;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_CONNECT)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_CONNECT)) {
|
||||
switch (sysio()->error.connect) {
|
||||
case Noux::Sysio::CONNECT_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::CONNECT_ERR_ALREADY: errno = EALREADY; break;
|
||||
@ -1630,7 +1678,7 @@ namespace {
|
||||
sysio()->getpeername_in.fd = noux_fd(fd->context);
|
||||
sysio()->getpeername_in.addrlen = *addrlen;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_GETPEERNAME)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_GETPEERNAME)) {
|
||||
/* errno */
|
||||
return -1;
|
||||
}
|
||||
@ -1648,7 +1696,7 @@ namespace {
|
||||
sysio()->listen_in.fd = noux_fd(fd->context);
|
||||
sysio()->listen_in.backlog = backlog;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_LISTEN)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_LISTEN)) {
|
||||
switch (sysio()->error.listen) {
|
||||
case Noux::Sysio::LISTEN_ERR_ADDR_IN_USE: errno = EADDRINUSE; break;
|
||||
case Noux::Sysio::LISTEN_ERR_NOT_SUPPORTED: errno = EOPNOTSUPP; break;
|
||||
@ -1672,7 +1720,7 @@ namespace {
|
||||
sysio()->recv_in.fd = noux_fd(fd->context);
|
||||
sysio()->recv_in.len = curr_len;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_RECV)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_RECV)) {
|
||||
switch (sysio()->error.recv) {
|
||||
case Noux::Sysio::RECV_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::RECV_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
|
||||
@ -1717,7 +1765,7 @@ namespace {
|
||||
else
|
||||
sysio()->recvfrom_in.addrlen = *addrlen;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_RECVFROM)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_RECVFROM)) {
|
||||
switch (sysio()->error.recv) {
|
||||
case Noux::Sysio::RECV_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::RECV_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
|
||||
@ -1765,7 +1813,7 @@ namespace {
|
||||
sysio()->send_in.len = curr_len;
|
||||
Genode::memcpy(sysio()->send_in.buf, src, curr_len);
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SEND)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SEND)) {
|
||||
PERR("write error %d", sysio()->error.general);
|
||||
switch (sysio()->error.send) {
|
||||
case Noux::Sysio::SEND_ERR_AGAIN: errno = EAGAIN; break;
|
||||
@ -1816,7 +1864,7 @@ namespace {
|
||||
Genode::memcpy(&sysio()->sendto_in.dest_addr, dest_addr, addrlen);
|
||||
}
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SENDTO)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SENDTO)) {
|
||||
switch (sysio()->error.send) {
|
||||
case Noux::Sysio::SEND_ERR_AGAIN: errno = EAGAIN; break;
|
||||
case Noux::Sysio::SEND_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
|
||||
@ -1842,7 +1890,7 @@ namespace {
|
||||
sysio()->shutdown_in.fd = noux_fd(fd->context);
|
||||
sysio()->shutdown_in.how = how;
|
||||
|
||||
if (!noux()->syscall(Noux::Session::SYSCALL_SHUTDOWN)) {
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_SHUTDOWN)) {
|
||||
switch (sysio()->error.shutdown) {
|
||||
case Noux::Sysio::SHUTDOWN_ERR_NOT_CONNECTED: errno = ENOTCONN; break;
|
||||
default: errno = 0; break;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <io_receptor_registry.h>
|
||||
#include <destruct_queue.h>
|
||||
#include <destruct_dispatcher.h>
|
||||
#include <interrupt_handler.h>
|
||||
|
||||
#include <local_cpu_service.h>
|
||||
#include <local_ram_service.h>
|
||||
@ -95,16 +96,22 @@ namespace Noux {
|
||||
class Child : public Rpc_object<Session>,
|
||||
public File_descriptor_registry,
|
||||
public Family_member,
|
||||
public Destruct_queue::Element<Child>
|
||||
public Destruct_queue::Element<Child>,
|
||||
public Interrupt_handler
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_receiver *_sig_rec;
|
||||
|
||||
/**
|
||||
* Semaphore used for implementing blocking syscalls, i.e., select
|
||||
* Lock used for implementing blocking syscalls, i.e., select
|
||||
*
|
||||
* The reason to have it as a member variable instead of creating
|
||||
* it on demand is to not have to register and unregister an
|
||||
* interrupt handler at every IO channel on every blocking syscall,
|
||||
* but only once when the IO channel gets added.
|
||||
*/
|
||||
Semaphore _blocker;
|
||||
Lock _blocker;
|
||||
|
||||
Allocator *_alloc;
|
||||
Destruct_queue &_destruct_queue;
|
||||
@ -196,6 +203,10 @@ namespace Noux {
|
||||
Attached_ram_dataspace _sysio_ds;
|
||||
Sysio * const _sysio;
|
||||
|
||||
typedef Ring_buffer<enum Sysio::Signal, Sysio::SIGNAL_QUEUE_SIZE>
|
||||
Signal_queue;
|
||||
Signal_queue _pending_signals;
|
||||
|
||||
Session_capability const _noux_session_cap;
|
||||
|
||||
Local_noux_service _local_noux_service;
|
||||
@ -242,11 +253,34 @@ namespace Noux {
|
||||
child->add_io_channel(io_channel_by_fd(fd), fd);
|
||||
}
|
||||
|
||||
void _block_for_io_channel(Shared_pointer<Io_channel> &io)
|
||||
/**
|
||||
* Block until the IO channel is ready for reading or writing or an
|
||||
* exception occured.
|
||||
*
|
||||
* \param io the IO channel
|
||||
* \param rd check for data available for reading
|
||||
* \param wr check for readiness for writing
|
||||
* \param ex check for exceptions
|
||||
*/
|
||||
void _block_for_io_channel(Shared_pointer<Io_channel> &io,
|
||||
bool rd, bool wr, bool ex)
|
||||
{
|
||||
/* reset the blocker lock to the 'locked' state */
|
||||
_blocker.unlock();
|
||||
_blocker.lock();
|
||||
|
||||
Wake_up_notifier notifier(&_blocker);
|
||||
io->register_wake_up_notifier(¬ifier);
|
||||
_blocker.down();
|
||||
|
||||
for (;;) {
|
||||
if (io->check_unblock(rd, wr, ex) ||
|
||||
!_pending_signals.empty())
|
||||
break;
|
||||
|
||||
/* block (unless the lock got unlocked in the meantime) */
|
||||
_blocker.lock();
|
||||
}
|
||||
|
||||
io->unregister_wake_up_notifier(¬ifier);
|
||||
}
|
||||
|
||||
@ -395,6 +429,78 @@ namespace Noux {
|
||||
return fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/****************************************
|
||||
** File_descriptor_registry overrides **
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* Find out if the IO channel associated with 'fd' has more file
|
||||
* descriptors associated with it
|
||||
*/
|
||||
bool _is_the_only_fd_for_io_channel(int fd,
|
||||
Shared_pointer<Io_channel> io_channel)
|
||||
{
|
||||
for (int f = 0; f < MAX_FILE_DESCRIPTORS; f++) {
|
||||
if ((f != fd) &&
|
||||
fd_in_use(f) &&
|
||||
(io_channel_by_fd(f) == io_channel))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int add_io_channel(Shared_pointer<Io_channel> io_channel, int fd = -1)
|
||||
{
|
||||
fd = File_descriptor_registry::add_io_channel(io_channel, fd);
|
||||
|
||||
/* Register the interrupt handler only once per IO channel */
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel))
|
||||
io_channel->register_interrupt_handler(this);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void remove_io_channel(int fd)
|
||||
{
|
||||
Shared_pointer<Io_channel> io_channel = _lookup_channel(fd);
|
||||
|
||||
/*
|
||||
* Unregister the interrupt handler only if there are no other
|
||||
* file descriptors associated with the IO channel.
|
||||
*/
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel))
|
||||
io_channel->unregister_interrupt_handler(this);
|
||||
|
||||
File_descriptor_registry::remove_io_channel(fd);
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++)
|
||||
try {
|
||||
remove_io_channel(fd);
|
||||
} catch (Invalid_fd) { }
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
** Interrupt_handler interface **
|
||||
*********************************/
|
||||
|
||||
void handle_interrupt()
|
||||
{
|
||||
try {
|
||||
_pending_signals.add(Sysio::SIG_INT);
|
||||
} catch (Signal_queue::Overflow) {
|
||||
PERR("signal queue is full - signal dropped");
|
||||
}
|
||||
|
||||
_blocker.unlock();
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ namespace Noux {
|
||||
*
|
||||
* \return noux file descriptor used for the I/O channel
|
||||
*/
|
||||
int add_io_channel(Shared_pointer<Io_channel> io_channel, int fd = -1)
|
||||
virtual int add_io_channel(Shared_pointer<Io_channel> io_channel, int fd = -1)
|
||||
{
|
||||
if ((fd == -1) && !_find_available_fd(&fd)) {
|
||||
PERR("Could not allocate file descriptor");
|
||||
@ -88,7 +88,7 @@ namespace Noux {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void remove_io_channel(int fd)
|
||||
virtual void remove_io_channel(int fd)
|
||||
{
|
||||
if (!_is_valid_fd(fd))
|
||||
PERR("File descriptor %d is out of range", fd);
|
||||
@ -103,14 +103,13 @@ namespace Noux {
|
||||
|
||||
Shared_pointer<Io_channel> io_channel_by_fd(int fd) const
|
||||
{
|
||||
if (!fd_in_use(fd)) {
|
||||
PWRN("File descriptor %d is not open", fd);
|
||||
if (!fd_in_use(fd))
|
||||
return Shared_pointer<Io_channel>();
|
||||
}
|
||||
|
||||
return _fds[fd].io_channel;
|
||||
}
|
||||
|
||||
void flush()
|
||||
virtual void flush()
|
||||
{
|
||||
/* close all file descriptors */
|
||||
for (unsigned i = 0; i < MAX_FILE_DESCRIPTORS; i++)
|
||||
|
@ -33,6 +33,21 @@ namespace Noux {
|
||||
* a device and is therefore false by default.
|
||||
*/
|
||||
virtual bool ioctl(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
|
||||
|
||||
/**
|
||||
* Return true if an unblocking condition of the file is satisfied
|
||||
*
|
||||
* \param rd if true, check for data available for reading
|
||||
* \param wr if true, check for readiness for writing
|
||||
* \param ex if true, check for exceptions
|
||||
*/
|
||||
virtual bool check_unblock(Vfs_handle *vfs_handle,
|
||||
bool rd, bool wr, bool ex)
|
||||
{ return true; }
|
||||
|
||||
virtual void register_read_ready_sigh(Vfs_handle *vfs_handle,
|
||||
Signal_context_capability sigh)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
|
29
ports/src/noux/interrupt_handler.h
Normal file
29
ports/src/noux/interrupt_handler.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* \brief Interrupt handler interface
|
||||
* \author Christian Prochaska
|
||||
* \date 2013-10-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NOUX__INTERRUPT_HANDLER__H_
|
||||
#define _NOUX__INTERRUPT_HANDLER__H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Interrupt_handler : List<Interrupt_handler>::Element
|
||||
{
|
||||
virtual void handle_interrupt() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _NOUX__INTERRUPT_HANDLER__H_ */
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <noux_session/sysio.h>
|
||||
#include <shared_pointer.h>
|
||||
#include <wake_up_notifier.h>
|
||||
#include <interrupt_handler.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
@ -52,8 +53,10 @@ namespace Noux {
|
||||
* List of notifiers (i.e., processes) used by threads that block
|
||||
* for an I/O-channel event
|
||||
*/
|
||||
List<Wake_up_notifier> _notifiers;
|
||||
Lock _notifiers_lock;
|
||||
List<Wake_up_notifier> _notifiers;
|
||||
Lock _notifiers_lock;
|
||||
List<Interrupt_handler> _interrupt_handlers;
|
||||
Lock _interrupt_handlers_lock;
|
||||
|
||||
public:
|
||||
|
||||
@ -130,6 +133,41 @@ namespace Noux {
|
||||
for (Wake_up_notifier *n = _notifiers.first(); n; n = n->next())
|
||||
n->wake_up();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register interrupt handler
|
||||
*
|
||||
* This function is called by Child objects to get woken up if the
|
||||
* terminal sends, for example, Ctrl-C.
|
||||
*/
|
||||
void register_interrupt_handler(Interrupt_handler *handler)
|
||||
{
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
_interrupt_handlers.insert(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister interrupt handler
|
||||
*/
|
||||
void unregister_interrupt_handler(Interrupt_handler *handler)
|
||||
{
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
_interrupt_handlers.remove(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell all registered handlers about an interrupt event
|
||||
*/
|
||||
void invoke_all_interrupt_handlers()
|
||||
{
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
for (Interrupt_handler *h = _interrupt_handlers.first();
|
||||
h; h = h->next())
|
||||
h->handle_interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/lock.h>
|
||||
#include <base/semaphore.h>
|
||||
#include <util/list.h>
|
||||
|
||||
|
||||
@ -26,19 +25,19 @@ namespace Noux {
|
||||
{
|
||||
private:
|
||||
|
||||
Semaphore *_sem;
|
||||
Lock *_lock;
|
||||
|
||||
public:
|
||||
|
||||
Io_receptor(Semaphore *semaphore)
|
||||
Io_receptor(Lock *lock)
|
||||
:
|
||||
_sem(semaphore)
|
||||
_lock(lock)
|
||||
{ }
|
||||
|
||||
void check_and_wakeup()
|
||||
{
|
||||
if (_sem)
|
||||
_sem->up();
|
||||
if (_lock)
|
||||
_lock->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -89,11 +89,11 @@ namespace Noux {
|
||||
{
|
||||
private:
|
||||
Timeout_state *_state;
|
||||
Semaphore *_blocker;
|
||||
Lock *_blocker;
|
||||
Timeout_scheduler *_scheduler;
|
||||
|
||||
public:
|
||||
Timeout_alarm(Timeout_state *st, Semaphore *blocker, Timeout_scheduler *scheduler, Time timeout)
|
||||
Timeout_alarm(Timeout_state *st, Lock *blocker, Timeout_scheduler *scheduler, Time timeout)
|
||||
:
|
||||
_state(st),
|
||||
_blocker(blocker),
|
||||
@ -109,7 +109,7 @@ namespace Noux {
|
||||
bool on_alarm()
|
||||
{
|
||||
_state->timed_out = true;
|
||||
_blocker->up();
|
||||
_blocker->unlock();
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -127,6 +127,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Genode::printf("PID %d -> SYSCALL %s\n",
|
||||
pid(), Noux::Session::syscall_name(sc));
|
||||
|
||||
bool result = false;
|
||||
|
||||
try {
|
||||
switch (sc) {
|
||||
|
||||
@ -139,17 +141,26 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->write_in.fd);
|
||||
|
||||
if (!io->is_nonblocking())
|
||||
if (!io->check_unblock(false, true, false))
|
||||
_block_for_io_channel(io);
|
||||
_block_for_io_channel(io, false, true, false);
|
||||
|
||||
/*
|
||||
* 'io->write' is expected to update 'write_out.count'
|
||||
*/
|
||||
if (io->write(_sysio, count) == false)
|
||||
return false;
|
||||
if (io->check_unblock(false, true, false)) {
|
||||
/*
|
||||
* 'io->write' is expected to update
|
||||
* '_sysio->write_out.count' and 'count'
|
||||
*/
|
||||
result = io->write(_sysio, count);
|
||||
if (result == false)
|
||||
break;
|
||||
} else {
|
||||
if (result == false) {
|
||||
/* nothing was written yet */
|
||||
_sysio->error.write = Sysio::WRITE_ERR_INTERRUPT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_READ:
|
||||
@ -157,20 +168,28 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->read_in.fd);
|
||||
|
||||
if (!io->is_nonblocking())
|
||||
while (!io->check_unblock(true, false, false))
|
||||
_block_for_io_channel(io);
|
||||
_block_for_io_channel(io, true, false, false);
|
||||
|
||||
return io->read(_sysio);
|
||||
if (io->check_unblock(true, false, false))
|
||||
result = io->read(_sysio);
|
||||
else
|
||||
_sysio->error.read = Sysio::READ_ERR_INTERRUPT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_FTRUNCATE:
|
||||
{
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->ftruncate_in.fd);
|
||||
|
||||
while (!io->check_unblock(true, false, false))
|
||||
_block_for_io_channel(io);
|
||||
_block_for_io_channel(io, false, true, false);
|
||||
|
||||
return io->ftruncate(_sysio);
|
||||
if (io->check_unblock(false, true, false))
|
||||
result = io->ftruncate(_sysio);
|
||||
else
|
||||
_sysio->error.ftruncate = Sysio::FTRUNCATE_ERR_INTERRUPT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_STAT:
|
||||
@ -225,7 +244,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
Shared_pointer<Io_channel>
|
||||
channel(new Vfs_io_channel(_sysio->open_in.path,
|
||||
leaf_path, root_dir(), vfs_handle),
|
||||
leaf_path, root_dir(),
|
||||
vfs_handle, *_sig_rec),
|
||||
Genode::env()->heap());
|
||||
|
||||
_sysio->open_out.fd = add_io_channel(channel);
|
||||
@ -302,6 +322,17 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
_assign_io_channels_to(child);
|
||||
|
||||
/*
|
||||
* Close all open files.
|
||||
*
|
||||
* This action is not part of the child destructor,
|
||||
* because in the case that a child exits itself,
|
||||
* it may need to close all files to unblock the
|
||||
* parent (which might be reading from a pipe) before
|
||||
* the parent can destroy the child object.
|
||||
*/
|
||||
flush();
|
||||
|
||||
/* signal main thread to remove ourself */
|
||||
Genode::Signal_transmitter(_destruct_context_cap).submit();
|
||||
|
||||
@ -329,6 +360,46 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
long timeout_usec = _sysio->select_in.timeout.usec;
|
||||
bool timeout_reached = false;
|
||||
|
||||
/* reset the blocker lock to the 'locked' state */
|
||||
_blocker.unlock();
|
||||
_blocker.lock();
|
||||
|
||||
/*
|
||||
* Register ourself at all watched I/O channels
|
||||
*
|
||||
* We instantiate as many notifiers as we have file
|
||||
* descriptors to observe. Each notifier is associated
|
||||
* with the child's blocking semaphore. When any of the
|
||||
* notifiers get woken up, the semaphore gets unblocked.
|
||||
*
|
||||
* XXX However, the blocker may get unblocked for other
|
||||
* conditions such as the destruction of the child.
|
||||
* ...to be done.
|
||||
*/
|
||||
|
||||
Wake_up_notifier notifiers[in_fds_total];
|
||||
|
||||
for (Genode::size_t i = 0; i < in_fds_total; i++) {
|
||||
int fd = in_fds.array[i];
|
||||
if (!fd_in_use(fd)) continue;
|
||||
|
||||
Shared_pointer<Io_channel> io = io_channel_by_fd(fd);
|
||||
notifiers[i].lock = &_blocker;
|
||||
|
||||
io->register_wake_up_notifier(¬ifiers[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register ourself at the Io_receptor_registry
|
||||
*
|
||||
* Each entry in the registry will be unblocked if an external
|
||||
* event has happend, e.g. network I/O.
|
||||
*/
|
||||
|
||||
Io_receptor receptor(&_blocker);
|
||||
io_receptor_registry()->register_receptor(&receptor);
|
||||
|
||||
|
||||
/*
|
||||
* Block for one action of the watched file descriptors
|
||||
*/
|
||||
@ -383,13 +454,14 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
/* exception fds are currently not considered */
|
||||
_sysio->select_out.fds.num_ex = unblock_ex;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return if I/O channel triggered, but timeout exceeded
|
||||
* Return if timeout is zero or timeout exceeded
|
||||
*/
|
||||
|
||||
|
||||
if (_sysio->select_in.timeout.zero() || timeout_reached) {
|
||||
/*
|
||||
if (timeout_reached) PINF("timeout_reached");
|
||||
@ -399,43 +471,19 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->select_out.fds.num_wr = 0;
|
||||
_sysio->select_out.fds.num_ex = 0;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register ourself at all watched I/O channels
|
||||
*
|
||||
* We instantiate as many notifiers as we have file
|
||||
* descriptors to observe. Each notifier is associated
|
||||
* with the child's blocking semaphore. When any of the
|
||||
* notifiers get woken up, the semaphore gets unblocked.
|
||||
*
|
||||
* XXX However, the semaphore may get unblocked for other
|
||||
* conditions such as the destruction of the child.
|
||||
* ...to be done.
|
||||
* Return if signals are pending
|
||||
*/
|
||||
|
||||
Wake_up_notifier notifiers[in_fds_total];
|
||||
|
||||
for (Genode::size_t i = 0; i < in_fds_total; i++) {
|
||||
int fd = in_fds.array[i];
|
||||
if (!fd_in_use(fd)) continue;
|
||||
|
||||
Shared_pointer<Io_channel> io = io_channel_by_fd(fd);
|
||||
notifiers[i].semaphore = &_blocker;
|
||||
io->register_wake_up_notifier(¬ifiers[i]);
|
||||
if (!_pending_signals.empty()) {
|
||||
_sysio->error.select = Sysio::SELECT_ERR_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register ourself at the Io_receptor_registry
|
||||
*
|
||||
* Each entry in the registry will be unblocked if an external
|
||||
* event has happend, e.g. network I/O.
|
||||
*/
|
||||
|
||||
Io_receptor receptor(&_blocker);
|
||||
io_receptor_registry()->register_receptor(&receptor);
|
||||
|
||||
/*
|
||||
* Block at barrier except when reaching the timeout
|
||||
*/
|
||||
@ -446,7 +494,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Timeout_alarm ta(&ts, &_blocker, Noux::timeout_scheduler(), to_msec);
|
||||
|
||||
/* block until timeout is reached or we were unblocked */
|
||||
_blocker.down();
|
||||
_blocker.lock();
|
||||
|
||||
if (ts.timed_out) {
|
||||
timeout_reached = 1;
|
||||
@ -461,28 +509,28 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
}
|
||||
else {
|
||||
/* let's block infinitely */
|
||||
_blocker.down();
|
||||
_blocker.lock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister barrier at watched I/O channels
|
||||
*/
|
||||
for (Genode::size_t i = 0; i < in_fds_total; i++) {
|
||||
int fd = in_fds.array[i];
|
||||
if (!fd_in_use(fd)) continue;
|
||||
|
||||
Shared_pointer<Io_channel> io = io_channel_by_fd(fd);
|
||||
io->unregister_wake_up_notifier(¬ifiers[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister receptor
|
||||
*/
|
||||
io_receptor_registry()->unregister_receptor(&receptor);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
/*
|
||||
* Unregister barrier at watched I/O channels
|
||||
*/
|
||||
for (Genode::size_t i = 0; i < in_fds_total; i++) {
|
||||
int fd = in_fds.array[i];
|
||||
if (!fd_in_use(fd)) continue;
|
||||
|
||||
Shared_pointer<Io_channel> io = io_channel_by_fd(fd);
|
||||
io->unregister_wake_up_notifier(¬ifiers[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister receptor
|
||||
*/
|
||||
io_receptor_registry()->unregister_receptor(&receptor);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_FORK:
|
||||
@ -722,7 +770,12 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
catch (...) { PERR("Unexpected exception"); }
|
||||
|
||||
return false;
|
||||
/* handle signals which might have occured */
|
||||
while (!_pending_signals.empty() &&
|
||||
(_sysio->pending_signals.avail_capacity() > 0))
|
||||
_sysio->pending_signals.add(_pending_signals.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,6 +145,11 @@ namespace Noux {
|
||||
|
||||
operator bool () const { return _ptr != 0; }
|
||||
|
||||
bool operator== (const Shared_pointer &other)
|
||||
{
|
||||
return (_ptr == other._ptr);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Shared_pointer<To> dynamic_pointer_cast()
|
||||
{
|
||||
|
@ -32,8 +32,6 @@ namespace Noux {
|
||||
private:
|
||||
|
||||
Terminal::Session_client _terminal;
|
||||
Signal_context _read_avail_sig_ctx;
|
||||
Signal_receiver _read_avail_sig_rec;
|
||||
|
||||
enum { FILENAME_MAX_LEN = 64 };
|
||||
char _filename[FILENAME_MAX_LEN];
|
||||
@ -74,11 +72,6 @@ namespace Noux {
|
||||
/* wati for signal */
|
||||
sig_rec.wait_for_signal();
|
||||
sig_rec.dissolve(&sig_ctx);
|
||||
|
||||
/*
|
||||
* Register "read available" signal handler
|
||||
*/
|
||||
_terminal.read_avail_sigh(_read_avail_sig_rec.manage(&_read_avail_sig_ctx));
|
||||
}
|
||||
|
||||
|
||||
@ -212,12 +205,28 @@ namespace Noux {
|
||||
|
||||
bool read(Sysio *sysio, Vfs_handle *vfs_handle)
|
||||
{
|
||||
_read_avail_sig_rec.wait_for_signal();
|
||||
sysio->read_out.count = _terminal.read(sysio->read_out.chunk, sysio->read_in.count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
|
||||
|
||||
bool check_unblock(Vfs_handle *vfs_handle, bool rd, bool wr, bool ex)
|
||||
{
|
||||
if (rd && (_terminal.avail() > 0))
|
||||
return true;
|
||||
|
||||
if (wr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void register_read_ready_sigh(Vfs_handle *vfs_handle,
|
||||
Signal_context_capability sigh)
|
||||
{
|
||||
_terminal.read_avail_sigh(sigh);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
#include <base/printf.h>
|
||||
#include <os/ring_buffer.h>
|
||||
#include <terminal_session/connection.h>
|
||||
|
||||
/* Noux includes */
|
||||
@ -33,6 +34,8 @@ namespace Noux {
|
||||
|
||||
enum Type { STDIN, STDOUT, STDERR } type;
|
||||
|
||||
Ring_buffer<char, Sysio::CHUNK_SIZE + 1> read_buffer;
|
||||
|
||||
Terminal_io_channel(Terminal::Session &terminal, Type type,
|
||||
Signal_receiver &sig_rec)
|
||||
: terminal(terminal), sig_rec(sig_rec), eof(false), type(type)
|
||||
@ -80,29 +83,32 @@ namespace Noux {
|
||||
min(sysio->read_in.count,
|
||||
sizeof(sysio->read_out.chunk));
|
||||
|
||||
sysio->read_out.count =
|
||||
terminal.read(sysio->read_out.chunk, max_count);
|
||||
for (sysio->read_out.count = 0;
|
||||
(sysio->read_out.count < max_count) && !read_buffer.empty();
|
||||
sysio->read_out.count++) {
|
||||
|
||||
/* scan received characters for EOF */
|
||||
for (unsigned i = 0; i < sysio->read_out.count; i++) {
|
||||
char c = read_buffer.get();
|
||||
|
||||
enum { EOF = 4 };
|
||||
if (sysio->read_out.chunk[i] != EOF)
|
||||
continue;
|
||||
|
||||
/* discard EOF character and everything that follows... */
|
||||
sysio->read_out.count = i;
|
||||
if (c == EOF) {
|
||||
|
||||
/*
|
||||
* If EOF was the only character of the batch, the count has
|
||||
* reached zero. In this case the read result indicates the EOF
|
||||
* condition as is. However, if count is greater than zero, we
|
||||
* deliver the previous characters of the batch and return the
|
||||
* zero result from the subsequent 'read' call. This condition
|
||||
* is tracked by the 'eof' variable.
|
||||
*/
|
||||
if (sysio->read_out.count > 0)
|
||||
eof = true;
|
||||
/*
|
||||
* If EOF was the only character of the batch, the count
|
||||
* has reached zero. In this case the read result indicates
|
||||
* the EOF condition as is. However, if count is greater
|
||||
* than zero, we deliver the previous characters of the
|
||||
* batch and return the zero result from the subsequent
|
||||
* 'read' call. This condition is tracked by the 'eof'
|
||||
* variable.
|
||||
*/
|
||||
if (sysio->read_out.count > 0)
|
||||
eof = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sysio->read_out.chunk[sysio->read_out.count] = c;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -150,7 +156,7 @@ namespace Noux {
|
||||
* Unblock I/O channel if the terminal has new user input. Channels
|
||||
* otther than STDIN will never unblock.
|
||||
*/
|
||||
return (rd && (type == STDIN) && terminal.avail());
|
||||
return (rd && (type == STDIN) && !read_buffer.empty());
|
||||
}
|
||||
|
||||
bool ioctl(Sysio *sysio)
|
||||
@ -194,6 +200,21 @@ namespace Noux {
|
||||
*/
|
||||
void dispatch(unsigned)
|
||||
{
|
||||
while ((read_buffer.avail_capacity() > 0) &&
|
||||
terminal.avail()) {
|
||||
|
||||
char c;
|
||||
terminal.read(&c, 1);
|
||||
|
||||
enum { INTERRUPT = 3 };
|
||||
|
||||
if (c == INTERRUPT) {
|
||||
Io_channel::invoke_all_interrupt_handlers();
|
||||
} else {
|
||||
read_buffer.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
Io_channel::invoke_all_notifiers();
|
||||
}
|
||||
};
|
||||
|
@ -21,18 +21,29 @@
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Vfs_io_channel : public Io_channel
|
||||
struct Vfs_io_channel : Io_channel, Signal_dispatcher_base
|
||||
{
|
||||
Vfs_handle *_fh;
|
||||
|
||||
Absolute_path _path;
|
||||
Absolute_path _leaf_path;
|
||||
|
||||
Vfs_io_channel(char const *path, char const *leaf_path,
|
||||
Dir_file_system *root_dir, Vfs_handle *vfs_handle)
|
||||
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path) { }
|
||||
Signal_receiver &_sig_rec;
|
||||
|
||||
~Vfs_io_channel() { destroy(env()->heap(), _fh); }
|
||||
Vfs_io_channel(char const *path, char const *leaf_path,
|
||||
Dir_file_system *root_dir, Vfs_handle *vfs_handle,
|
||||
Signal_receiver &sig_rec)
|
||||
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path),
|
||||
_sig_rec(sig_rec)
|
||||
{
|
||||
_fh->fs()->register_read_ready_sigh(_fh, _sig_rec.manage(this));
|
||||
}
|
||||
|
||||
~Vfs_io_channel()
|
||||
{
|
||||
_sig_rec.dissolve(this);
|
||||
destroy(env()->heap(), _fh);
|
||||
}
|
||||
|
||||
bool write(Sysio *sysio, size_t &count)
|
||||
{
|
||||
@ -158,12 +169,21 @@ namespace Noux {
|
||||
|
||||
bool check_unblock(bool rd, bool wr, bool ex) const
|
||||
{
|
||||
/*
|
||||
* XXX For now, we use the TAR fs only, which never blocks.
|
||||
* However, real file systems may block.
|
||||
*/
|
||||
return true;
|
||||
return _fh->fs()->check_unblock(_fh, rd, wr, ex);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
** Signal_dispatcher_base interface **
|
||||
**************************************/
|
||||
|
||||
/**
|
||||
* Called by Noux main loop on the occurrence of new input
|
||||
*/
|
||||
void dispatch(unsigned)
|
||||
{
|
||||
Io_channel::invoke_all_notifiers();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,21 +16,21 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
#include <base/semaphore.h>
|
||||
#include <base/lock.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Wake_up_notifier : List<Wake_up_notifier>::Element
|
||||
{
|
||||
Semaphore *semaphore;
|
||||
Lock *lock;
|
||||
|
||||
Wake_up_notifier(Semaphore *semaphore = 0)
|
||||
: semaphore(semaphore) { }
|
||||
Wake_up_notifier(Lock *lock = 0)
|
||||
: lock(lock) { }
|
||||
|
||||
void wake_up()
|
||||
{
|
||||
if (semaphore)
|
||||
semaphore->up();
|
||||
if (lock)
|
||||
lock->unlock();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
56
ports/src/test/noux_signals/main.cc
Normal file
56
ports/src/test/noux_signals/main.cc
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief Noux SIGINT handler test
|
||||
* \author Christian Prochaska
|
||||
* \date 2013-10-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
void signal_handler(int signal)
|
||||
{
|
||||
printf("%d: signal handler for signal %d called\n",
|
||||
getpid(), signal);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char c;
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
memset (&sa, '\0', sizeof(sa));
|
||||
|
||||
sa.sa_handler = signal_handler;
|
||||
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
|
||||
int pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
printf("test ready\n");
|
||||
|
||||
if ((read(0, &c, 1) == -1) && (errno = EINTR))
|
||||
printf("%d: 'read()' returned with error EINTR\n", getpid());
|
||||
else
|
||||
printf("%d: 'read()' returned character 0x = %x\n", getpid(), c);
|
||||
|
||||
if (pid > 0) {
|
||||
waitpid(pid, 0, 0);
|
||||
printf("test finished\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
3
ports/src/test/noux_signals/target.mk
Normal file
3
ports/src/test/noux_signals/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-noux_signals
|
||||
SRC_CC = main.cc
|
||||
LIBS = libc libc_noux
|
Loading…
Reference in New Issue
Block a user