libc: cancel select when POSIX signal occurs

With this patch, Vim running via the 'bash.run' script becomes able to
adopt itself to changed window dimensions.

Issue #3544
This commit is contained in:
Norman Feske 2019-10-29 10:52:49 +01:00 committed by Christian Helmuth
parent fafa409cf9
commit 636e0f6444
3 changed files with 33 additions and 8 deletions

View File

@ -65,7 +65,7 @@ namespace Libc {
/** /**
* Select support * Select support
*/ */
void init_select(Suspend &, Resume &, Select &); void init_select(Suspend &, Resume &, Select &, Signal &);
/** /**
* Support for querying available RAM quota in sysctl functions * Support for querying available RAM quota in sysctl functions

View File

@ -347,7 +347,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
init_sleep(*this); init_sleep(*this);
init_vfs_plugin(*this); init_vfs_plugin(*this);
init_time(*this, _rtc_path, *this); init_time(*this, _rtc_path, *this);
init_select(*this, *this, *this); init_select(*this, *this, *this, _signal);
init_socket_fs(*this); init_socket_fs(*this);
init_passwd(_passwd_config()); init_passwd(_passwd_config());
init_signal(_signal); init_signal(_signal);

View File

@ -36,9 +36,11 @@
/* libc-internal includes */ /* libc-internal includes */
#include <internal/init.h> #include <internal/init.h>
#include <internal/signal.h>
#include <internal/suspend.h> #include <internal/suspend.h>
#include <internal/resume.h> #include <internal/resume.h>
#include <internal/select.h> #include <internal/select.h>
#include <internal/errno.h>
namespace Libc { namespace Libc {
struct Select_cb; struct Select_cb;
@ -48,16 +50,19 @@ namespace Libc {
using namespace Libc; using namespace Libc;
static Suspend *_suspend_ptr; static Suspend *_suspend_ptr;
static Resume *_resume_ptr; static Resume *_resume_ptr;
static Select *_select_ptr; static Select *_select_ptr;
static Libc::Signal *_signal_ptr;
void Libc::init_select(Suspend &suspend, Resume &resume, Select &select) void Libc::init_select(Suspend &suspend, Resume &resume, Select &select,
Signal &signal)
{ {
_suspend_ptr = &suspend; _suspend_ptr = &suspend;
_resume_ptr = &resume; _resume_ptr = &resume;
_select_ptr = &select; _select_ptr = &select;
_signal_ptr = &signal;
} }
@ -312,18 +317,38 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
{ {
struct Missing_call_of_init_select : Exception { }; struct Missing_call_of_init_select : Exception { };
if (!_suspend_ptr) if (!_suspend_ptr || !_signal_ptr)
throw Missing_call_of_init_select(); throw Missing_call_of_init_select();
} }
while (!timeout.expired() && select_cb->nready == 0) unsigned const orig_signal_count = _signal_ptr->count();
auto signal_occurred_during_select = [&] ()
{
return _signal_ptr->count() != orig_signal_count;
};
for (;;) {
if (timeout.expired())
break;
if (select_cb->nready != 0)
break;
if (signal_occurred_during_select())
break;
timeout.duration = _suspend_ptr->suspend(check, timeout.duration); timeout.duration = _suspend_ptr->suspend(check, timeout.duration);
}
select_cb_list().remove(&(*select_cb)); select_cb_list().remove(&(*select_cb));
if (timeout.expired()) if (timeout.expired())
return 0; return 0;
if (signal_occurred_during_select())
return Errno(EINTR);
/* not timed out -> results have been stored in select_cb by select_notify() */ /* not timed out -> results have been stored in select_cb by select_notify() */
if (readfds) *readfds = select_cb->readfds; if (readfds) *readfds = select_cb->readfds;