diff --git a/src/framework/core/eventdispatcher.cpp b/src/framework/core/eventdispatcher.cpp index 9417ac41..5da923e4 100644 --- a/src/framework/core/eventdispatcher.cpp +++ b/src/framework/core/eventdispatcher.cpp @@ -75,6 +75,16 @@ void EventDispatcher::poll() } m_pollEventsSize = m_eventList.size(); } + + for(auto it = m_coroutines.begin(); it != m_coroutines.end();) { + stdext::coroutine& coroutine = (*it); + if(coroutine.is_finished()) + it = m_coroutines.erase(it); + else { + coroutine.resume(); + ++it; + } + } } ScheduledEventPtr EventDispatcher::scheduleEvent(const std::function& callback, int delay) @@ -114,3 +124,8 @@ EventPtr EventDispatcher::addEvent(const std::function& callback, bool p m_eventList.push_back(event); return event; } + +void EventDispatcher::addCoroutine(const stdext::coroutine& coroutine) +{ + m_coroutines.push_back(coroutine); +} diff --git a/src/framework/core/eventdispatcher.h b/src/framework/core/eventdispatcher.h index 16d6209a..bb1c46ab 100644 --- a/src/framework/core/eventdispatcher.h +++ b/src/framework/core/eventdispatcher.h @@ -27,6 +27,7 @@ #include "scheduledevent.h" #include +#include // @bindsingleton g_dispatcher class EventDispatcher @@ -35,6 +36,7 @@ public: void shutdown(); void poll(); + void addCoroutine(const stdext::coroutine& coroutine); EventPtr addEvent(const std::function& callback, bool pushFront = false); ScheduledEventPtr scheduleEvent(const std::function& callback, int delay); ScheduledEventPtr cycleEvent(const std::function& callback, int delay); @@ -44,6 +46,7 @@ private: int m_pollEventsSize; stdext::boolean m_disabled; std::priority_queue, lessScheduledEvent> m_scheduledEventList; + std::list m_coroutines; }; extern EventDispatcher g_dispatcher; diff --git a/src/framework/stdext/coroutine.h b/src/framework/stdext/coroutine.h new file mode 100644 index 00000000..b48ed41b --- /dev/null +++ b/src/framework/stdext/coroutine.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef COROUTINE_H +#define COROUTINE_H + +#include +#include +#include +#include +#include + +namespace stdext { + +// +class coroutine +{ + struct codata : public stdext::shared_object { + std::unique_ptr thread; + std::condition_variable conditionVar; + std::mutex mutex; + std::function func; + }; + + stdext::shared_object_ptr m; + + void run() { + assert(m->func); + m->func(); + std::lock_guard lock(m->mutex); + m->func = nullptr; + m->conditionVar.notify_all(); + } + +public: + coroutine() : m(stdext::make_shared_object()) { } + coroutine(const coroutine& other) : m(other.m) { } + + coroutine& operator=(const coroutine& other) { m = other.m; return *this; } + + ~coroutine() { + if(m.is_unique()) { + m->conditionVar.notify_all(); + m->thread->join(); + assert(!m->func); + } + } + + void create(const std::function& func) { + assert(!!func && !m->func); + m->func = func; + } + + void yield() const { + std::unique_lock lock(m->mutex); + m->conditionVar.notify_all(); + m->conditionVar.wait(lock); + } + + void resume() { + if(!m->thread) { + std::unique_lock lock(m->mutex); + m->thread.reset(new std::thread(std::bind(&coroutine::run, this))); + m->conditionVar.wait(lock); // wait for the thread to start + } else { + std::unique_lock lock(m->mutex); + assert(m->func); + m->conditionVar.notify_all(); + m->conditionVar.wait(lock); + } + } + + void join() { + while(!is_finished()) + resume(); + } + + bool is_suspended() { return !!m->func; } + bool is_finished() { return !m->func; } +}; + +}; + +#endif