mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
libc: component-compatible execution semantics
Now, the libc kernel supports to execute application code from all RPC functions not only Component::construct(). This is enabled by the Libc::with_libc() scope function.
This commit is contained in:
parent
3a65f0bba3
commit
0aac473229
@ -255,7 +255,7 @@ struct Libc::Pthreads
|
|||||||
_timeout.start(timeout_ms);
|
_timeout.start(timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_timeout()
|
void handle_timeout() override
|
||||||
{
|
{
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
@ -347,6 +347,7 @@ struct Libc::Kernel
|
|||||||
|
|
||||||
jmp_buf _kernel_context;
|
jmp_buf _kernel_context;
|
||||||
jmp_buf _user_context;
|
jmp_buf _user_context;
|
||||||
|
bool _valid_user_context = false;
|
||||||
|
|
||||||
Genode::Thread &_myself { *Genode::Thread::myself() };
|
Genode::Thread &_myself { *Genode::Thread::myself() };
|
||||||
|
|
||||||
@ -354,15 +355,18 @@ struct Libc::Kernel
|
|||||||
_myself.alloc_secondary_stack(_myself.name().string(),
|
_myself.alloc_secondary_stack(_myself.name().string(),
|
||||||
Component::stack_size()) };
|
Component::stack_size()) };
|
||||||
|
|
||||||
Genode::Reconstructible<Genode::Signal_handler<Kernel>> _resume_main_handler {
|
|
||||||
_env.ep(), *this, &Kernel::_resume_main };
|
|
||||||
|
|
||||||
void (*_original_suspended_callback)() = nullptr;
|
void (*_original_suspended_callback)() = nullptr;
|
||||||
|
|
||||||
enum State { KERNEL, USER };
|
enum State { KERNEL, USER };
|
||||||
|
|
||||||
State _state = KERNEL;
|
State _state = KERNEL;
|
||||||
|
|
||||||
|
Application_code *_app_code = nullptr;
|
||||||
|
bool _app_returned = false;
|
||||||
|
|
||||||
|
bool _resume_main_once = false;
|
||||||
|
void _resume_main() { _resume_main_once = true; }
|
||||||
|
|
||||||
struct Timer_accessor : Libc::Timer_accessor
|
struct Timer_accessor : Libc::Timer_accessor
|
||||||
{
|
{
|
||||||
Genode::Env &_env;
|
Genode::Env &_env;
|
||||||
@ -393,10 +397,9 @@ struct Libc::Kernel
|
|||||||
|
|
||||||
struct Main_timeout : Timeout_handler
|
struct Main_timeout : Timeout_handler
|
||||||
{
|
{
|
||||||
Genode::Signal_context_capability _signal_cap;
|
|
||||||
|
|
||||||
Timer_accessor &_timer_accessor;
|
Timer_accessor &_timer_accessor;
|
||||||
Constructible<Timeout> _timeout;
|
Constructible<Timeout> _timeout;
|
||||||
|
Kernel &_kernel;
|
||||||
|
|
||||||
void _construct_timeout_once()
|
void _construct_timeout_once()
|
||||||
{
|
{
|
||||||
@ -404,13 +407,12 @@ struct Libc::Kernel
|
|||||||
_timeout.construct(_timer_accessor, *this);
|
_timeout.construct(_timer_accessor, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Main_timeout(Timer_accessor &timer_accessor)
|
Main_timeout(Timer_accessor &timer_accessor, Kernel &kernel)
|
||||||
: _timer_accessor(timer_accessor)
|
: _timer_accessor(timer_accessor), _kernel(kernel)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void timeout(unsigned long timeout_ms, Signal_context_capability signal_cap)
|
void timeout(unsigned long timeout_ms)
|
||||||
{
|
{
|
||||||
_signal_cap = signal_cap;
|
|
||||||
_construct_timeout_once();
|
_construct_timeout_once();
|
||||||
_timeout->start(timeout_ms);
|
_timeout->start(timeout_ms);
|
||||||
}
|
}
|
||||||
@ -421,20 +423,13 @@ struct Libc::Kernel
|
|||||||
return _timeout->duration_left();
|
return _timeout->duration_left();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_timeout()
|
void handle_timeout() override
|
||||||
{
|
{
|
||||||
/*
|
_kernel._resume_main();
|
||||||
* XXX I don't dare to call _resume_main() here as this switches
|
|
||||||
* immediately to the user stack, which would result in dead lock
|
|
||||||
* if the calling context holds any lock in the timeout
|
|
||||||
* implementation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Genode::Signal_transmitter(_signal_cap).submit();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Main_timeout _main_timeout { _timer_accessor };
|
Main_timeout _main_timeout { _timer_accessor, *this };
|
||||||
|
|
||||||
Pthreads _pthreads { _timer_accessor };
|
Pthreads _pthreads { _timer_accessor };
|
||||||
|
|
||||||
@ -445,10 +440,9 @@ struct Libc::Kernel
|
|||||||
*/
|
*/
|
||||||
static void _user_entry(Libc::Kernel *kernel)
|
static void _user_entry(Libc::Kernel *kernel)
|
||||||
{
|
{
|
||||||
Libc::Component::construct(kernel->_libc_env);
|
kernel->_app_code->execute();
|
||||||
|
kernel->_app_returned = true;
|
||||||
/* returned from user - switch stack to libc and return to dispatch loop */
|
kernel->_suspend_main(0);
|
||||||
kernel->_switch_to_kernel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _main_context() const { return &_myself == Genode::Thread::myself(); }
|
bool _main_context() const { return &_myself == Genode::Thread::myself(); }
|
||||||
@ -473,29 +467,25 @@ struct Libc::Kernel
|
|||||||
*/
|
*/
|
||||||
void _switch_to_user()
|
void _switch_to_user()
|
||||||
{
|
{
|
||||||
|
if (!_valid_user_context)
|
||||||
|
Genode::error("switching to invalid user context");
|
||||||
|
|
||||||
|
_resume_main_once = false;
|
||||||
_state = USER;
|
_state = USER;
|
||||||
_longjmp(_user_context, 1);
|
_longjmp(_user_context, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called from signal handler */
|
|
||||||
void _resume_main()
|
|
||||||
{
|
|
||||||
if (!_main_context() || _state != KERNEL) {
|
|
||||||
Genode::error(__PRETTY_FUNCTION__, " called from non-kernel context");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_setjmp(_kernel_context))
|
|
||||||
_switch_to_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long _suspend_main(unsigned long timeout_ms)
|
unsigned long _suspend_main(unsigned long timeout_ms)
|
||||||
{
|
{
|
||||||
if (timeout_ms > 0)
|
if (timeout_ms > 0)
|
||||||
_main_timeout.timeout(timeout_ms, *_resume_main_handler);
|
_main_timeout.timeout(timeout_ms);
|
||||||
|
|
||||||
if (!_setjmp(_user_context))
|
if (!_setjmp(_user_context)) {
|
||||||
|
_valid_user_context = true;
|
||||||
_switch_to_kernel();
|
_switch_to_kernel();
|
||||||
|
} else {
|
||||||
|
_valid_user_context = false;
|
||||||
|
}
|
||||||
|
|
||||||
return timeout_ms > 0 ? _main_timeout.duration_left() : 0;
|
return timeout_ms > 0 ? _main_timeout.duration_left() : 0;
|
||||||
}
|
}
|
||||||
@ -506,29 +496,39 @@ struct Libc::Kernel
|
|||||||
|
|
||||||
~Kernel() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); }
|
~Kernel() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); }
|
||||||
|
|
||||||
|
Libc::Env & libc_env() { return _libc_env; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup kernel context and run libc application main context
|
* Setup kernel context and run libc application main context
|
||||||
*
|
*
|
||||||
* This function is called by the component thread at component
|
* This function is called by the component thread on with_libc().
|
||||||
* construction time.
|
|
||||||
*/
|
*/
|
||||||
void run()
|
void run(Libc::Application_code &app_code)
|
||||||
{
|
{
|
||||||
if (!_main_context() || _state != KERNEL) {
|
if (!_main_context() || _state != KERNEL) {
|
||||||
Genode::error(__PRETTY_FUNCTION__, " called from non-kernel context");
|
Genode::error(__PRETTY_FUNCTION__, " called from non-kernel context");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_app_returned = false;
|
||||||
|
_app_code = &app_code;
|
||||||
|
|
||||||
/* save continuation of libc kernel (incl. current stack) */
|
/* save continuation of libc kernel (incl. current stack) */
|
||||||
if (!_setjmp(_kernel_context)) {
|
if (!_setjmp(_kernel_context)) {
|
||||||
/* _setjmp() returned directly -> switch to user stack and launch component */
|
/* _setjmp() returned directly -> switch to user stack and call application code */
|
||||||
_state = USER;
|
_state = USER;
|
||||||
call_func(_user_stack, (void *)_user_entry, (void *)this);
|
call_func(_user_stack, (void *)_user_entry, (void *)this);
|
||||||
|
|
||||||
/* never reached */
|
/* never reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _setjmp() returned after _longjmp() -> we're done */
|
/* _setjmp() returned after _longjmp() - user context suspended */
|
||||||
|
|
||||||
|
while (!_app_returned) {
|
||||||
|
_env.ep().wait_and_dispatch_one_signal();
|
||||||
|
if (_resume_main_once)
|
||||||
|
_switch_to_user();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -536,8 +536,7 @@ struct Libc::Kernel
|
|||||||
*/
|
*/
|
||||||
void resume_all()
|
void resume_all()
|
||||||
{
|
{
|
||||||
Genode::Signal_transmitter(*_resume_main_handler).submit();
|
_resume_main();
|
||||||
|
|
||||||
_pthreads.resume_all();
|
_pthreads.resume_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,8 +581,12 @@ struct Libc::Kernel
|
|||||||
_original_suspended_callback = original_suspended_callback;
|
_original_suspended_callback = original_suspended_callback;
|
||||||
_env.ep().schedule_suspend(suspended_callback, resumed_callback);
|
_env.ep().schedule_suspend(suspended_callback, resumed_callback);
|
||||||
|
|
||||||
if (!_setjmp(_user_context))
|
if (!_setjmp(_user_context)) {
|
||||||
|
_valid_user_context = true;
|
||||||
_switch_to_kernel();
|
_switch_to_kernel();
|
||||||
|
} else {
|
||||||
|
_valid_user_context = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -591,8 +594,6 @@ struct Libc::Kernel
|
|||||||
*/
|
*/
|
||||||
void entrypoint_suspended()
|
void entrypoint_suspended()
|
||||||
{
|
{
|
||||||
_resume_main_handler.destruct();
|
|
||||||
|
|
||||||
_original_suspended_callback();
|
_original_suspended_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,9 +602,7 @@ struct Libc::Kernel
|
|||||||
*/
|
*/
|
||||||
void entrypoint_resumed()
|
void entrypoint_resumed()
|
||||||
{
|
{
|
||||||
_resume_main_handler.construct(_env.ep(), *this, &Kernel::_resume_main);
|
/* TODO */ _resume_main();
|
||||||
|
|
||||||
Genode::Signal_transmitter(*_resume_main_handler).submit();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -657,7 +656,7 @@ unsigned long Libc::current_time()
|
|||||||
void Libc::schedule_suspend(void (*suspended) ())
|
void Libc::schedule_suspend(void (*suspended) ())
|
||||||
{
|
{
|
||||||
if (!kernel) {
|
if (!kernel) {
|
||||||
error("libc kernel not initialized, needed for suspend");
|
error("libc kernel not initialized, needed for suspend()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
kernel->schedule_suspend(suspended);
|
kernel->schedule_suspend(suspended);
|
||||||
@ -669,11 +668,25 @@ void Libc::execute_in_application_context(Libc::Application_code &app_code)
|
|||||||
warning("executing code in application context, not implemented");
|
warning("executing code in application context, not implemented");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX missing: switch to/from libc app task
|
* XXX We don't support a second entrypoint - pthreads should work as they
|
||||||
* XXX Should we detect nested calls?
|
* don't use this code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app_code.execute();
|
static bool nested = false;
|
||||||
|
|
||||||
|
if (nested) {
|
||||||
|
error("nested call of with_libc() detected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kernel) {
|
||||||
|
error("libc kernel not initialized, needed for with_libc()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nested = true;
|
||||||
|
kernel->run(app_code);
|
||||||
|
nested = false;
|
||||||
|
|
||||||
warning("leaving application context");
|
warning("leaving application context");
|
||||||
}
|
}
|
||||||
@ -699,7 +712,9 @@ void Component::construct(Genode::Env &env)
|
|||||||
Libc::plugin_registry()->for_each_plugin(init_plugin);
|
Libc::plugin_registry()->for_each_plugin(init_plugin);
|
||||||
|
|
||||||
kernel = unmanaged_singleton<Libc::Kernel>(env);
|
kernel = unmanaged_singleton<Libc::Kernel>(env);
|
||||||
kernel->run();
|
|
||||||
|
/* construct libc component on kernel stack */
|
||||||
|
Libc::Component::construct(kernel->libc_env());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -707,7 +722,4 @@ void Component::construct(Genode::Env &env)
|
|||||||
* Default stack size for libc-using components
|
* Default stack size for libc-using components
|
||||||
*/
|
*/
|
||||||
Genode::size_t Libc::Component::stack_size() __attribute__((weak));
|
Genode::size_t Libc::Component::stack_size() __attribute__((weak));
|
||||||
Genode::size_t Libc::Component::stack_size() {
|
Genode::size_t Libc::Component::stack_size() { return 32UL*1024*sizeof(long); }
|
||||||
return 32UL * 1024 * sizeof(Genode::addr_t); }
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ extern char **environ;
|
|||||||
extern "C" int main(int argc, char ** argv, char **envp);
|
extern "C" int main(int argc, char ** argv, char **envp);
|
||||||
|
|
||||||
|
|
||||||
void Libc::Component::construct(Libc::Env &env)
|
static void construct_component(Libc::Env &env)
|
||||||
{
|
{
|
||||||
using Genode::Xml_node;
|
using Genode::Xml_node;
|
||||||
using Genode::Xml_attribute;
|
using Genode::Xml_attribute;
|
||||||
@ -105,3 +105,9 @@ void Libc::Component::construct(Libc::Env &env)
|
|||||||
|
|
||||||
exit(main(genode_argc, genode_argv, genode_envp));
|
exit(main(genode_argc, genode_argv, genode_envp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Libc::Component::construct(Libc::Env &env)
|
||||||
|
{
|
||||||
|
Libc::with_libc([&] () { construct_component(env); });
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user