309 lines
6.2 KiB
C++
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();
|
|
}
|