PageRenderTime 137ms CodeModel.GetById 117ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/coroutine.h

http://github.com/mozy/mordor
C Header | 236 lines | 197 code | 38 blank | 1 comment | 6 complexity | 827e99e6a3d61ddadf719fa65060ddec MD5 | raw file
  1#ifndef __MORDOR_COROUTINE_H__
  2#define __MORDOR_COROUTINE_H__
  3// Copyright (c) 2009 - Mozy, Inc.
  4
  5#include <boost/bind.hpp>
  6#include <boost/function.hpp>
  7#include <boost/noncopyable.hpp>
  8
  9#include "exception.h"
 10#include "fiber.h"
 11
 12namespace Mordor {
 13
 14struct DummyVoid;
 15
 16struct CoroutineAbortedException : virtual OperationAbortedException {};
 17
 18template <class Result, class Arg = DummyVoid>
 19class Coroutine : boost::noncopyable
 20{
 21public:
 22    Coroutine()
 23    {
 24        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
 25    }
 26
 27    Coroutine(boost::function<void (Coroutine &, Arg)> dg)
 28        : m_dg(dg)
 29    {
 30        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
 31    }
 32
 33    ~Coroutine()
 34    {
 35        reset();
 36    }
 37
 38    void reset()
 39    {
 40        if (m_fiber->state() == Fiber::HOLD) {
 41            try {
 42                throw boost::enable_current_exception(CoroutineAbortedException());
 43            } catch (...) {
 44                m_fiber->inject(boost::current_exception());
 45            }
 46        }
 47        m_fiber->reset(boost::bind(&Coroutine::run, this));
 48    }
 49
 50    void reset(boost::function<void (Coroutine &, Arg)> dg)
 51    {
 52        reset();
 53        m_dg = dg;
 54    }
 55
 56    Result call(const Arg &arg)
 57    {
 58        m_arg = arg;
 59        m_fiber->call();
 60        return m_result;
 61    }
 62
 63    Arg yield(const Result &result)
 64    {
 65        m_result = result;
 66        Fiber::yield();
 67        return m_arg;
 68    }
 69
 70    Fiber::State state() const
 71    {
 72        return m_fiber->state();
 73    }
 74
 75private:
 76    void run()
 77    {
 78        try {
 79            m_dg(*this, m_arg);
 80            m_result = Result();
 81        } catch (CoroutineAbortedException &) {
 82        }
 83    }
 84
 85private:
 86    boost::function<void (Coroutine &, Arg)> m_dg;
 87    Result m_result;
 88    Arg m_arg;
 89    Fiber::ptr m_fiber;
 90};
 91
 92
 93template <class Result>
 94class Coroutine<Result, DummyVoid> : boost::noncopyable
 95{
 96public:
 97    Coroutine()
 98    {
 99        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
100    }
101
102    Coroutine(boost::function<void (Coroutine &)> dg)
103        : m_dg(dg)
104    {
105        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
106    }
107
108    ~Coroutine()
109    {
110        reset();
111    }
112
113    void reset()
114    {
115        if (m_fiber->state() == Fiber::HOLD) {
116            try {
117                throw boost::enable_current_exception(CoroutineAbortedException());
118            } catch (...) {
119                m_fiber->inject(boost::current_exception());
120            }
121        }
122        m_fiber->reset(boost::bind(&Coroutine::run, this));
123    }
124
125    void reset(boost::function<void (Coroutine &)> dg)
126    {
127        reset();
128        m_dg = dg;
129    }
130
131    Result call()
132    {
133        m_fiber->call();
134        return m_result;
135    }
136
137    void yield(const Result &result)
138    {
139        m_result = result;
140        Fiber::yield();
141    }
142
143    Fiber::State state() const
144    {
145        return m_fiber->state();
146    }
147
148private:
149    void run()
150    {
151        try {
152            m_dg(*this);
153            m_result = Result();
154        } catch (CoroutineAbortedException &) {
155        }
156    }
157
158private:
159    boost::function<void (Coroutine &)> m_dg;
160    Result m_result;
161    Fiber::ptr m_fiber;
162};
163
164template <class Arg>
165class Coroutine<void, Arg> : boost::noncopyable
166{
167public:
168    Coroutine()
169    {
170        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
171    }
172
173    Coroutine(boost::function<void (Coroutine &, Arg)> dg)
174        : m_dg(dg)
175    {
176        m_fiber = Fiber::ptr(new Fiber(boost::bind(&Coroutine::run, this)));
177    }
178
179    ~Coroutine()
180    {
181        reset();
182    }
183
184    void reset()
185    {
186        if (m_fiber->state() == Fiber::HOLD) {
187            try {
188                throw boost::enable_current_exception(CoroutineAbortedException());
189            } catch (...) {
190                m_fiber->inject(boost::current_exception());
191            }
192        }
193        m_fiber->reset(boost::bind(&Coroutine::run, this));
194    }
195
196    void reset(boost::function<void (Coroutine &, Arg)> dg)
197    {
198        reset();
199        m_dg = dg;
200    }
201
202    void call(const Arg &arg)
203    {
204        m_arg = arg;
205        m_fiber->call();
206    }
207
208    Arg yield()
209    {
210        Fiber::yield();
211        return m_arg;
212    }
213
214    Fiber::State state() const
215    {
216        return m_fiber->state();
217    }
218
219private:
220    void run()
221    {
222        try {
223            m_dg(*this, m_arg);
224        } catch (CoroutineAbortedException &) {
225        }
226    }
227
228private:
229    boost::function<void (Coroutine &, Arg)> m_dg;
230    Arg m_arg;
231    Fiber::ptr m_fiber;
232};
233
234}
235
236#endif