mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-07 06:18:48 +00:00
50e0f3b977
Issue #3922
188 lines
5.1 KiB
C++
188 lines
5.1 KiB
C++
/*
|
|
* \brief Virtualbox adjusted pthread_create implementation
|
|
* \author Alexander Boettcher
|
|
* \date 2014-04-09
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2014-2017 Genode Labs GmbH
|
|
*
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
* version 2.
|
|
*/
|
|
|
|
/* Genode */
|
|
#include <base/attached_rom_dataspace.h>
|
|
#include <base/log.h>
|
|
#include <base/sleep.h>
|
|
#include <base/thread.h>
|
|
#include <cpu_session/connection.h>
|
|
|
|
/* Genode libc pthread binding */
|
|
#include <internal/thread_create.h>
|
|
|
|
#include "sup.h"
|
|
#include "vmm.h"
|
|
|
|
/* libc */
|
|
#include <pthread.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/* vbox */
|
|
#include <internal/thread.h>
|
|
|
|
static bool use_priorities()
|
|
{
|
|
Genode::Attached_rom_dataspace const platform(genode_env(), "platform_info");
|
|
Genode::Xml_node const kernel = platform.xml().sub_node("kernel");
|
|
return kernel.attribute_value("name", Genode::String<16>("unknown")) == "nova";
|
|
}
|
|
|
|
static long prio_class(RTTHREADTYPE const type)
|
|
{
|
|
unsigned const VIRTUAL_GENODE_VBOX_LEVELS = 16;
|
|
static_assert (RTTHREADTYPE_END < VIRTUAL_GENODE_VBOX_LEVELS,
|
|
"prio levels exceeds VIRTUAL_GENODE_VBOX_LEVELS");
|
|
|
|
/* evaluate once */
|
|
static bool const priorities = use_priorities();
|
|
|
|
if (!priorities)
|
|
return Genode::Cpu_session::DEFAULT_PRIORITY;
|
|
|
|
return (VIRTUAL_GENODE_VBOX_LEVELS - type) *
|
|
Genode::Cpu_session::PRIORITY_LIMIT / VIRTUAL_GENODE_VBOX_LEVELS;
|
|
}
|
|
|
|
static Genode::Cpu_connection * cpu_connection(RTTHREADTYPE type)
|
|
{
|
|
using namespace Genode;
|
|
|
|
static Cpu_connection * con[RTTHREADTYPE_END - 1];
|
|
static Mutex mutex { };
|
|
|
|
Assert(type && type < RTTHREADTYPE_END);
|
|
|
|
Mutex::Guard guard(mutex);
|
|
|
|
if (con[type - 1])
|
|
return con[type - 1];
|
|
|
|
char * data = new (vmm_heap()) char[16];
|
|
|
|
Genode::snprintf(data, 16, "vbox %u", type);
|
|
|
|
con[type - 1] = new (vmm_heap()) Cpu_connection(genode_env(), data,
|
|
prio_class(type));
|
|
|
|
return con[type - 1];
|
|
}
|
|
|
|
|
|
static int create_thread(pthread_t *thread, const pthread_attr_t *attr,
|
|
void *(*start_routine) (void *), void *arg)
|
|
{
|
|
PRTTHREADINT rtthread = reinterpret_cast<PRTTHREADINT>(arg);
|
|
|
|
Assert(rtthread);
|
|
|
|
size_t const utcb_size = 4096;
|
|
|
|
size_t stack_size = Genode::Thread::stack_virtual_size() -
|
|
utcb_size - 2 * (1UL << 12);
|
|
|
|
if (rtthread->cbStack < stack_size)
|
|
stack_size = rtthread->cbStack;
|
|
|
|
/* sanity check - emt and vcpu thread have to have same prio class */
|
|
if (strstr(rtthread->szName, "EMT") == rtthread->szName)
|
|
Assert(rtthread->enmType == RTTHREADTYPE_EMULATION);
|
|
|
|
if (rtthread->enmType == RTTHREADTYPE_EMULATION) {
|
|
|
|
unsigned int cpu_id = 0;
|
|
sscanf(rtthread->szName, "EMT-%u", &cpu_id);
|
|
|
|
Genode::Cpu_connection * cpu = cpu_connection(RTTHREADTYPE_EMULATION);
|
|
Genode::Affinity::Space space = cpu->affinity_space();
|
|
Genode::Affinity::Location location(space.location_of_index(cpu_id));
|
|
|
|
if (create_emt_vcpu(thread, stack_size, start_routine, arg,
|
|
cpu, location, cpu_id, rtthread->szName,
|
|
prio_class(rtthread->enmType)))
|
|
return 0;
|
|
/*
|
|
* The virtualization layer had no need to setup the EMT
|
|
* specially, so create it as a ordinary pthread.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Make sure timers run at the same priority as component threads, otherwise
|
|
* no timer progress can be made. See 'rtTimeNanoTSInternalRef' (timesupref.h)
|
|
* and 'rtTimerLRThread' (timerlr-generic.cpp)
|
|
*/
|
|
bool const rtthread_timer = rtthread->enmType == RTTHREADTYPE_TIMER;
|
|
|
|
if (rtthread_timer) {
|
|
return Libc::pthread_create(thread, start_routine, arg,
|
|
stack_size, rtthread->szName, nullptr,
|
|
Genode::Affinity::Location());
|
|
|
|
} else {
|
|
using namespace Genode;
|
|
Cpu_connection *cpu = cpu_connection(rtthread->enmType);
|
|
return cpu->retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2},
|
|
[&] ()
|
|
{
|
|
return Libc::pthread_create(thread, start_routine, arg,
|
|
stack_size, rtthread->szName, cpu,
|
|
Genode::Affinity::Location());
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|
void *(*start_routine) (void *), void *arg)
|
|
{
|
|
PRTTHREADINT rtthread = reinterpret_cast<PRTTHREADINT>(arg);
|
|
|
|
/* retry thread creation once after CPU session upgrade */
|
|
for (unsigned i = 0; i < 2; i++) {
|
|
using namespace Genode;
|
|
|
|
try {
|
|
return create_thread(thread, attr, start_routine, arg); }
|
|
catch (Out_of_ram) {
|
|
log("Upgrading memory for creation of "
|
|
"thread '", Cstring(rtthread->szName), "'");
|
|
cpu_connection(rtthread->enmType)->upgrade_ram(4096);
|
|
} catch (Out_of_caps) {
|
|
error("out of caps ...");
|
|
}
|
|
catch (...) { break; }
|
|
}
|
|
|
|
Genode::error("could not create vbox pthread - halt");
|
|
Genode::sleep_forever();
|
|
return EAGAIN;
|
|
}
|
|
|
|
extern "C" int pthread_attr_setdetachstate(pthread_attr_t *, int)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C" int pthread_attr_setstacksize(pthread_attr_t *, size_t)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C" int pthread_atfork(void (*)(void), void (*)(void), void (*)(void))
|
|
{
|
|
return 0;
|
|
}
|