2015-12-23 15:22:33 +01:00
|
|
|
/*
|
|
|
|
* \brief User-level task based libc
|
|
|
|
* \author Christian Helmuth
|
|
|
|
* \date 2016-01-22
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/component.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/thread.h>
|
|
|
|
#include <base/rpc_server.h>
|
|
|
|
#include <base/rpc_client.h>
|
|
|
|
|
|
|
|
/* libc-internal includes */
|
|
|
|
#include <internal/call_func.h>
|
|
|
|
#include <base/internal/unmanaged_singleton.h>
|
|
|
|
|
|
|
|
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
/* escape sequences for highlighting debug message prefixes */
|
|
|
|
#define LIBC_ESC_START "\033[32m"
|
|
|
|
#define LIBC_ESC_END "\033[0m"
|
|
|
|
|
|
|
|
#define P(...) \
|
|
|
|
do { \
|
|
|
|
int dummy; \
|
|
|
|
using namespace Genode; \
|
|
|
|
Hex ctx((addr_t)&dummy >> 20, Hex::OMIT_PREFIX); \
|
|
|
|
log(LIBC_ESC_START "[", ctx, "] ", \
|
|
|
|
__PRETTY_FUNCTION__, ":", __LINE__, \
|
|
|
|
LIBC_ESC_END " ", ##__VA_ARGS__); \
|
2015-12-23 15:22:33 +01:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
namespace Libc {
|
|
|
|
class Task;
|
|
|
|
|
2016-04-27 22:11:38 +02:00
|
|
|
void (*original_call_component_construct)(Genode::Env &);
|
|
|
|
void call_component_construct(Genode::Env &env);
|
2015-12-23 15:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct Task_resume
|
|
|
|
{
|
|
|
|
GENODE_RPC(Rpc_resume, void, resume);
|
|
|
|
GENODE_RPC_INTERFACE(Rpc_resume);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-04-19 15:35:35 +02:00
|
|
|
Genode::size_t Component::stack_size() {
|
|
|
|
return 32UL * 1024 * sizeof(Genode::addr_t); }
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
/**
|
|
|
|
* Libc task
|
|
|
|
*
|
|
|
|
* The libc task represents the "kernel" of the libc-based application.
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
class Libc::Task : public Genode::Rpc_object<Task_resume, Libc::Task>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2016-04-27 22:11:38 +02:00
|
|
|
Genode::Env &_env;
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Application context and execution state
|
|
|
|
*/
|
|
|
|
bool _app_runnable = true;
|
|
|
|
jmp_buf _app_task;
|
|
|
|
|
2016-05-09 15:04:37 +02:00
|
|
|
Genode::Thread &_myself = *Genode::Thread::myself();
|
|
|
|
|
2015-12-23 15:22:33 +01:00
|
|
|
void *_app_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
|
|
|
|
|
|
|
/**
|
|
|
|
* Libc context
|
|
|
|
*/
|
|
|
|
jmp_buf _libc_task;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Trampoline to application code
|
|
|
|
*/
|
|
|
|
static void _app_entry(Task *);
|
|
|
|
|
|
|
|
/* executed in the context of the main thread */
|
|
|
|
static void _resumed_callback();
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2016-04-27 22:11:38 +02:00
|
|
|
Task(Genode::Env &env) : _env(env) { }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
~Task() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
|
|
|
void run()
|
|
|
|
{
|
|
|
|
/* save continuation of libc task (incl. current stack) */
|
|
|
|
if (!_setjmp(_libc_task)) {
|
|
|
|
/* _setjmp() returned directly -> switch to app stack and launch component */
|
|
|
|
call_func(_app_stack, (void *)_app_entry, (void *)this);
|
|
|
|
|
|
|
|
/* never reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* _setjmp() returned after _longjmp() -> we're done */
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called in the context of the entrypoint via RPC
|
|
|
|
*/
|
|
|
|
void resume()
|
|
|
|
{
|
|
|
|
if (!_setjmp(_libc_task))
|
|
|
|
_longjmp(_app_task, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from the app context (by fork)
|
|
|
|
*/
|
|
|
|
void schedule_suspend(void(*suspended_callback) ())
|
|
|
|
{
|
|
|
|
if (_setjmp(_app_task))
|
|
|
|
return;
|
|
|
|
|
|
|
|
_env.ep().schedule_suspend(suspended_callback, _resumed_callback);
|
|
|
|
|
|
|
|
/* switch to libc task, which will return to entrypoint */
|
|
|
|
_longjmp(_libc_task, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from the context of the initial thread
|
|
|
|
*/
|
|
|
|
void resumed()
|
|
|
|
{
|
|
|
|
Genode::Capability<Task_resume> cap = _env.ep().manage(*this);
|
|
|
|
cap.call<Task_resume::Rpc_resume>();
|
|
|
|
_env.ep().dissolve(*this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************
|
|
|
|
** Libc task implementation **
|
|
|
|
******************************/
|
|
|
|
|
|
|
|
void Libc::Task::_app_entry(Task *task)
|
|
|
|
{
|
|
|
|
original_call_component_construct(task->_env);
|
|
|
|
|
|
|
|
/* returned from task - switch stack to libc and return to dispatch loop */
|
|
|
|
_longjmp(task->_libc_task, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Libc task singleton
|
|
|
|
*
|
|
|
|
* The singleton is implemented with the unmanaged-singleton utility 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::Task *task;
|
|
|
|
|
|
|
|
|
|
|
|
void Libc::Task::_resumed_callback() { task->resumed(); }
|
|
|
|
|
|
|
|
|
|
|
|
namespace Libc {
|
|
|
|
|
|
|
|
void schedule_suspend(void (*suspended) ())
|
|
|
|
{
|
|
|
|
task->schedule_suspend(suspended);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** Component-startup hook **
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
/* XXX needs base-internal header? */
|
2016-04-27 22:11:38 +02:00
|
|
|
namespace Genode { extern void (*call_component_construct)(Genode::Env &); }
|
2015-12-23 15:22:33 +01:00
|
|
|
|
2016-04-27 22:11:38 +02:00
|
|
|
void Libc::call_component_construct(Genode::Env &env)
|
2015-12-23 15:22:33 +01:00
|
|
|
{
|
|
|
|
task = unmanaged_singleton<Libc::Task>(env);
|
|
|
|
task->run();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void __attribute__((constructor)) libc_task_constructor(void)
|
|
|
|
{
|
|
|
|
/* hook into component startup */
|
|
|
|
Libc::original_call_component_construct = Genode::call_component_construct;
|
|
|
|
Genode::call_component_construct = &Libc::call_component_construct;
|
|
|
|
}
|