genode/repos/os/src/lib/dde_kit/thread.cc

309 lines
6.2 KiB
C++

/*
* \brief Thread facility
* \author Christian Helmuth
* \date 2008-10-20
*
*/
/*
* Copyright (C) 2008-2013 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.
*/
#include <base/env.h>
#include <base/sleep.h>
#include <base/lock.h>
#include <base/printf.h>
extern "C" {
#include <dde_kit/thread.h>
#include <dde_kit/timer.h>
}
#include "thread.h"
using namespace Genode;
/***********+**************
** Thread info database **
**************************/
class Thread_info_database : public Avl_tree<Dde_kit::Thread_info>
{
private:
Lock _lock;
public:
Dde_kit::Thread_info *lookup(Thread_base *thread_base)
{
Lock::Guard lock_guard(_lock);
if (!first()) throw Dde_kit::Thread_info::Not_found();
return first()->lookup(thread_base);
}
void insert(Dde_kit::Thread_info *info)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Dde_kit::Thread_info>::insert(info);
}
void remove(Dde_kit::Thread_info *info)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Dde_kit::Thread_info>::remove(info);
}
};
static Thread_info_database *threads()
{
static Thread_info_database _threads;
return &_threads;
}
/********************************
** Generic thread information **
********************************/
unsigned Dde_kit::Thread_info::_id_counter = 0x1000;
bool Dde_kit::Thread_info::higher(Thread_info *info)
{
return (info->_thread_base >= _thread_base);
}
Dde_kit::Thread_info *Dde_kit::Thread_info::lookup(Thread_base *thread_base)
{
Dde_kit::Thread_info *info = this;
do {
if (thread_base == info->_thread_base) return info;
if (thread_base < info->_thread_base)
info = info->child(LEFT);
else
info = info->child(RIGHT);
} while (info);
/* thread not in AVL tree */
throw Not_found();
}
Dde_kit::Thread_info::Thread_info(Thread_base *thread_base, const char *name)
: _thread_base(thread_base), _name(name), _id(_id_counter++)
{ }
Dde_kit::Thread_info::~Thread_info()
{ }
/********************
** DDE Kit thread **
********************/
static Dde_kit::Thread_info *adopt_thread(Thread_base *thread, const char *name)
{
Dde_kit::Thread_info *info = 0;
try {
info = new (env()->heap()) Dde_kit::Thread_info(thread, name);
threads()->insert(info);
} catch (...) {
PERR("thread adoption failed");
return 0;
}
return info;
}
struct dde_kit_thread : public Dde_kit::Thread_info
{
/**
* Dummy constructor
*
* This constructor is never executed because we only use pointers to
* 'dde_kit_thread'. Even though, this constructor is never used, gcc-3.4
* (e.g., used for OKL4v2) would report an error if it did not exist.
*/
dde_kit_thread() : Dde_kit::Thread_info(0, 0) { }
};
class _Thread : public Dde_kit::Thread
{
private:
void (*_thread_fn)(void *);
void *_thread_arg;
Dde_kit::Thread_info *_thread_info;
public:
_Thread(const char *name, void (*thread_fn)(void *), void *thread_arg)
:
Dde_kit::Thread(name),
_thread_fn(thread_fn), _thread_arg(thread_arg),
_thread_info(adopt_thread(this, name))
{ start(); }
void entry() { _thread_fn(_thread_arg); }
Dde_kit::Thread_info *thread_info() { return _thread_info; }
};
extern "C" struct dde_kit_thread *dde_kit_thread_create(void (*fun)(void *),
void *arg, const char *name)
{
_Thread *thread;
try {
thread = new (env()->heap()) _Thread(name, fun, arg);
} catch (...) {
PERR("thread creation failed");
return 0;
}
return static_cast<struct dde_kit_thread *>(thread->thread_info());
}
extern "C" struct dde_kit_thread *dde_kit_thread_adopt_myself(const char *name)
{
try {
return static_cast<dde_kit_thread *>(adopt_thread(Thread_base::myself(), name));
} catch (...) {
PERR("thread adoption failed");
return 0;
}
}
extern "C" struct dde_kit_thread *dde_kit_thread_myself()
{
try {
return static_cast<struct dde_kit_thread *>
(threads()->lookup(Thread_base::myself()));
} catch (...) {
return 0;
}
}
extern "C" void * dde_kit_thread_get_data(struct dde_kit_thread *thread) {
return static_cast<Dde_kit::Thread_info *>(thread)->data(); }
extern "C" void * dde_kit_thread_get_my_data(void)
{
try {
return (threads()->lookup(Thread_base::myself()))->data();
} catch (...) {
PERR("current thread not in database");
return 0;
}
}
extern "C" void dde_kit_thread_set_data(struct dde_kit_thread *thread, void *data) {
reinterpret_cast<Dde_kit::Thread_info *>(thread)->data(data); }
extern "C" void dde_kit_thread_set_my_data(void *data)
{
try {
(threads()->lookup(Thread_base::myself()))->data(data);
} catch (...) {
PERR("current thread not in database");
}
}
extern "C" void dde_kit_thread_exit(void)
{
PERR("not implemented yet");
sleep_forever();
}
extern "C" const char *dde_kit_thread_get_name(struct dde_kit_thread *thread) {
return reinterpret_cast<Dde_kit::Thread_info *>(thread)->name(); }
extern "C" int dde_kit_thread_get_id(struct dde_kit_thread *thread) {
return reinterpret_cast<Dde_kit::Thread_info *>(thread)->id(); }
extern "C" void dde_kit_thread_schedule(void)
{
/* FIXME */
}
/*********************
** Sleep interface **
*********************/
static void _wake_up_msleep(void *lock)
{
reinterpret_cast<Lock *>(lock)->unlock();
}
extern "C" void dde_kit_thread_msleep(unsigned long msecs)
{
/*
* This simple msleep() registers a timer that fires after 'msecs' and
* blocks on 'lock'. The registered timer handler just unlocks 'lock' and
* the sleeping thread unblocks.
*/
Lock *lock;
struct dde_kit_timer *timer;
unsigned long timeout = dde_kit_timer_ticks + (msecs * DDE_KIT_HZ) / 1000;
lock = new (env()->heap()) Lock(Lock::LOCKED);
timer = dde_kit_timer_add(_wake_up_msleep, lock, timeout);
lock->lock();
dde_kit_timer_del(timer);
destroy((env()->heap()), lock);
}
extern "C" void dde_kit_thread_usleep(unsigned long usecs)
{
unsigned long msecs = usecs / 1000;
if (msecs > 1)
dde_kit_thread_msleep(msecs);
else
dde_kit_thread_schedule();
}
extern "C" void dde_kit_thread_nsleep(unsigned long nsecs)
{
unsigned long msecs = nsecs / 1000000;
if (msecs > 1)
dde_kit_thread_msleep(msecs);
else
dde_kit_thread_schedule();
}