summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2010-03-12 14:50:40 +0100
committerChristian Kamm <christian.d.kamm@nokia.com>2010-03-26 13:05:02 +0100
commitb03a4b990d9d26f62958cb1968bcf463e6d87eb5 (patch)
tree4b83dc518cfe7ae1c6309ec198934f63e523c762
parentd0264201dd42d7735c41338f78c6065b2f9593bc (diff)
Use thread local storage for active fiber. Don't require inheritance.
-rw-r--r--src/fiber.cpp59
-rw-r--r--src/fiber.h27
2 files changed, 44 insertions, 42 deletions
diff --git a/src/fiber.cpp b/src/fiber.cpp
index 7208ced..1c484e1 100644
--- a/src/fiber.cpp
+++ b/src/fiber.cpp
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <QtCore/QtGlobal>
+#include <QtCore/QThreadStorage>
#include "fiber.h"
@@ -10,23 +11,21 @@
Fibers, also known as coroutines, allow managing multiple stacks in the same
thread.
+ \omit ### outdated \endomit
To create a fiber, subclass Fiber and override the run() method. To run it,
call cont(). This will execute the code in run() until it calls Fiber::yield().
At that point, the call to cont() returns. Subsequent calls to cont() will
continue execution of the fiber just after the yield().
Example:
- class MyFiber : public Fiber
+ void myFiber()
{
- virtual void run()
- {
- qDebug() << "1";
- Fiber::yield();
- qDebug() << "2";
- }
+ qDebug() << "1";
+ Fiber::yield();
+ qDebug() << "2";
}
- MyFiber fib;
+ MyFiber fib(&myFiber);
qDebug() << "0.5";
fib.cont(); // prints 1
qDebug() << "1.5";
@@ -43,10 +42,9 @@ void initializeStack(void *data, int size, void (*entry)(), void **stackPointer)
void switchStack(void* to, void** from) { _switchStackInternal(to, from); }
#endif
-Fiber *Fiber::_currentFiber = 0;
-
-Fiber::Fiber(int stackSize)
- : _stackData(0)
+Fiber::Fiber(StartFunction startFunction, int stackSize)
+ : _startFunction(startFunction)
+ , _stackData(0)
, _stackPointer(0)
, _previousFiber(0)
, _status(NotStarted)
@@ -58,8 +56,9 @@ Fiber::Fiber(int stackSize)
initializeStack(_stackData, stackSize, &entryPoint, &_stackPointer);
}
-Fiber::Fiber(bool)
- : _stackData(0)
+Fiber::Fiber()
+ : _startFunction(0)
+ , _stackData(0)
, _stackPointer(0)
, _previousFiber(0)
, _status(Running)
@@ -72,18 +71,23 @@ Fiber::~Fiber()
free(_stackData);
}
+static QThreadStorage<Fiber *> qt_currentFiber;
+
Fiber *Fiber::currentFiber()
{
+ Fiber *current = qt_currentFiber.localData();
+ if (current)
+ return current;
+
// establish a context for the starting fiber
- if (!_currentFiber)
- _currentFiber = new Fiber(true);
-
- return _currentFiber;
+ current = new Fiber;
+ qt_currentFiber.setLocalData(current);
+ return current;
}
void Fiber::entryPoint()
{
- _currentFiber->run();
+ qt_currentFiber.localData()->_startFunction();
yieldHelper(Terminated);
Q_ASSERT(0); // unreachable
}
@@ -94,9 +98,10 @@ bool Fiber::cont()
Q_ASSERT(_status == NotStarted || _status == Stopped);
Q_ASSERT(!_previousFiber);
- _previousFiber = _currentFiber;
- _currentFiber = this;
_status = Running;
+
+ _previousFiber = qt_currentFiber.localData();
+ qt_currentFiber.setLocalData(this);
switchStack(_stackPointer, &_previousFiber->_stackPointer);
return _status != Terminated;
}
@@ -108,13 +113,15 @@ void Fiber::yield()
void Fiber::yieldHelper(Status stopStatus)
{
- Fiber *stoppingFiber = _currentFiber;
+ Fiber *stoppingFiber = qt_currentFiber.localData();
Q_ASSERT(stoppingFiber);
- Q_ASSERT(stoppingFiber->_previousFiber);
Q_ASSERT(stoppingFiber->_status == Running);
+ stoppingFiber->_status = stopStatus;
+
+ Fiber *continuingFiber = stoppingFiber->_previousFiber;
+ Q_ASSERT(continuingFiber);
- _currentFiber = stoppingFiber->_previousFiber;
stoppingFiber->_previousFiber = 0;
- stoppingFiber->_status = stopStatus;
- switchStack(_currentFiber->_stackPointer, &stoppingFiber->_stackPointer);
+ qt_currentFiber.setLocalData(continuingFiber);
+ switchStack(continuingFiber, &stoppingFiber->_stackPointer);
}
diff --git a/src/fiber.h b/src/fiber.h
index 6afc57d..b7bbcb1 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -4,6 +4,8 @@
class Fiber
{
public:
+ typedef void(*StartFunction)();
+
enum Status
{
NotStarted,
@@ -13,36 +15,29 @@ public:
};
public:
- explicit Fiber(int stackSize = 32768);
- virtual ~Fiber();
+ explicit Fiber(StartFunction startFunction, int stackSize = 32768);
+ ~Fiber();
bool cont();
static void yield();
- static Fiber *currentFiber();
-
Status status()
{ return _status; }
-
-protected:
- // could be abstract if subclassing for start fiber
- virtual void run() {}
-
+
+ static Fiber *currentFiber();
+
private:
// for the original fiber
- Fiber(bool);
+ Fiber();
static void yieldHelper(Status stopStatus);
-
+ static void entryPoint();
+
+ StartFunction _startFunction;
void *_stackData;
void *_stackPointer;
Fiber *_previousFiber;
Status _status;
-
- // should be thread local
- static Fiber *_currentFiber;
-
- static void entryPoint();
};
#endif // INCLUDE_FIBER_H