/* * \brief Signal context for completions and events * \author Sebastian Sumpf * \date 2012-05-23 */ /* * Copyright (C) 2012-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 #include static Signal_helper *_signal = 0; /** * Context for events */ class Event_context { private: Genode::Signal_dispatcher _dispatcher; void _handle(unsigned) { Routine::schedule_all(); } Event_context() : _dispatcher(*_signal->receiver(), *this, &Event_context::_handle) { _signal->sender()->context(_dispatcher); } public: static Event_context *e() { static Event_context _e; return &_e; } void submit() { _signal->sender()->submit(); } char const *debug() { return "Event_context"; } }; void Event::init(Genode::Signal_receiver *recv) { _signal = new (Genode::env()->heap()) Signal_helper(recv); } /** * Delayed work */ class Work : public Genode::List::Element { private: void *_work; bool _delayed; static Genode::List *_list() { static Genode::List _l; return &_l; } public: Work(void *work, bool delayed) : _work(work), _delayed(delayed) { } static void schedule(void *work, bool delayed) { Work *w = new (Genode::env()->heap()) Work(work, delayed); _list()->insert(w); } static void exec() { while (_list()->first()) { Work *w = _list()->first(); _list()->remove(w); if (w->_delayed) { delayed_work *work = static_cast(w->_work); work->work.func(&(work)->work); } else { work_struct *work = static_cast(w->_work); work->func(work); } destroy(Genode::env()->heap(), w); } } }; /************************ ** linux/completion.h ** ************************/ void __wake_up() { Routine::schedule_all(); } void __wait_event() { /* schedule work first */ Work::exec(); /* schedule other routines or wait for signals */ Service_handler::s()->process(); } void init_completion(struct completion *work) { dde_kit_log(DEBUG_COMPLETION, "New completion %p", work); work->done = 0; } void complete(struct completion *work) { dde_kit_log(DEBUG_COMPLETION, "%p", work); work->done = 1; /* send signal */ Event_context::e()->submit(); } void complete_and_exit(struct completion *work, long code) { dde_kit_log(DEBUG_COMPLETION, "%p", work); complete(work); Routine::remove(); } static void __wait_completion(struct completion *work) { while (!work->done) __wait_event(); work->done = 0; } static unsigned long __wait_completion_timeout(struct completion *work, unsigned long timeout) { unsigned long _j = jiffies + (timeout / HZ); while (!work->done) { __wait_event(); if (_j >= jiffies) return 0; } work->done = 0; return _j - jiffies; } unsigned long wait_for_completion_timeout(struct completion *work, unsigned long timeout) { dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); __wait_completion(work); return 1; } int wait_for_completion_interruptible(struct completion *work) { dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); __wait_completion(work); return 0; } long wait_for_completion_interruptible_timeout(struct completion *work, unsigned long timeout) { dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); __wait_completion(work); return 1; } void wait_for_completion(struct completion *work) { dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); __wait_completion(work); } /******************* ** linux/timer.h ** *******************/ signed long schedule_timeout_uninterruptible(signed long timeout) { dde_kit_log(DEBUG_COMPLETION, "%ld\n", timeout); __wait_event(); return 0; } int wake_up_process(struct task_struct *tsk) { Routine::schedule_all(); return 0; } /*********************** ** linux/workquque.h ** ***********************/ int schedule_delayed_work(struct delayed_work *work, unsigned long delay) { Work::schedule((void *)work, true); //work->work.func(&(work)->work); return 0; } int schedule_work(struct work_struct *work) { Work::schedule((void *)work, false); return 1; } bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay) { Work::schedule((void *)dwork, true); return true; }