genode/repos/base-pistachio/src/core/platform_thread.cc

263 lines
6.0 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Pistachio thread facility
* \author Julian Stecklina
* \date 2008-03-19
*/
/*
2013-01-10 21:44:47 +01:00
* Copyright (C) 2008-2013 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* 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/printf.h>
#include <util/string.h>
#include <pistachio/thread_helper.h>
#include <pistachio/kip.h>
/* core includes */
#include <platform_pd.h>
#include <platform_thread.h>
/* Pistachio includes */
namespace Pistachio
{
#include <l4/types.h>
#include <l4/thread.h>
#include <l4/schedule.h>
#include <l4/sigma0.h>
};
using namespace Genode;
using namespace Pistachio;
static const bool verbose = false;
static const bool verbose2 = true;
#define PT_DBG(args...) if (verbose) { PDBG(args); } else { }
2011-12-22 16:19:25 +01:00
void Platform_thread::affinity(Affinity::Location location)
2011-12-22 16:19:25 +01:00
{
_location = location;
unsigned const cpu_no = location.xpos();
2011-12-22 16:19:25 +01:00
if (cpu_no >= L4_NumProcessors(get_kip())) {
PERR("Invalid processor number.");
return;
}
if (_l4_thread_id != L4_nilthread)
if (L4_Set_ProcessorNo(_l4_thread_id, cpu_no) == 0)
PERR("Error setting processor number.");
2011-12-22 16:19:25 +01:00
}
Affinity::Location Platform_thread::affinity()
{
return _location;
}
int Platform_thread::start(void *ip, void *sp)
2011-12-22 16:19:25 +01:00
{
L4_ThreadId_t thread = _l4_thread_id;
L4_ThreadId_t pager = _pager ? _pager->cap().dst() : L4_nilthread;
2011-12-22 16:19:25 +01:00
/* XXX should always be the root task */
L4_ThreadId_t preempter = L4_Myself();
PT_DBG("Trying to Platform_thread::start the thread '%s'.", _name);
if (verbose2)
printf("thread '%s' has id 0x%08lx (task = 0x%x, thread = 0x%x)\n",
_name, thread.raw, _platform_pd->pd_id(), _thread_id);
if (_thread_id == THREAD_INVALID) {
PERR("Trying to start a thread with invalid ID.");
return -1;
}
L4_Word_t utcb_location = _platform_pd->_utcb_location(_thread_id);
PT_DBG("New thread's utcb at %08lx.", utcb_location);
PT_DBG("Attaching thread to address space 0x%08lx.",
_platform_pd->_l4_task_id.raw);
PT_DBG("sp = %p, ip = %p", sp, ip);
int ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id,
preempter, L4_Myself(), (void *)utcb_location);
PT_DBG("L4_ThreadControl() = %d", ret);
if (ret != 1) {
PERR("Error code = 0x%08lx", L4_ErrorCode());
PERR("L4_ThreadControl failed.");
return -2;
}
/* set real pager */
ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id,
L4_nilthread, pager, (void *)-1);
if (ret != 1) {
PERR("Error code = 0x%08lx", L4_ErrorCode());
PERR("Setting pager failed.");
return -3;
}
/* get the thread running on the right cpu */
affinity(_location);
2011-12-22 16:19:25 +01:00
/* assign priority */
if (!L4_Set_Priority(thread,
Cpu_session::scale_priority(DEFAULT_PRIORITY, _priority)))
PWRN("Could not set thread prioritry to default");
/* send start message */
L4_Msg_t msg;
L4_Clear(&msg);
L4_Append(&msg, (L4_Word_t)ip);
L4_Append(&msg, (L4_Word_t)sp);
L4_Load(&msg);
L4_MsgTag_t tag = L4_Send(thread);
if (L4_IpcFailed(tag)) {
PERR("Starting thread failed. (IPC error)");
return -4;
}
PT_DBG("Done starting thread.");
return 0;
}
void Platform_thread::pause()
{
PDBG("not implemented");
}
void Platform_thread::resume()
{
PDBG("not implemented");
}
void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id,
Platform_pd *pd)
{
_thread_id = thread_id;
_l4_thread_id = l4_thread_id;
_platform_pd = pd;
}
void Platform_thread::unbind()
{
PT_DBG("Killing thread 0x%08lx.", _l4_thread_id.raw);
L4_Word_t res = L4_ThreadControl(_l4_thread_id, L4_nilthread,
L4_nilthread, L4_nilthread, (void *)-1);
if (res != 1)
PERR("Deleting thread 0x%08lx failed. Continuing...", _l4_thread_id.raw);
_thread_id = THREAD_INVALID;
_l4_thread_id = L4_nilthread;
_platform_pd = 0;
}
void Platform_thread::state(Thread_state)
2011-12-22 16:19:25 +01:00
{
PDBG("Not implemented");
throw Cpu_session::State_access_failed();
}
Thread_state Platform_thread::state()
{
Thread_state s;
2011-12-22 16:19:25 +01:00
L4_Word_t dummy;
L4_ThreadId_t dummy_tid;
L4_Word_t ip, sp;
enum {
DELIVER = 1 << 9,
};
L4_ExchangeRegisters(_l4_thread_id,
DELIVER,
0, 0, 0, 0, L4_nilthread,
&dummy, &sp, &ip, &dummy, &dummy,
&dummy_tid);
s.ip = ip;
s.sp = sp;
return s;
2011-12-22 16:19:25 +01:00
}
void Platform_thread::cancel_blocking()
{
L4_Word_t dummy;
L4_ThreadId_t dummy_tid;
/*
* XXX: This implementation is not safe because it only cancels
* a currently executed blocking operation but it has no
* effect when the thread is executing user code and going
* to block soon. To solve this issue, we would need signalling
* semantics, which means that we flag the thread to being
* canceled the next time it enters the kernel.
*/
/* control flags for 'L4_ExchangeRegisters' */
enum {
CANCEL_SEND = 1 << 2,
CANCEL_RECV = 1 << 1,
CANCEL_IPC = CANCEL_SEND | CANCEL_RECV,
USER_DEFINED_HANDLE = 1 << 6,
RESUME = 1 << 8,
};
/* reset value for the thread's user-defined handle */
enum { USER_DEFINED_HANDLE_ZERO = 0 };
L4_ExchangeRegisters(_l4_thread_id,
CANCEL_IPC | RESUME | USER_DEFINED_HANDLE,
0, 0, 0, USER_DEFINED_HANDLE_ZERO, L4_nilthread,
&dummy, &dummy, &dummy, &dummy, &dummy,
&dummy_tid);
}
Weak_ptr<Address_space> Platform_thread::address_space()
{
return _platform_pd->Address_space::weak_ptr();
}
thread API & CPU session: accounting of CPU quota In the init configuration one can configure the donation of CPU time via 'resource' tags that have the attribute 'name' set to "CPU" and the attribute 'quantum' set to the percentage of CPU quota that init shall donate. The pattern is the same as when donating RAM quota. ! <start name="test"> ! <resource name="CPU" quantum="75"/> ! </start> This would cause init to try donating 75% of its CPU quota to the child "test". Init and core do not preserve CPU quota for their own requirements by default as it is done with RAM quota. The CPU quota that a process owns can be applied through the thread constructor. The constructor has been enhanced by an argument that indicates the percentage of the programs CPU quota that shall be granted to the new thread. So 'Thread(33, "test")' would cause the backing CPU session to try to grant 33% of the programs CPU quota to the thread "test". By now, the CPU quota of a thread can't be altered after construction. Constructing a thread with CPU quota 0 doesn't mean the thread gets never scheduled but that the thread has no guaranty to receive CPU time. Such threads have to live with excess CPU time. Threads that already existed in the official repositories of Genode were adapted in the way that they receive a quota of 0. This commit also provides a run test 'cpu_quota' in base-hw (the only kernel that applies the CPU-quota scheme currently). The test basically runs three threads with different physical CPU quota. The threads simply count for 30 seconds each and the test then checks wether the counter values relate to the CPU-quota distribution. fix #1275
2014-10-16 11:15:46 +02:00
Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
addr_t, int id)
2011-12-22 16:19:25 +01:00
: _thread_id(id), _l4_thread_id(L4_nilthread), _priority(prio), _pager(0)
{
strncpy(_name, name, sizeof(_name));
}
Platform_thread::~Platform_thread()
{
/*
* We inform our protection domain about thread destruction, which will end up in
* Thread::unbind()
*/
if (_platform_pd)
_platform_pd->unbind_thread(this);
}