mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
parent
e9762ee25f
commit
7b0771659e
@ -195,7 +195,6 @@ __SYS_DUMMY(int, -1, truncate, (const char *, off_t))
|
||||
DUMMY(int, -1, sigblock, (int))
|
||||
DUMMY(int, -1, thr_kill2, (pid_t pid, long id, int sig));
|
||||
|
||||
__SYS_DUMMY_SILENT(int, -1, sigaction, (int, const struct sigaction *, struct sigaction *));
|
||||
__SYS_DUMMY(int, -1, sigsuspend, (const sigset_t *))
|
||||
__SYS_DUMMY(int, -1, sigtimedwait, (const sigset_t *, siginfo_t *, const struct timespec *));
|
||||
__SYS_DUMMY(int, -1, sigwaitinfo, (const sigset_t *, siginfo_t *));
|
||||
|
@ -35,6 +35,7 @@ namespace Libc {
|
||||
struct Clone_connection;
|
||||
struct Kernel_routine_scheduler;
|
||||
struct Watch;
|
||||
struct Signal;
|
||||
|
||||
/**
|
||||
* Support for shared libraries
|
||||
@ -129,6 +130,11 @@ namespace Libc {
|
||||
*/
|
||||
void init_execve(Genode::Env &, Genode::Allocator &, void *user_stack,
|
||||
Reset_malloc_heap &);
|
||||
|
||||
/**
|
||||
* Signal handling
|
||||
*/
|
||||
void init_signal(Signal &);
|
||||
}
|
||||
|
||||
#endif /* _LIBC__INTERNAL__INIT_H_ */
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <internal/current_time.h>
|
||||
#include <internal/kernel_timer_accessor.h>
|
||||
#include <internal/watch.h>
|
||||
#include <internal/signal.h>
|
||||
|
||||
namespace Libc { class Kernel; }
|
||||
|
||||
@ -117,6 +118,13 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
|
||||
Config_attr const _rtc_path = _libc_env.libc_config().attribute_value("rtc", Config_attr());
|
||||
|
||||
/* handler for watching the stdout's info pseudo file */
|
||||
Constructible<Watch_handler<Kernel>> _terminal_resize_handler { };
|
||||
|
||||
void _handle_terminal_resize();
|
||||
|
||||
Signal _signal;
|
||||
|
||||
Reconstructible<Io_signal_handler<Kernel>> _resume_main_handler {
|
||||
_env.ep(), *this, &Kernel::_resume_main };
|
||||
|
||||
@ -279,6 +287,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
_switch_to_kernel();
|
||||
} else {
|
||||
_valid_user_context = false;
|
||||
_signal.execute_signal_handlers();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -439,6 +448,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
} else {
|
||||
_valid_user_context = false;
|
||||
_dispatch_pending_io_signals = false;
|
||||
_signal.execute_signal_handlers();
|
||||
}
|
||||
}
|
||||
|
||||
|
108
repos/libports/src/lib/libc/internal/signal.h
Normal file
108
repos/libports/src/lib/libc/internal/signal.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* \brief POSIX signal handling
|
||||
* \author Norman Feske
|
||||
* \date 2019-10-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _LIBC__INTERNAL__SIGNAL_H_
|
||||
#define _LIBC__INTERNAL__SIGNAL_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/noncopyable.h>
|
||||
#include <base/registry.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <signal.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include <internal/types.h>
|
||||
|
||||
namespace Libc { struct Signal; }
|
||||
|
||||
|
||||
struct Libc::Signal : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct sigaction signal_action[NSIG + 1] { };
|
||||
|
||||
private:
|
||||
|
||||
struct Pending
|
||||
{
|
||||
virtual ~Pending() { }
|
||||
|
||||
unsigned const n;
|
||||
|
||||
Pending(unsigned n) : n(n) { }
|
||||
};
|
||||
|
||||
Constructible<Registered<Pending>> _charged_signals[NSIG + 1];
|
||||
|
||||
Registry<Registered<Pending>> _pending_signals { };
|
||||
|
||||
void _execute_signal_handler(unsigned n);
|
||||
|
||||
unsigned _count = 0;
|
||||
|
||||
bool _exit = false;
|
||||
|
||||
unsigned _exit_code = 0;
|
||||
|
||||
unsigned _nesting_level = 0;
|
||||
|
||||
public:
|
||||
|
||||
void charge(unsigned n)
|
||||
{
|
||||
if (n > NSIG)
|
||||
return;
|
||||
|
||||
_charged_signals[n].construct(_pending_signals, n);
|
||||
_count++;
|
||||
}
|
||||
|
||||
void execute_signal_handlers()
|
||||
{
|
||||
/*
|
||||
* Prevent nested execution of signal handlers, which may happen
|
||||
* if I/O operations are executed by a signal handler.
|
||||
*/
|
||||
if (_nesting_level > 0) {
|
||||
warning("attempt to nested execution of signal handlers");
|
||||
return;
|
||||
}
|
||||
|
||||
_nesting_level++;
|
||||
|
||||
_pending_signals.for_each([&] (Pending &pending) {
|
||||
_execute_signal_handler(pending.n);
|
||||
_charged_signals[pending.n].destruct();
|
||||
});
|
||||
|
||||
_nesting_level--;
|
||||
|
||||
/*
|
||||
* Exit application due to a signal such as SIGINT.
|
||||
*/
|
||||
if (_exit)
|
||||
exit(_exit_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of triggered signals
|
||||
*
|
||||
* The value is intended to be used for tracking whether a signal
|
||||
* occurred during a blocking operation ('select').
|
||||
*/
|
||||
unsigned count() const { return _count; }
|
||||
};
|
||||
|
||||
#endif /* _LIBC__INTERNAL__SIGNAL_H_ */
|
@ -44,9 +44,19 @@ class Libc::Vfs_plugin : public Plugin
|
||||
|
||||
/**
|
||||
* Return path to pseudo files used for ioctl operations of a given FD
|
||||
*
|
||||
* The 'fd' argument must feature a valid 'fd.fd_path' member.
|
||||
* This assumption can be violated by the stdout, stdin, or stderr FDs
|
||||
* if the <libc> configuration lacks the corresponding attribute.
|
||||
*/
|
||||
static Absolute_path ioctl_dir(File_descriptor const &fd)
|
||||
{
|
||||
if (!fd.fd_path) {
|
||||
error("Libc::Vfs_plugin::ioctl_dir: fd lacks path information");
|
||||
class Fd_lacks_path : Exception { };
|
||||
throw Fd_lacks_path();
|
||||
}
|
||||
|
||||
Absolute_path path(fd.fd_path);
|
||||
|
||||
/*
|
||||
|
@ -168,6 +168,30 @@ void Libc::Kernel::_init_file_descriptors()
|
||||
for (unsigned fd = 0; fd <= 2; fd++)
|
||||
file_descriptor_allocator()->preserve(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Watch stdout's 'info' pseudo file to detect terminal resize events
|
||||
*/
|
||||
File_descriptor const * const stdout_fd =
|
||||
file_descriptor_allocator()->find_by_libc_fd(STDOUT_FILENO);
|
||||
|
||||
if (stdout_fd && stdout_fd->fd_path) {
|
||||
Absolute_path dir = Vfs_plugin::ioctl_dir(*stdout_fd);
|
||||
dir.append_element("info");
|
||||
|
||||
_vfs.with_root_dir([&] (Directory &root_dir) {
|
||||
if (root_dir.file_exists(dir.string()))
|
||||
_terminal_resize_handler.construct(root_dir, dir.string(),
|
||||
*this, &Kernel::_handle_terminal_resize);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Libc::Kernel::_handle_terminal_resize()
|
||||
{
|
||||
_signal.charge(SIGWINCH);
|
||||
_resume_main();
|
||||
}
|
||||
|
||||
|
||||
@ -326,6 +350,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
|
||||
init_select(*this, *this, *this);
|
||||
init_socket_fs(*this);
|
||||
init_passwd(_passwd_config());
|
||||
init_signal(_signal);
|
||||
|
||||
_init_file_descriptors();
|
||||
|
||||
|
@ -21,15 +21,57 @@ extern "C" {
|
||||
#include <sys/wait.h>
|
||||
}
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include <internal/types.h>
|
||||
#include <internal/init.h>
|
||||
#include <internal/signal.h>
|
||||
|
||||
using namespace Libc;
|
||||
|
||||
|
||||
static Libc::Signal *_signal_ptr;
|
||||
|
||||
|
||||
void Libc::init_signal(Signal &signal)
|
||||
{
|
||||
_signal_ptr = &signal;
|
||||
}
|
||||
|
||||
|
||||
void Libc::Signal::_execute_signal_handler(unsigned n)
|
||||
{
|
||||
if (signal_action[n].sa_flags & SA_SIGINFO) {
|
||||
signal_action[n].sa_sigaction(n, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (signal_action[n].sa_handler == SIG_DFL) {
|
||||
switch (n) {
|
||||
case SIGCHLD:
|
||||
case SIGWINCH:
|
||||
/* ignore */
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Trigger the termination of the process.
|
||||
*
|
||||
* We cannot call 'exit' immediately as the exiting code (e.g.,
|
||||
* 'atexit' handlers) may potentially issue I/O operations such
|
||||
* as FD sync and close. Hence, we just flag the intention to
|
||||
* exit and issue the actual exit call at the end of
|
||||
* 'Signal::execute_signal_handlers'
|
||||
*/
|
||||
_exit = true;
|
||||
_exit_code = (n << 8) | EXIT_FAILURE;
|
||||
}
|
||||
} else if (signal_action[n].sa_handler == SIG_IGN) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
signal_action[n].sa_handler(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __attribute__((weak))
|
||||
int sigprocmask(int how, const sigset_t *set, sigset_t *old_set)
|
||||
{
|
||||
@ -68,6 +110,31 @@ extern "C" int __i386_libc_sigprocmask(int how, const sigset_t *set, sigset_t *o
|
||||
}
|
||||
|
||||
|
||||
extern "C" int sigaction(int, const struct sigaction *, struct sigaction *) __attribute__((weak));
|
||||
|
||||
|
||||
extern "C" int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
|
||||
{
|
||||
if ((signum < 1) || (signum > NSIG)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oldact)
|
||||
*oldact = _signal_ptr->signal_action[signum];
|
||||
|
||||
if (act)
|
||||
_signal_ptr->signal_action[signum] = *act;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int _sigaction(int, const struct sigaction *, struct sigaction *) __attribute__((weak, alias("sigaction")));
|
||||
extern "C" int __sys_sigaction(int, const struct sigaction *, struct sigaction *) __attribute__((weak, alias("sigaction")));
|
||||
extern "C" int __libc_sigaction(int, const struct sigaction *, struct sigaction *) __attribute__((weak, alias("sigaction")));
|
||||
|
||||
|
||||
extern "C" pid_t wait(int *istat) {
|
||||
return wait4(WAIT_ANY, istat, 0, NULL); }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user