aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/executor.cc4
-rw-r--r--lib/executor.h16
-rw-r--r--lib/thread.cc8
-rw-r--r--lib/thread.h49
4 files changed, 64 insertions, 13 deletions
diff --git a/lib/executor.cc b/lib/executor.cc
index 3d3c044..774354f 100644
--- a/lib/executor.cc
+++ b/lib/executor.cc
@@ -5,6 +5,10 @@
#include "arch.h"
namespace nMatcha {
+ const void* Executor::getStackPtr() const {
+ return mStackPtr;
+ }
+
void Executor::spawn(std::unique_ptr<Thread> t) {
mThreads.push_front(std::move(t));
mThreads.front()->mExecutor = this;
diff --git a/lib/executor.h b/lib/executor.h
index f04f3f1..0f2eca9 100644
--- a/lib/executor.h
+++ b/lib/executor.h
@@ -8,16 +8,26 @@
#include <memory>
namespace nMatcha {
+ // Cooperative user thread scheduler.
+ //
+ // The executor is responsible to schedule the next user thread after one
+ // thread yielded, as long as there are user threads that didn't finish.
+ //
+ // When a `Thread` instance is spawned on an `Executor`, its ownership is
+ // transfered to the executor.
+ //
struct Executor {
Executor(const Executor&) = delete;
Executor& operator=(const Executor&) = delete;
Executor() = default;
- const void* getStackPtr() const {
- return mStackPtr;
- }
+ const void* getStackPtr() const;
+ // Spawn an user thread on the executor.
void spawn(std::unique_ptr<Thread> t);
+
+ // Run the executor until all user threads are finished.
+ // This example executor implements round robin scheduling.
void run();
private:
diff --git a/lib/thread.cc b/lib/thread.cc
index ed2dee3..424041d 100644
--- a/lib/thread.cc
+++ b/lib/thread.cc
@@ -41,8 +41,12 @@ namespace nMatcha {
mStackPtr = init_stack(mStackPtr, Thread::entry, static_cast<void*>(this));
}
- void Thread::entry(void* obj) {
- Thread* t = static_cast<Thread*>(obj);
+ bool Thread::isFinished() const {
+ return mFinished;
+ }
+
+ void Thread::entry(void* ctx) {
+ Thread* t = static_cast<Thread*>(ctx);
try {
t->threadFn();
} catch (const std::exception& e) {
diff --git a/lib/thread.h b/lib/thread.h
index c181425..3dfa457 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -8,23 +8,42 @@
namespace nMatcha {
struct Executor;
+ // An abstract base class for implementing cooperative user threads.
+ //
+ // # Usage
+ //
+ // To implement a cooperative user thread following interface invoked by
+ // the Executor must be implemented:
+ // virtual void threadFn() = 0;
+ // By calling `yield()` a thread can give control back to the executor.
+ //
+ // # Example
+ //
+ // ```cpp
+ // class MyThread : public nMatcha::Thread {
+ // virtual void threadFn() override {
+ // puts("Hello");
+ // yield();
+ // puts("World");
+ // }
+ // };
+ // ```
+ //
struct Thread {
Thread(const Thread&) = delete;
Thread& operator=(const Thread&) = delete;
Thread();
virtual ~Thread() {}
- virtual void threadFn() = 0;
-
- bool isFinished() const {
- return mFinished;
- }
+ bool isFinished() const;
protected:
void yield();
private:
- static void entry(void* obj);
+ virtual void threadFn() = 0;
+
+ static void entry(void* ctx);
void* mStackPtr;
bool mFinished;
@@ -32,20 +51,34 @@ namespace nMatcha {
const Executor* mExecutor;
};
+ // Helper interface to implement yielding for function objects.
struct Yielder {
virtual void yield() = 0;
};
+ // Utility class to create cooperative user threads from function objects.
+ //
+ // # Example
+ //
+ // ```cpp
+ // auto t = nMatcha::FnThread::make([](nMatcha::Yielder& y) {
+ // puts("Hello");
+ // y.yield();
+ // puts("World");
+ // });
+ // ```
+ //
struct FnThread : public Thread, public Yielder {
using UserFn = std::function<void(Yielder&)>;
+
+ // Factory method to create `FnThread` objects.
static std::unique_ptr<Thread> make(UserFn f);
private:
+ UserFn mUserFn;
virtual void threadFn() override;
virtual void yield() override;
- UserFn mUserFn;
-
enum class CreatorToken {};
public: