2015-12-23 15:22:33 +01:00
|
|
|
/*
|
2016-12-13 17:09:35 +01:00
|
|
|
* \brief Libc kernel for main and pthreads user contexts
|
2015-12-23 15:22:33 +01:00
|
|
|
* \author Christian Helmuth
|
2016-12-13 17:09:35 +01:00
|
|
|
* \author Emery Hemingway
|
2015-12-23 15:22:33 +01:00
|
|
|
* \date 2016-01-22
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2016-12-13 17:09:35 +01:00
|
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
2015-12-23 15:22:33 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/component.h>
|
2016-12-13 17:09:35 +01:00
|
|
|
#include <base/log.h>
|
2015-12-23 15:22:33 +01:00
|
|
|
#include <base/thread.h>
|
|
|
|
#include <base/rpc_server.h>
|
|
|
|
#include <base/rpc_client.h>
|
2016-05-25 15:47:22 +02:00
|
|
|
#include <base/heap.h>
|
2017-01-03 14:33:55 +01:00
|
|
|
#include <base/attached_rom_dataspace.h>
|
2017-02-16 10:10:23 +01:00
|
|
|
#include <vfs/file_system_factory.h>
|
2017-01-03 14:33:55 +01:00
|
|
|
#include <vfs/dir_file_system.h>
|
2016-12-13 17:09:35 +01:00
|
|
|
#include <timer_session/connection.h>
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-22 15:01:19 +01:00
|
|
|
/* libc includes */
|
|
|
|
#include <libc/component.h>
|
2017-02-14 22:26:03 +01:00
|
|
|
#include <libc/select.h>
|
2017-02-07 10:34:49 +01:00
|
|
|
#include <libc-plugin/plugin_registry.h>
|
2016-12-22 15:01:19 +01:00
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/* libc-internal includes */
|
|
|
|
#include <internal/call_func.h>
|
|
|
|
#include <base/internal/unmanaged_singleton.h>
|
2016-05-25 15:47:22 +02:00
|
|
|
#include "vfs_plugin.h"
|
2016-10-30 15:17:24 +01:00
|
|
|
#include "libc_init.h"
|
2016-12-13 17:09:35 +01:00
|
|
|
#include "task.h"
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-03-09 22:22:55 +01:00
|
|
|
extern char **environ;
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-01-03 14:33:55 +01:00
|
|
|
namespace Libc {
|
|
|
|
class Env_implementation;
|
2016-12-13 17:09:35 +01:00
|
|
|
class Kernel;
|
|
|
|
class Pthreads;
|
|
|
|
class Timer;
|
|
|
|
class Timer_accessor;
|
|
|
|
class Timeout;
|
|
|
|
class Timeout_handler;
|
2017-01-31 16:38:23 +01:00
|
|
|
class Io_response_handler;
|
2016-12-13 17:09:35 +01:00
|
|
|
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
using Genode::Microseconds;
|
2017-01-03 14:33:55 +01:00
|
|
|
}
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
|
2017-01-03 14:33:55 +01:00
|
|
|
class Libc::Env_implementation : public Libc::Env
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::Env &_env;
|
|
|
|
|
|
|
|
Genode::Attached_rom_dataspace _config { _env, "config" };
|
|
|
|
|
|
|
|
Genode::Xml_node _vfs_config()
|
|
|
|
{
|
|
|
|
try { return _config.xml().sub_node("vfs"); }
|
|
|
|
catch (Genode::Xml_node::Nonexistent_sub_node) { }
|
|
|
|
try {
|
|
|
|
Genode::Xml_node node =
|
|
|
|
_config.xml().sub_node("libc").sub_node("vfs");
|
|
|
|
Genode::warning("'<config> <libc> <vfs/>' is deprecated, "
|
|
|
|
"please move to '<config> <vfs/>'");
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
catch (Genode::Xml_node::Nonexistent_sub_node) { }
|
|
|
|
|
|
|
|
return Genode::Xml_node("<vfs/>");
|
|
|
|
}
|
|
|
|
|
2017-02-22 14:42:20 +01:00
|
|
|
Genode::Xml_node _libc_config()
|
|
|
|
{
|
|
|
|
try { return _config.xml().sub_node("libc"); }
|
|
|
|
catch (Genode::Xml_node::Nonexistent_sub_node) { }
|
|
|
|
|
|
|
|
return Genode::Xml_node("<libc/>");
|
|
|
|
}
|
|
|
|
|
2017-02-16 10:10:23 +01:00
|
|
|
Vfs::Global_file_system_factory _file_system_factory;
|
|
|
|
Vfs::Dir_file_system _vfs;
|
2017-01-03 14:33:55 +01:00
|
|
|
|
|
|
|
Genode::Xml_node _config_xml() const override {
|
|
|
|
return _config.xml(); };
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-01-31 16:38:23 +01:00
|
|
|
Env_implementation(Genode::Env &env, Genode::Allocator &alloc,
|
|
|
|
Vfs::Io_response_handler &io_response_handler)
|
2017-01-03 14:33:55 +01:00
|
|
|
:
|
2017-02-16 10:10:23 +01:00
|
|
|
_env(env), _file_system_factory(alloc),
|
2017-01-31 16:38:23 +01:00
|
|
|
_vfs(_env, alloc, _vfs_config(), io_response_handler,
|
2017-11-20 10:21:38 +01:00
|
|
|
_file_system_factory, Vfs::Dir_file_system::Root())
|
2017-01-03 14:33:55 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
** Libc::Env interface **
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
Vfs::File_system &vfs() override {
|
|
|
|
return _vfs; }
|
|
|
|
|
2017-02-22 14:42:20 +01:00
|
|
|
Genode::Xml_node libc_config() override {
|
|
|
|
return _libc_config(); }
|
|
|
|
|
2017-01-03 14:33:55 +01:00
|
|
|
|
|
|
|
/***************************
|
|
|
|
** Genode::Env interface **
|
|
|
|
***************************/
|
|
|
|
|
|
|
|
Parent &parent() override {
|
|
|
|
return _env.parent(); }
|
|
|
|
|
|
|
|
Ram_session &ram() override {
|
|
|
|
return _env.ram(); }
|
|
|
|
|
|
|
|
Cpu_session &cpu() override {
|
|
|
|
return _env.cpu(); }
|
|
|
|
|
|
|
|
Region_map &rm() override {
|
|
|
|
return _env.rm(); }
|
|
|
|
|
|
|
|
Pd_session &pd() override {
|
|
|
|
return _env.pd(); }
|
|
|
|
|
|
|
|
Entrypoint &ep() override {
|
|
|
|
return _env.ep(); }
|
|
|
|
|
|
|
|
Ram_session_capability ram_session_cap() override {
|
|
|
|
return _env.ram_session_cap(); }
|
|
|
|
Cpu_session_capability cpu_session_cap() override {
|
|
|
|
return _env.cpu_session_cap(); }
|
|
|
|
|
|
|
|
Pd_session_capability pd_session_cap() override {
|
|
|
|
return _env.pd_session_cap(); }
|
|
|
|
|
|
|
|
Id_space<Parent::Client> &id_space() override {
|
|
|
|
return _env.id_space(); }
|
|
|
|
|
|
|
|
Session_capability session(Parent::Service_name const &name,
|
|
|
|
Parent::Client::Id id,
|
|
|
|
Parent::Session_args const &args,
|
|
|
|
Affinity const &aff) override {
|
|
|
|
return _env.session(name, id, args, aff); }
|
|
|
|
|
|
|
|
|
|
|
|
void upgrade(Parent::Client::Id id,
|
|
|
|
Parent::Upgrade_args const &args) override {
|
|
|
|
return _env.upgrade(id, args); }
|
|
|
|
|
|
|
|
void close(Parent::Client::Id id) override {
|
|
|
|
return _env.close(id); }
|
2017-03-15 15:40:55 +01:00
|
|
|
|
|
|
|
/* already done by the libc */
|
|
|
|
void exec_static_constructors() override { }
|
2017-05-14 14:59:30 +02:00
|
|
|
|
|
|
|
void reinit(Native_capability::Raw raw) override {
|
|
|
|
_env.reinit(raw); }
|
|
|
|
|
|
|
|
void reinit_main_thread(Capability<Region_map> &stack_area_rm) override {
|
|
|
|
_env.reinit_main_thread(stack_area_rm); }
|
2017-01-03 14:33:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
struct Libc::Timer
|
|
|
|
{
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
::Timer::Connection _timer;
|
2016-12-13 17:09:35 +01:00
|
|
|
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
Timer(Genode::Env &env) : _timer(env) { }
|
2016-12-13 17:09:35 +01:00
|
|
|
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
unsigned long curr_time()
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
return _timer.curr_time().trunc_to_plain_us().value/1000;
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static Microseconds microseconds(unsigned long timeout_ms)
|
|
|
|
{
|
|
|
|
return Microseconds(1000*timeout_ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long max_timeout()
|
|
|
|
{
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
return ~0UL/1000;
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Interface for obtaining the libc-global timer instance
|
2015-12-23 15:22:33 +01:00
|
|
|
*
|
2016-12-13 17:09:35 +01:00
|
|
|
* The 'Timer' is instantiated on demand whenever the 'Timer_accessor::timer'
|
|
|
|
* method is first called. This way, libc-using components do not depend of a
|
|
|
|
* timer connection unless they actually use time-related functionality.
|
|
|
|
*/
|
|
|
|
struct Libc::Timer_accessor
|
|
|
|
{
|
|
|
|
virtual Timer &timer() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Libc::Timeout_handler
|
|
|
|
{
|
|
|
|
virtual void handle_timeout() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO curr_time wrapping
|
|
|
|
*/
|
|
|
|
struct Libc::Timeout
|
|
|
|
{
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
Libc::Timer_accessor &_timer_accessor;
|
|
|
|
Timeout_handler &_handler;
|
|
|
|
::Timer::One_shot_timeout<Timeout> _timeout;
|
2016-12-13 17:09:35 +01:00
|
|
|
|
|
|
|
bool _expired = true;
|
|
|
|
unsigned long _absolute_timeout_ms = 0;
|
|
|
|
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
void _handle(Duration now)
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
|
|
|
_expired = true;
|
|
|
|
_absolute_timeout_ms = 0;
|
|
|
|
_handler.handle_timeout();
|
|
|
|
}
|
|
|
|
|
|
|
|
Timeout(Timer_accessor &timer_accessor, Timeout_handler &handler)
|
|
|
|
:
|
|
|
|
_timer_accessor(timer_accessor),
|
|
|
|
_handler(handler),
|
|
|
|
_timeout(_timer_accessor.timer()._timer, *this, &Timeout::_handle)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
void start(unsigned long timeout_ms)
|
|
|
|
{
|
|
|
|
unsigned long const now = _timer_accessor.timer().curr_time();
|
|
|
|
|
|
|
|
_expired = false;
|
|
|
|
_absolute_timeout_ms = now + timeout_ms;
|
|
|
|
|
os/timer: interpolate time via timestamps
Previously, the Genode::Timer::curr_time always used the
Timer_session::elapsed_ms RPC as back end. Now, Genode::Timer reads
this remote time only in a periodic fashion independently from the calls
to Genode::Timer::curr_time. If now one calls Genode::Timer::curr_time,
the function takes the last read remote time value and adapts it using
the timestamp difference since the remote-time read. The conversion
factor from timestamps to time is estimated on every remote-time read
using the last read remote-time value and the timestamp difference since
the last remote time read.
This commit also re-works the timeout test. The test now has two stages.
In the first stage, it tests fast polling of the
Genode::Timer::curr_time. This stage checks the error between locally
interpolated and timer-driver time as well as wether the locally
interpolated time is monotone and sufficiently homogeneous. In the
second stage several periodic and one-shot timeouts are scheduled at
once. This stage checks if the timeouts trigger sufficiently precise.
This commit adds the new Kernel::time syscall to base-hw. The syscall is
solely used by the Genode::Timer on base-hw as substitute for the
timestamp. This is because on ARM, the timestamp function uses the ARM
performance counter that stops counting when the WFI (wait for
interrupt) instruction is active. This instruction, however is used by
the base-hw idle contexts that get active when no user thread needs to
be scheduled. Thus, the ARM performance counter is not a good choice for
time interpolation and we use the kernel internal time instead.
With this commit, the timeout library becomes a basic library. That means
that it is linked against the LDSO which then provides it to the program it
serves. Furthermore, you can't use the timeout library anymore without the
LDSO because through the kernel-dependent LDSO make-files we can achieve a
kernel-dependent timeout implementation.
This commit introduces a structured Duration type that shall successively
replace the use of Microseconds, Milliseconds, and integer types for duration
values.
Open issues:
* The timeout test fails on Raspberry PI because of precision errors in the
first stage. However, this does not render the framework unusable in general
on the RPI but merely is an issue when speaking of microseconds precision.
* If we run on ARM with another Kernel than HW the timestamp speed may
continuously vary from almost 0 up to CPU speed. The Timer, however,
only uses interpolation if the timestamp speed remained stable (12.5%
tolerance) for at least 3 observation periods. Currently, one period is
100ms, so its 300ms. As long as this is not the case,
Timer_session::elapsed_ms is called instead.
Anyway, it might happen that the CPU load was stable for some time so
interpolation becomes active and now the timestamp speed drops. In the
worst case, we would now have 100ms of slowed down time. The bad thing
about it would be, that this also affects the timeout of the period.
Thus, it might "freeze" the local time for more than 100ms.
On the other hand, if the timestamp speed suddenly raises after some
stable time, interpolated time can get too fast. This would shorten the
period but nonetheless may result in drifting away into the far future.
Now we would have the problem that we can't deliver the real time
anymore until it has caught up because the output of Timer::curr_time
shall be monotone. So, effectively local time might "freeze" again for
more than 100ms.
It would be a solution to not use the Trace::timestamp on ARM w/o HW but
a function whose return value causes the Timer to never use
interpolation because of its stability policy.
Fixes #2400
2017-04-22 00:52:23 +02:00
|
|
|
_timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms));
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long duration_left() const
|
|
|
|
{
|
|
|
|
unsigned long const now = _timer_accessor.timer().curr_time();
|
|
|
|
|
2017-05-22 15:55:39 +02:00
|
|
|
if (_expired || _absolute_timeout_ms < now)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return _absolute_timeout_ms - now;
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Libc::Pthreads
|
|
|
|
{
|
|
|
|
struct Pthread : Timeout_handler
|
|
|
|
{
|
|
|
|
Genode::Lock lock { Genode::Lock::LOCKED };
|
|
|
|
Pthread *next { nullptr };
|
|
|
|
|
2017-08-20 17:23:22 +02:00
|
|
|
Timer_accessor &_timer_accessor;
|
|
|
|
Constructible<Timeout> _timeout;
|
|
|
|
|
|
|
|
void _construct_timeout_once()
|
|
|
|
{
|
|
|
|
if (!_timeout.constructed())
|
|
|
|
_timeout.construct(_timer_accessor, *this);
|
|
|
|
}
|
2016-12-13 17:09:35 +01:00
|
|
|
|
|
|
|
Pthread(Timer_accessor &timer_accessor, unsigned long timeout_ms)
|
2017-08-20 17:23:22 +02:00
|
|
|
: _timer_accessor(timer_accessor)
|
|
|
|
{
|
|
|
|
if (timeout_ms > 0) {
|
|
|
|
_construct_timeout_once();
|
|
|
|
_timeout->start(timeout_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long duration_left()
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
2017-08-20 17:23:22 +02:00
|
|
|
_construct_timeout_once();
|
|
|
|
return _timeout->duration_left();
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
void handle_timeout() override
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
|
|
|
lock.unlock();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Genode::Lock mutex;
|
|
|
|
Pthread *pthreads = nullptr;
|
|
|
|
Timer_accessor &timer_accessor;
|
|
|
|
|
|
|
|
|
|
|
|
Pthreads(Timer_accessor &timer_accessor)
|
|
|
|
: timer_accessor(timer_accessor) { }
|
|
|
|
|
|
|
|
void resume_all()
|
|
|
|
{
|
|
|
|
Genode::Lock::Guard g(mutex);
|
|
|
|
|
|
|
|
for (Pthread *p = pthreads; p; p = p->next)
|
|
|
|
p->lock.unlock();
|
|
|
|
}
|
|
|
|
|
2017-02-20 13:30:36 +01:00
|
|
|
unsigned long suspend_myself(Suspend_functor & check, unsigned long timeout_ms)
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
|
|
|
Pthread myself { timer_accessor, timeout_ms };
|
|
|
|
{
|
|
|
|
Genode::Lock::Guard g(mutex);
|
|
|
|
|
|
|
|
myself.next = pthreads;
|
|
|
|
pthreads = &myself;
|
|
|
|
}
|
2017-02-20 13:30:36 +01:00
|
|
|
|
|
|
|
if (check.suspend())
|
|
|
|
myself.lock.lock();
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
|
|
|
Genode::Lock::Guard g(mutex);
|
|
|
|
|
|
|
|
/* address of pointer to next pthread allows to change the head */
|
|
|
|
for (Pthread **next = &pthreads; *next; next = &(*next)->next) {
|
|
|
|
if (*next == &myself) {
|
|
|
|
*next = myself.next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:23:22 +02:00
|
|
|
return timeout_ms > 0 ? myself.duration_left() : 0;
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-02-01 21:07:14 +01:00
|
|
|
extern void (*libc_select_notify)();
|
|
|
|
|
2017-01-31 16:38:23 +01:00
|
|
|
struct Libc::Io_response_handler : Vfs::Io_response_handler
|
|
|
|
{
|
2017-02-01 21:07:14 +01:00
|
|
|
void handle_io_response(Vfs::Vfs_handle::Context *) override
|
2017-01-31 16:38:23 +01:00
|
|
|
{
|
2017-02-01 21:07:14 +01:00
|
|
|
/* some contexts may have been deblocked from select() */
|
|
|
|
if (libc_select_notify)
|
|
|
|
libc_select_notify();
|
|
|
|
|
|
|
|
/* resume all as any context may have been deblocked from blocking I/O */
|
2017-01-31 16:38:23 +01:00
|
|
|
Libc::resume_all();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/* internal utility */
|
|
|
|
static void resumed_callback();
|
|
|
|
static void suspended_callback();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Libc "kernel"
|
|
|
|
*
|
|
|
|
* This class represents the "kernel" of the libc-based application
|
2015-12-23 15:22:33 +01:00
|
|
|
* Blocking and deblocking happens here on libc functions like read() or
|
|
|
|
* select(). This combines blocking of the VFS backend and other signal sources
|
|
|
|
* (e.g., timers). The libc task runs on the component thread and allocates a
|
|
|
|
* secondary stack for the application task. Context switching uses
|
|
|
|
* setjmp/longjmp.
|
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
struct Libc::Kernel
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2017-02-20 16:08:06 +01:00
|
|
|
Genode::Env &_env;
|
2017-05-12 23:10:41 +02:00
|
|
|
Genode::Allocator &_heap;
|
2017-02-20 16:08:06 +01:00
|
|
|
Io_response_handler _io_response_handler;
|
|
|
|
Env_implementation _libc_env { _env, _heap, _io_response_handler };
|
|
|
|
Vfs_plugin _vfs { _libc_env, _heap };
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
Genode::Reconstructible<Genode::Io_signal_handler<Kernel>> _resume_main_handler {
|
2017-02-20 16:08:06 +01:00
|
|
|
_env.ep(), *this, &Kernel::_resume_main };
|
2016-05-25 15:47:22 +02:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
jmp_buf _kernel_context;
|
|
|
|
jmp_buf _user_context;
|
2017-05-18 16:04:21 +02:00
|
|
|
bool _valid_user_context = false;
|
|
|
|
bool _dispatch_pending_io_signals = false;
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
Genode::Thread &_myself { *Genode::Thread::myself() };
|
2016-05-09 15:04:37 +02:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
void *_user_stack = {
|
2016-05-09 15:04:37 +02:00
|
|
|
_myself.alloc_secondary_stack(_myself.name().string(),
|
|
|
|
Component::stack_size()) };
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
void (*_original_suspended_callback)() = nullptr;
|
|
|
|
|
|
|
|
enum State { KERNEL, USER };
|
|
|
|
|
|
|
|
State _state = KERNEL;
|
|
|
|
|
2017-02-20 14:23:34 +01:00
|
|
|
Application_code *_nested_app_code = nullptr;
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
Application_code *_app_code = nullptr;
|
|
|
|
bool _app_returned = false;
|
|
|
|
|
2017-02-21 17:35:51 +01:00
|
|
|
bool _resume_main_once = false;
|
|
|
|
bool _suspend_scheduled = false;
|
2017-02-14 22:26:03 +01:00
|
|
|
|
|
|
|
Select_handler_base *_scheduled_select_handler = nullptr;
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
void _resume_main() { _resume_main_once = true; }
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
struct Timer_accessor : Libc::Timer_accessor
|
|
|
|
{
|
|
|
|
Genode::Env &_env;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The '_timer' is constructed by whatever thread (main thread
|
|
|
|
* of pthread) that uses a time-related function first. Hence,
|
|
|
|
* the construction must be protected by a lock.
|
|
|
|
*/
|
|
|
|
Genode::Lock _lock;
|
|
|
|
|
|
|
|
Genode::Constructible<Timer> _timer;
|
|
|
|
|
|
|
|
Timer_accessor(Genode::Env &env) : _env(env) { }
|
|
|
|
|
|
|
|
Timer &timer() override
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
|
|
|
|
if (!_timer.constructed())
|
|
|
|
_timer.construct(_env);
|
|
|
|
|
|
|
|
return *_timer;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Timer_accessor _timer_accessor { _env };
|
|
|
|
|
|
|
|
struct Main_timeout : Timeout_handler
|
|
|
|
{
|
|
|
|
Timer_accessor &_timer_accessor;
|
|
|
|
Constructible<Timeout> _timeout;
|
2017-02-12 17:48:11 +01:00
|
|
|
Kernel &_kernel;
|
2016-12-13 17:09:35 +01:00
|
|
|
|
|
|
|
void _construct_timeout_once()
|
|
|
|
{
|
|
|
|
if (!_timeout.constructed())
|
|
|
|
_timeout.construct(_timer_accessor, *this);
|
|
|
|
}
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
Main_timeout(Timer_accessor &timer_accessor, Kernel &kernel)
|
|
|
|
: _timer_accessor(timer_accessor), _kernel(kernel)
|
2016-12-13 17:09:35 +01:00
|
|
|
{ }
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
void timeout(unsigned long timeout_ms)
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
|
|
|
_construct_timeout_once();
|
|
|
|
_timeout->start(timeout_ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long duration_left()
|
|
|
|
{
|
|
|
|
_construct_timeout_once();
|
|
|
|
return _timeout->duration_left();
|
|
|
|
}
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
void handle_timeout() override
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
2017-02-12 17:48:11 +01:00
|
|
|
_kernel._resume_main();
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
Main_timeout _main_timeout { _timer_accessor, *this };
|
2016-12-13 17:09:35 +01:00
|
|
|
|
|
|
|
Pthreads _pthreads { _timer_accessor };
|
|
|
|
|
2017-02-21 17:35:51 +01:00
|
|
|
struct Resumer
|
|
|
|
{
|
|
|
|
GENODE_RPC(Rpc_resume, void, resume);
|
|
|
|
GENODE_RPC_INTERFACE(Rpc_resume);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Resumer_component : Rpc_object<Resumer, Resumer_component>
|
|
|
|
{
|
|
|
|
Kernel &_kernel;
|
|
|
|
|
|
|
|
Resumer_component(Kernel &kernel) : _kernel(kernel) { }
|
|
|
|
|
|
|
|
void resume() { _kernel.run_after_resume(); }
|
|
|
|
};
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Trampoline to application (user) code
|
|
|
|
*
|
|
|
|
* This function is called by the main thread.
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
static void _user_entry(Libc::Kernel *kernel)
|
|
|
|
{
|
2017-02-20 13:30:36 +01:00
|
|
|
struct Check : Suspend_functor {
|
|
|
|
bool suspend() override { return true; }
|
|
|
|
} check;
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
kernel->_app_code->execute();
|
|
|
|
kernel->_app_returned = true;
|
2017-02-20 13:30:36 +01:00
|
|
|
kernel->_suspend_main(check, 0);
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool _main_context() const { return &_myself == Genode::Thread::myself(); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Utility to switch main context to kernel
|
|
|
|
*
|
|
|
|
* User context must be saved explicitly before this function is called
|
|
|
|
* to enable _switch_to_user() later.
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
void _switch_to_kernel()
|
|
|
|
{
|
|
|
|
_state = KERNEL;
|
|
|
|
_longjmp(_kernel_context, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility to switch main context to user
|
|
|
|
*
|
|
|
|
* Kernel context must be saved explicitly before this function is called
|
|
|
|
* to enable _switch_to_kernel() later.
|
|
|
|
*/
|
|
|
|
void _switch_to_user()
|
|
|
|
{
|
2017-02-12 17:48:11 +01:00
|
|
|
if (!_valid_user_context)
|
|
|
|
Genode::error("switching to invalid user context");
|
|
|
|
|
|
|
|
_resume_main_once = false;
|
2016-12-13 17:09:35 +01:00
|
|
|
_state = USER;
|
|
|
|
_longjmp(_user_context, 1);
|
|
|
|
}
|
|
|
|
|
2017-02-20 13:30:36 +01:00
|
|
|
unsigned long _suspend_main(Suspend_functor &check,
|
|
|
|
unsigned long timeout_ms)
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
2017-03-14 13:19:02 +01:00
|
|
|
/* check if we're running on the user context */
|
|
|
|
if (Thread::myself()->mystack().top != (Genode::addr_t)_user_stack) {
|
|
|
|
error("libc suspend() called from non-user context (",
|
|
|
|
__builtin_return_address(0), ") - aborting");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2017-02-20 13:30:36 +01:00
|
|
|
if (!check.suspend())
|
|
|
|
return 0;
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
if (timeout_ms > 0)
|
2017-02-12 17:48:11 +01:00
|
|
|
_main_timeout.timeout(timeout_ms);
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
if (!_setjmp(_user_context)) {
|
|
|
|
_valid_user_context = true;
|
2016-12-13 17:09:35 +01:00
|
|
|
_switch_to_kernel();
|
2017-02-12 17:48:11 +01:00
|
|
|
} else {
|
|
|
|
_valid_user_context = false;
|
|
|
|
}
|
2016-12-13 17:09:35 +01:00
|
|
|
|
2017-02-20 14:23:34 +01:00
|
|
|
/*
|
2017-05-18 16:04:21 +02:00
|
|
|
* During the suspension of the application code a nested
|
2017-02-20 14:23:34 +01:00
|
|
|
* Libc::with_libc() call took place, which will be executed
|
|
|
|
* before returning to the first Libc::with_libc() call.
|
|
|
|
*/
|
|
|
|
if (_nested_app_code) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to explicitly set the user context back to true
|
|
|
|
* because we are borrowing it to execute our nested application
|
|
|
|
* code.
|
|
|
|
*/
|
|
|
|
_valid_user_context = true;
|
|
|
|
|
|
|
|
_nested_app_code->execute();
|
|
|
|
_nested_app_code = nullptr;
|
|
|
|
_longjmp(_kernel_context, 1);
|
|
|
|
}
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
return timeout_ms > 0 ? _main_timeout.duration_left() : 0;
|
|
|
|
}
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-05-12 23:10:41 +02:00
|
|
|
Kernel(Genode::Env &env, Genode::Allocator &heap)
|
|
|
|
: _env(env), _heap(heap) { }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
~Kernel() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
Libc::Env & libc_env() { return _libc_env; }
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/**
|
|
|
|
* Setup kernel context and run libc application main context
|
|
|
|
*
|
2017-02-12 17:48:11 +01:00
|
|
|
* This function is called by the component thread on with_libc().
|
2016-12-13 17:09:35 +01:00
|
|
|
*/
|
2017-02-12 17:48:11 +01:00
|
|
|
void run(Libc::Application_code &app_code)
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
2016-12-13 17:09:35 +01:00
|
|
|
if (!_main_context() || _state != KERNEL) {
|
|
|
|
Genode::error(__PRETTY_FUNCTION__, " called from non-kernel context");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-12 12:39:18 +01:00
|
|
|
_resume_main_once = false;
|
|
|
|
_app_returned = false;
|
|
|
|
_app_code = &app_code;
|
2017-02-12 17:48:11 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/* save continuation of libc kernel (incl. current stack) */
|
|
|
|
if (!_setjmp(_kernel_context)) {
|
2017-02-12 17:48:11 +01:00
|
|
|
/* _setjmp() returned directly -> switch to user stack and call application code */
|
2016-12-13 17:09:35 +01:00
|
|
|
_state = USER;
|
|
|
|
call_func(_user_stack, (void *)_user_entry, (void *)this);
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
/* never reached */
|
|
|
|
}
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
/* _setjmp() returned after _longjmp() - user context suspended */
|
|
|
|
|
2017-02-21 17:35:51 +01:00
|
|
|
while ((!_app_returned) && (!_suspend_scheduled)) {
|
2017-05-18 16:04:21 +02:00
|
|
|
if (_dispatch_pending_io_signals) {
|
|
|
|
/* dispatch pending signals but don't block */
|
|
|
|
while (_env.ep().dispatch_pending_io_signal()) ;
|
|
|
|
} else {
|
|
|
|
/* block for signals */
|
|
|
|
_env.ep().wait_and_dispatch_one_io_signal();
|
|
|
|
}
|
2017-02-20 14:23:34 +01:00
|
|
|
|
2017-02-12 12:39:18 +01:00
|
|
|
if (_resume_main_once && !_setjmp(_kernel_context))
|
2017-02-12 17:48:11 +01:00
|
|
|
_switch_to_user();
|
|
|
|
}
|
2017-02-21 17:35:51 +01:00
|
|
|
|
|
|
|
_suspend_scheduled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run libc application main context after suspend and resume
|
|
|
|
*/
|
|
|
|
void run_after_resume()
|
|
|
|
{
|
|
|
|
if (!_setjmp(_kernel_context))
|
|
|
|
_switch_to_user();
|
|
|
|
|
|
|
|
while ((!_app_returned) && (!_suspend_scheduled)) {
|
2017-04-03 10:45:51 +02:00
|
|
|
_env.ep().wait_and_dispatch_one_io_signal();
|
2017-02-21 17:35:51 +01:00
|
|
|
if (_resume_main_once && !_setjmp(_kernel_context))
|
|
|
|
_switch_to_user();
|
|
|
|
}
|
|
|
|
|
|
|
|
_suspend_scheduled = false;
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Resume all contexts (main and pthreads)
|
|
|
|
*/
|
|
|
|
void resume_all()
|
|
|
|
{
|
2017-02-14 22:26:03 +01:00
|
|
|
if (_app_returned) {
|
|
|
|
if (_scheduled_select_handler)
|
|
|
|
_scheduled_select_handler->dispatch_select();
|
|
|
|
} else {
|
2017-02-20 16:08:06 +01:00
|
|
|
if (_main_context())
|
|
|
|
_resume_main();
|
|
|
|
else
|
|
|
|
Genode::Signal_transmitter(*_resume_main_handler).submit();
|
2017-02-14 22:26:03 +01:00
|
|
|
}
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
_pthreads.resume_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Suspend this context (main or pthread)
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2017-02-20 13:30:36 +01:00
|
|
|
unsigned long suspend(Suspend_functor &check, unsigned long timeout_ms)
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
2017-02-10 22:38:37 +01:00
|
|
|
if (timeout_ms > 0
|
|
|
|
&& timeout_ms > _timer_accessor.timer().max_timeout()) {
|
2016-12-13 17:09:35 +01:00
|
|
|
Genode::warning("libc: limiting exceeding timeout of ",
|
|
|
|
timeout_ms, " ms to maximum of ",
|
|
|
|
_timer_accessor.timer().max_timeout(), " ms");
|
|
|
|
|
2017-02-10 22:38:37 +01:00
|
|
|
timeout_ms = min(timeout_ms, _timer_accessor.timer().max_timeout());
|
|
|
|
}
|
2016-12-13 17:09:35 +01:00
|
|
|
|
2017-02-20 13:30:36 +01:00
|
|
|
return _main_context() ? _suspend_main(check, timeout_ms)
|
|
|
|
: _pthreads.suspend_myself(check, timeout_ms);
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
2017-05-18 16:04:21 +02:00
|
|
|
void dispatch_pending_io_signals()
|
|
|
|
{
|
|
|
|
if (!_main_context()) return;
|
|
|
|
|
|
|
|
if (!_setjmp(_user_context)) {
|
|
|
|
_valid_user_context = true;
|
|
|
|
_dispatch_pending_io_signals = true;
|
|
|
|
_resume_main_once = true; /* afterwards resume main */
|
|
|
|
_switch_to_kernel();
|
|
|
|
} else {
|
|
|
|
_valid_user_context = false;
|
|
|
|
_dispatch_pending_io_signals = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 22:38:37 +01:00
|
|
|
unsigned long current_time()
|
|
|
|
{
|
|
|
|
return _timer_accessor.timer().curr_time();
|
|
|
|
}
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Called from the main context (by fork)
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
void schedule_suspend(void(*original_suspended_callback) ())
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
2016-12-13 17:09:35 +01:00
|
|
|
if (_state != USER) {
|
|
|
|
Genode::error(__PRETTY_FUNCTION__, " called from non-user context");
|
2015-12-23 15:22:33 +01:00
|
|
|
return;
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/*
|
|
|
|
* We hook into suspend-resume callback chain to destruct and
|
|
|
|
* reconstruct parts of the kernel from the context of the initial
|
|
|
|
* thread, i.e., without holding any object locks.
|
|
|
|
*/
|
|
|
|
_original_suspended_callback = original_suspended_callback;
|
|
|
|
_env.ep().schedule_suspend(suspended_callback, resumed_callback);
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
if (!_setjmp(_user_context)) {
|
|
|
|
_valid_user_context = true;
|
2017-02-21 17:35:51 +01:00
|
|
|
_suspend_scheduled = true;
|
2016-12-13 17:09:35 +01:00
|
|
|
_switch_to_kernel();
|
2017-02-12 17:48:11 +01:00
|
|
|
} else {
|
|
|
|
_valid_user_context = false;
|
|
|
|
}
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
2017-02-14 22:26:03 +01:00
|
|
|
void schedule_select(Select_handler_base *h)
|
|
|
|
{
|
|
|
|
_scheduled_select_handler = h;
|
|
|
|
}
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Called from the context of the initial thread (on fork)
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
void entrypoint_suspended()
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
2017-02-20 16:08:06 +01:00
|
|
|
_resume_main_handler.destruct();
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
_original_suspended_callback();
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/**
|
|
|
|
* Called from the context of the initial thread (after fork)
|
|
|
|
*/
|
|
|
|
void entrypoint_resumed()
|
|
|
|
{
|
2017-02-20 16:08:06 +01:00
|
|
|
_resume_main_handler.construct(_env.ep(), *this, &Kernel::_resume_main);
|
|
|
|
|
2017-02-21 17:35:51 +01:00
|
|
|
Resumer_component resumer { *this };
|
|
|
|
|
|
|
|
Capability<Resumer> resumer_cap =
|
|
|
|
_env.ep().rpc_ep().manage(&resumer);
|
|
|
|
|
|
|
|
resumer_cap.call<Resumer::Rpc_resume>();
|
|
|
|
|
|
|
|
_env.ep().rpc_ep().dissolve(&resumer);
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
2017-02-20 14:23:34 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return if main is currently suspended
|
|
|
|
*/
|
|
|
|
bool main_suspended() { return _state == KERNEL; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute application code while already executing in run()
|
|
|
|
*/
|
|
|
|
void nested_execution(Libc::Application_code &app_code)
|
|
|
|
{
|
|
|
|
_nested_app_code = &app_code;
|
|
|
|
|
|
|
|
if (!_setjmp(_kernel_context)) {
|
|
|
|
_switch_to_user();
|
|
|
|
}
|
|
|
|
}
|
2016-12-13 17:09:35 +01:00
|
|
|
};
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2017-01-03 14:33:55 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/**
|
|
|
|
* Libc kernel singleton
|
|
|
|
*
|
|
|
|
* The singleton is implemented with the unmanaged-singleton utility
|
|
|
|
* in Component::construct() to ensure it is never destructed
|
|
|
|
* like normal static global objects. Otherwise, the task object may be
|
|
|
|
* destructed in a RPC to Rpc_resume, which would result in a deadlock.
|
|
|
|
*/
|
|
|
|
static Libc::Kernel *kernel;
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Main context execution was suspended (on fork)
|
|
|
|
*
|
|
|
|
* This function is executed in the context of the initial thread.
|
|
|
|
*/
|
|
|
|
static void suspended_callback() { kernel->entrypoint_suspended(); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-12-13 17:09:35 +01:00
|
|
|
* Resume main context execution (after fork)
|
2015-12-23 15:22:33 +01:00
|
|
|
*
|
2016-12-13 17:09:35 +01:00
|
|
|
* This function is executed in the context of the initial thread.
|
2015-12-23 15:22:33 +01:00
|
|
|
*/
|
2016-12-13 17:09:35 +01:00
|
|
|
static void resumed_callback() { kernel->entrypoint_resumed(); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
/*******************
|
|
|
|
** Libc task API **
|
|
|
|
*******************/
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
void Libc::resume_all() { kernel->resume_all(); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
|
2017-03-14 13:19:02 +01:00
|
|
|
unsigned long Libc::suspend(Suspend_functor &s, unsigned long timeout_ms)
|
2016-12-13 17:09:35 +01:00
|
|
|
{
|
2017-03-14 13:19:02 +01:00
|
|
|
if (!kernel) {
|
|
|
|
error("libc kernel not initialized, needed for suspend()");
|
|
|
|
exit(1);
|
|
|
|
}
|
2017-02-20 13:30:36 +01:00
|
|
|
return kernel->suspend(s, timeout_ms);
|
2016-12-13 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
2017-05-18 16:04:21 +02:00
|
|
|
|
|
|
|
void Libc::dispatch_pending_io_signals()
|
|
|
|
{
|
|
|
|
kernel->dispatch_pending_io_signals();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-10 22:38:37 +01:00
|
|
|
unsigned long Libc::current_time()
|
|
|
|
{
|
|
|
|
return kernel->current_time();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-13 17:09:35 +01:00
|
|
|
void Libc::schedule_suspend(void (*suspended) ())
|
|
|
|
{
|
|
|
|
if (!kernel) {
|
2017-03-14 13:19:02 +01:00
|
|
|
error("libc kernel not initialized, needed for fork()");
|
|
|
|
exit(1);
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
2016-12-13 17:09:35 +01:00
|
|
|
kernel->schedule_suspend(suspended);
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-14 22:26:03 +01:00
|
|
|
void Libc::schedule_select(Libc::Select_handler_base *h)
|
|
|
|
{
|
|
|
|
if (!kernel) {
|
|
|
|
error("libc kernel not initialized, needed for select()");
|
2017-03-14 13:19:02 +01:00
|
|
|
exit(1);
|
2017-02-14 22:26:03 +01:00
|
|
|
}
|
|
|
|
kernel->schedule_select(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-01 12:43:30 +01:00
|
|
|
void Libc::execute_in_application_context(Libc::Application_code &app_code)
|
|
|
|
{
|
|
|
|
/*
|
2017-02-12 17:48:11 +01:00
|
|
|
* XXX We don't support a second entrypoint - pthreads should work as they
|
|
|
|
* don't use this code.
|
2017-02-01 12:43:30 +01:00
|
|
|
*/
|
|
|
|
|
2017-03-14 13:19:02 +01:00
|
|
|
if (!kernel) {
|
|
|
|
error("libc kernel not initialized, needed for with_libc()");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
static bool nested = false;
|
|
|
|
|
|
|
|
if (nested) {
|
2017-02-20 14:23:34 +01:00
|
|
|
|
|
|
|
if (kernel->main_suspended()) {
|
|
|
|
kernel->nested_execution(app_code);
|
|
|
|
} else {
|
|
|
|
app_code.execute();
|
|
|
|
}
|
2017-02-12 17:48:11 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nested = true;
|
|
|
|
kernel->run(app_code);
|
|
|
|
nested = false;
|
2017-02-01 12:43:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-22 15:01:19 +01:00
|
|
|
/***************************
|
|
|
|
** Component entry point **
|
|
|
|
***************************/
|
|
|
|
|
|
|
|
Genode::size_t Component::stack_size() { return Libc::Component::stack_size(); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
|
2016-12-22 15:01:19 +01:00
|
|
|
void Component::construct(Genode::Env &env)
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
2017-03-09 22:22:55 +01:00
|
|
|
/* initialize the global pointer to environment variables */
|
|
|
|
static char *null_env = nullptr;
|
|
|
|
if (!environ) environ = &null_env;
|
|
|
|
|
2017-05-12 23:10:41 +02:00
|
|
|
Genode::Allocator &heap =
|
|
|
|
*unmanaged_singleton<Genode::Heap>(env.ram(), env.rm());
|
|
|
|
|
2016-10-30 15:17:24 +01:00
|
|
|
/* pass Genode::Env to libc subsystems that depend on it */
|
2017-05-12 23:10:41 +02:00
|
|
|
Libc::init_malloc(heap);
|
2017-01-31 16:01:07 +01:00
|
|
|
Libc::init_mem_alloc(env);
|
2016-12-22 15:01:19 +01:00
|
|
|
Libc::init_dl(env);
|
2017-02-22 14:23:06 +01:00
|
|
|
Libc::sysctl_init(env);
|
2016-10-30 15:17:24 +01:00
|
|
|
|
2017-05-12 23:10:41 +02:00
|
|
|
kernel = unmanaged_singleton<Libc::Kernel>(env, heap);
|
2017-03-15 15:40:55 +01:00
|
|
|
|
|
|
|
Libc::libc_config_init(kernel->libc_env().libc_config());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX The following two steps leave us with the dilemma that we don't know
|
|
|
|
* which linked library may depend on the successfull initialization of a
|
|
|
|
* plugin. For example, some high-level library may try to open a network
|
|
|
|
* connection in its constructor before the network-stack library is
|
|
|
|
* initialized. But, we can't initialize plugins before calling static
|
|
|
|
* constructors as those are needed to know about the libc plugin. The only
|
|
|
|
* solution is to remove all libc plugins beside the VFS implementation,
|
|
|
|
* which is our final goal anyway.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* finish static construction of component and libraries */
|
|
|
|
Libc::with_libc([&] () { env.exec_static_constructors(); });
|
|
|
|
|
2017-02-07 10:34:49 +01:00
|
|
|
/* initialize plugins that require Genode::Env */
|
|
|
|
auto init_plugin = [&] (Libc::Plugin &plugin) {
|
|
|
|
plugin.init(env);
|
|
|
|
};
|
|
|
|
Libc::plugin_registry()->for_each_plugin(init_plugin);
|
|
|
|
|
2017-02-12 17:48:11 +01:00
|
|
|
/* construct libc component on kernel stack */
|
|
|
|
Libc::Component::construct(kernel->libc_env());
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-22 15:01:19 +01:00
|
|
|
/**
|
|
|
|
* Default stack size for libc-using components
|
|
|
|
*/
|
|
|
|
Genode::size_t Libc::Component::stack_size() __attribute__((weak));
|
2017-02-12 17:48:11 +01:00
|
|
|
Genode::size_t Libc::Component::stack_size() { return 32UL*1024*sizeof(long); }
|