libc: remove mutex parameter from monitor

Issue #3874
This commit is contained in:
Christian Helmuth 2020-09-09 08:16:17 +02:00 committed by Norman Feske
parent a0a112ffe7
commit 75ba52a52b
8 changed files with 45 additions and 106 deletions

View File

@ -368,10 +368,7 @@ struct Libc::Local_clone_service : Noncopyable
void destroy(Session &) override
{
Mutex mutex { };
mutex.acquire();
monitor().monitor(mutex, [&] {
monitor().monitor([&] {
_child_ready.child_ready();
return Fn::COMPLETE;
});
@ -610,15 +607,12 @@ extern "C" pid_t __sys_fork(void)
_user_stack_base_ptr = (void *)mystack.base;
_user_stack_size = mystack.top - mystack.base;
Mutex mutex { };
mutex.acquire();
enum class Stage { FORK, WAIT_FORK_READY };
Stage stage { Stage::FORK };
Forked_child *child { nullptr };
monitor().monitor(mutex, [&] {
monitor().monitor([&] {
switch (stage) {
case Stage::FORK:
child = fork_kernel_routine();
@ -704,10 +698,7 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage
Wait4_functor functor { pid, *_forked_children_ptr };
Mutex mutex { };
mutex.acquire();
monitor().monitor(mutex, [&] {
monitor().monitor([&] {
functor.with_exited_child([&] (Registered<Forked_child> &child) {
result = child.pid();
exit_code = child.exit_code();

View File

@ -547,13 +547,13 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
/**
* Monitor interface
*/
Monitor::Result _monitor(Mutex &mutex, Function &fn, uint64_t timeout_ms) override
Monitor::Result _monitor(Function &fn, uint64_t timeout_ms) override
{
if (_main_context()) {
_main_monitor_job.construct(fn, timeout_ms);
_monitors.monitor(mutex, *_main_monitor_job);
_monitors.monitor(*_main_monitor_job);
Monitor::Result const job_result = _main_monitor_job->completed()
? Monitor::Result::COMPLETE
@ -565,7 +565,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
} else {
Pthread_job job { fn, _timer_accessor, timeout_ms };
_monitors.monitor(mutex, job);
_monitors.monitor(job);
return job.completed() ? Monitor::Result::COMPLETE
: Monitor::Result::TIMEOUT;
}

View File

@ -59,7 +59,7 @@ class Libc::Monitor : Interface
protected:
virtual Result _monitor(Mutex &, Function &, uint64_t) = 0;
virtual Result _monitor(Function &, uint64_t) = 0;
virtual void _trigger_monitor_examination() = 0;
public:
@ -67,14 +67,10 @@ class Libc::Monitor : Interface
/**
* Block until monitored execution completed or timeout expires
*
* The mutex must be locked when calling the monitor. It is released
* during wait for completion and re-acquired before the function
* returns. This behavior is comparable to condition variables.
*
* Returns true if execution completed, false on timeout.
*/
template <typename FN>
Result monitor(Mutex &mutex, FN const &fn, uint64_t timeout_ms = 0)
Result monitor(FN const &fn, uint64_t timeout_ms = 0)
{
struct _Function : Function
{
@ -83,7 +79,7 @@ class Libc::Monitor : Interface
_Function(FN const &fn) : fn(fn) { }
} function { fn };
return _monitor(mutex, function, timeout_ms);
return _monitor(function, timeout_ms);
}
/**
@ -129,17 +125,13 @@ struct Libc::Monitor::Pool
Pool(Monitor &monitor) : _monitor(monitor) { }
/* called by monitor-user context */
void monitor(Mutex &mutex, Job &job)
void monitor(Job &job)
{
Registry<Job>::Element element { _jobs, job };
mutex.release();
_monitor.trigger_monitor_examination();
job.wait_for_completion();
mutex.acquire();
}
enum class State { JOBS_PENDING, ALL_COMPLETE };

View File

@ -165,6 +165,13 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base
bool _exiting = false;
/*
* The mutex synchronizes the execution of cancel() and join() to
* protect the about-to-exit pthread to be destructed before it leaves
* trigger_monitor_examination(), which uses a 'Signal_transmitter'
* and, therefore, holds a reference to a signal context capability
* that needs to be released before the thread can be destroyed.
*/
Genode::Mutex _mutex { };
/* return value for 'pthread_join()' */

View File

@ -80,9 +80,9 @@ void Libc::Pthread::Thread_object::entry()
void Libc::Pthread::join(void **retval)
{
monitor().monitor([&] {
Genode::Mutex::Guard guard(_mutex);
monitor().monitor(_mutex, [&] {
if (!_exiting)
return Fn::INCOMPLETE;

View File

@ -304,11 +304,8 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
return Monitor::Function_result::INCOMPLETE;
};
Mutex mutex { };
Mutex::Guard guard(mutex);
Monitor::Result const monitor_result =
_monitor_ptr->monitor(mutex, monitor_fn, timeout_ms);
_monitor_ptr->monitor(monitor_fn, timeout_ms);
select_cb_list().remove(&(*select_cb));

View File

@ -37,12 +37,7 @@ static void millisleep(Genode::uint64_t timeout_ms)
if (!_monitor_ptr)
throw Missing_call_of_init_sleep();
static Mutex mutex;
Mutex::Guard guard(mutex);
_monitor_ptr->monitor(mutex,
[&] { return Libc::Monitor::Function_result::INCOMPLETE; },
_monitor_ptr->monitor([&] { return Libc::Monitor::Function_result::INCOMPLETE; },
timeout_ms);
}

View File

@ -74,12 +74,6 @@ static Genode::Region_map &region_map()
}
static Genode::Mutex &vfs_mutex()
{
static Genode::Mutex mutex;
return mutex;
}
namespace { using Fn = Libc::Monitor::Function_result; }
@ -248,10 +242,8 @@ void Libc::Vfs_plugin::_with_info(File_descriptor &fd, FN const &fn)
int Libc::Vfs_plugin::access(const char *path, int amode)
{
Mutex::Guard guard(vfs_mutex());
bool succeeded = false;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (_root_fs.leaf_path(path))
succeeded = true;
return Fn::COMPLETE;
@ -383,9 +375,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags)
File_descriptor *fd = nullptr;
int result_errno = 0;
{
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
/* handle open for directories */
if (_root_fs.directory(path)) {
@ -596,9 +586,8 @@ int Libc::Vfs_plugin::close(File_descriptor *fd)
Vfs::Vfs_handle *handle = vfs_handle(fd);
Sync sync { *handle , _update_mtime, _current_real_time };
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if ((fd->modified) || (fd->flags & O_CREAT))
if (!sync.complete())
return Fn::INCOMPLETE;
@ -620,10 +609,8 @@ int Libc::Vfs_plugin::dup2(File_descriptor *fd,
typedef Vfs::Directory_service::Open_result Result;
Mutex::Guard guard(vfs_mutex());
int result = -1;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (_root_fs.open(fd->fd_path, fd->flags, &handle, _alloc) != Result::OPEN_OK) {
warning("dup2 failed for path ", fd->fd_path);
@ -651,11 +638,9 @@ Libc::File_descriptor *Libc::Vfs_plugin::dup(File_descriptor *fd)
typedef Vfs::Directory_service::Open_result Result;
Mutex::Guard guard(vfs_mutex());
Libc::File_descriptor *result = nullptr;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (_root_fs.open(fd->fd_path, fd->flags, &handle, _alloc) != Result::OPEN_OK) {
warning("dup failed for path ", fd->fd_path);
@ -689,9 +674,8 @@ int Libc::Vfs_plugin::fstat(File_descriptor *fd, struct stat *buf)
if (fd->modified) {
Sync sync { *handle , _update_mtime, _current_real_time };
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (!sync.complete()) {
return Fn::INCOMPLETE;
}
@ -733,11 +717,9 @@ int Libc::Vfs_plugin::mkdir(const char *path, mode_t mode)
typedef Vfs::Directory_service::Opendir_result Opendir_result;
Mutex::Guard guard(vfs_mutex());
int result = -1;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (_root_fs.opendir(path, true, &dir_handle, _alloc)) {
case Opendir_result::OPENDIR_ERR_LOOKUP_FAILED: result_errno = ENOENT; break;
case Opendir_result::OPENDIR_ERR_NAME_TOO_LONG: result_errno = ENAMETOOLONG; break;
@ -793,11 +775,9 @@ int Libc::Vfs_plugin::stat(char const *path, struct stat *buf)
Vfs::Directory_service::Stat stat;
Mutex::Guard guard(vfs_mutex());
int result = -1;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (_root_fs.stat(path, stat)) {
case Result::STAT_ERR_NO_ENTRY: result_errno = ENOENT; break;
case Result::STAT_ERR_NO_PERM: result_errno = EACCES; break;
@ -831,10 +811,8 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
Vfs::file_size out_count = 0;
Result out_result = Result::WRITE_OK;
Mutex::Guard guard(vfs_mutex());
if (fd->flags & O_NONBLOCK) {
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
try {
out_result = handle->fs().write(handle, (char const *)buf, count, out_count);
} catch (Vfs::File_io_service::Insufficient_buffer) { }
@ -870,7 +848,7 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
return stat.type == Vfs::Node_type::CONTINUOUS_FILE;
};
monitor().monitor(vfs_mutex(), [&]
monitor().monitor([&]
{
for (;;) {
@ -961,12 +939,10 @@ ssize_t Libc::Vfs_plugin::read(File_descriptor *fd, void *buf,
if (fd->flags & O_DIRECTORY)
return Errno(EISDIR);
Mutex::Guard guard(vfs_mutex());
/* TODO refactor multiple monitor() calls to state machine in one call */
bool succeeded = false;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (fd->flags & O_NONBLOCK && !read_ready_from_kernel(fd)) {
result_errno = EAGAIN;
return Fn::COMPLETE;
@ -981,7 +957,7 @@ ssize_t Libc::Vfs_plugin::read(File_descriptor *fd, void *buf,
Vfs::file_size out_count = 0;
Result out_result;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
out_result = handle->fs().complete_read(handle, (char *)buf, count, out_count);
return out_result != Result::READ_QUEUED ? Fn::COMPLETE : Fn::INCOMPLETE;
});
@ -1022,16 +998,15 @@ ssize_t Libc::Vfs_plugin::getdirentries(File_descriptor *fd, char *buf,
Dirent dirent_out;
/* TODO refactor multiple monitor() calls to state machine in one call */
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
return handle->fs().queue_read(handle, sizeof(Dirent)) ? Fn::COMPLETE : Fn::INCOMPLETE;
});
Result out_result;
Vfs::file_size out_count;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
out_result = handle->fs().complete_read(handle, (char *)&dirent_out, sizeof(Dirent), out_count);
return out_result != Result::READ_QUEUED ? Fn::COMPLETE : Fn::INCOMPLETE;
});
@ -1095,9 +1070,7 @@ int Libc::Vfs_plugin::ioctl(File_descriptor *fd, int request, char *argp)
if (!argp)
return Errno(EINVAL);
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
_with_info(*fd, [&] (Xml_node info) {
if (info.type() == "terminal") {
::winsize *winsize = (::winsize *)argp;
@ -1231,11 +1204,9 @@ int Libc::Vfs_plugin::_legacy_ioctl(File_descriptor *fd, int request, char *argp
Vfs::Vfs_handle *handle = vfs_handle(fd);
Mutex::Guard guard(vfs_mutex());
bool succeeded = false;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (handle->fs().ioctl(handle, opcode, arg, out)) {
case Result::IOCTL_ERR_INVALID: result_errno = EINVAL; break;
case Result::IOCTL_ERR_NOTTY: result_errno = ENOTTY; break;
@ -1318,11 +1289,10 @@ int Libc::Vfs_plugin::ftruncate(File_descriptor *fd, ::off_t length)
{
Vfs::Vfs_handle *handle = vfs_handle(fd);
Sync sync { *handle, _update_mtime, _current_real_time };
Mutex::Guard guard(vfs_mutex());
bool succeeded = false;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (fd->modified) {
if (!sync.complete()) {
return Fn::INCOMPLETE;
@ -1396,9 +1366,7 @@ int Libc::Vfs_plugin::fsync(File_descriptor *fd)
Sync sync { *handle, _update_mtime, _current_real_time };
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (!sync.complete()) {
return Fn::INCOMPLETE;
}
@ -1411,8 +1379,6 @@ int Libc::Vfs_plugin::fsync(File_descriptor *fd)
int Libc::Vfs_plugin::symlink(const char *target_path, const char *link_path)
{
Mutex::Guard guard(vfs_mutex());
enum class Stage { OPEN, WRITE, SYNC };
Stage stage { Stage::OPEN };
@ -1424,7 +1390,7 @@ int Libc::Vfs_plugin::symlink(const char *target_path, const char *link_path)
bool succeeded { false };
int result_errno { 0 };
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (stage) {
case Stage::OPEN:
@ -1490,8 +1456,6 @@ int Libc::Vfs_plugin::symlink(const char *target_path, const char *link_path)
ssize_t Libc::Vfs_plugin::readlink(const char *link_path, char *buf, ::size_t buf_size)
{
Mutex::Guard guard(vfs_mutex());
enum class Stage { OPEN, QUEUE_READ, COMPLETE_READ };
Stage stage { Stage::OPEN };
@ -1500,7 +1464,7 @@ ssize_t Libc::Vfs_plugin::readlink(const char *link_path, char *buf, ::size_t bu
bool succeeded { false };
int result_errno { 0 };
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (stage) {
case Stage::OPEN:
@ -1576,11 +1540,9 @@ int Libc::Vfs_plugin::unlink(char const *path)
{
typedef Vfs::Directory_service::Unlink_result Result;
Mutex::Guard guard(vfs_mutex());
bool succeeded = false;
int result_errno = 0;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
switch (_root_fs.unlink(path)) {
case Result::UNLINK_ERR_NO_ENTRY: result_errno = ENOENT; break;
case Result::UNLINK_ERR_NO_PERM: result_errno = EPERM; break;
@ -1600,11 +1562,9 @@ int Libc::Vfs_plugin::rename(char const *from_path, char const *to_path)
{
typedef Vfs::Directory_service::Rename_result Result;
Mutex::Guard guard(vfs_mutex());
bool succeeded = false;
int result_errno = false;
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
if (_root_fs.leaf_path(to_path)) {
if (_root_fs.directory(to_path)) {
if (!_root_fs.directory(from_path)) {
@ -1691,8 +1651,7 @@ void *Libc::Vfs_plugin::mmap(void *addr_in, ::size_t length, int prot, int flags
Genode::Dataspace_capability ds_cap;
Mutex::Guard guard(vfs_mutex());
monitor().monitor(vfs_mutex(), [&] {
monitor().monitor([&] {
ds_cap = _root_fs.dataspace(fd->fd_path);
return Fn::COMPLETE;
});
@ -1822,8 +1781,6 @@ int Libc::Vfs_plugin::select(int nfds,
FD_ZERO(writefds);
FD_ZERO(exceptfds);
Mutex::Guard guard(vfs_mutex());
auto fn = [&] {
for (int fd = 0; fd < nfds; ++fd) {
@ -1861,7 +1818,7 @@ int Libc::Vfs_plugin::select(int nfds,
if (Libc::Kernel::kernel().main_context() && Libc::Kernel::kernel().main_suspended()) {
fn();
} else {
monitor().monitor(vfs_mutex(), fn);
monitor().monitor(fn);
}
return nready;