00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef ACEDIA_ACTOR_H_
00031 #define ACEDIA_ACTOR_H_
00032
00033 #ifndef _XOPEN_SOURCE
00034 # define _XOPEN_SOURCE
00035 #endif
00036
00037 #include <boost/thread.hpp>
00038 #include <boost/thread/mutex.hpp>
00039 #include <boost/static_assert.hpp>
00040 #include <boost/thread/condition_variable.hpp>
00041
00042 #include "any.hpp"
00043 #include "acedia_atomic.hpp"
00044 #include "acedia.hpp"
00045 #include "context.hpp"
00046 #include "invoker.hpp"
00047 #include "actorref.hpp"
00048 #include "abstractactor.hpp"
00049 #include "tuple.hpp"
00050
00051 #include "acedia_util.hpp"
00052 #include "acedia_details.hpp"
00053
00054 namespace acedia
00055 {
00056
00060 typedef boost::int32_t ActorState;
00061
00067 static const boost::int32_t UNINITIALIZED = 0x01;
00068
00074 static const boost::int32_t READY = 0x02;
00075
00082 static const boost::int32_t BLOCKED = 0x04;
00083
00090 static const boost::int32_t WAITING = 0x08;
00091
00097 static const boost::int32_t RUNNING = 0x10;
00098
00105 static const boost::int32_t DETACHED = 0x20;
00106
00112 static const boost::int32_t HIDDEN = 0x40;
00113
00114
00121 static const boost::int32_t EXITED = 0x80;
00122
00126 class Actor : public AbstractActor
00127 {
00128 friend class ActorRef;
00129 friend ActorRef details::doSpawn(Actor*);
00130 friend struct Worker;
00131
00132 static void trampoline(Actor *_this);
00133
00134 #if defined(ACEDIA_UCONTEXT_IMPL)
00135
00136
00137 BOOST_STATIC_ASSERT(sizeof(Actor*) == sizeof(int));
00138
00139
00140 static void ucontext_trampoline(int _this);
00141 #elif defined(ACEDIA_FIBER_IMPL)
00142 static void fiber_trampoline(PVOID *_this);
00143 #endif
00144
00145
00146 void executeActor();
00147
00148
00149 volatile ActorState m_state;
00150
00151 Context *m_context;
00152
00153 volatile Context *m_returnContext;
00154
00155
00156 util::RWSpinlock m_mailboxLock;
00157
00158 util::Spinlock m_receptionistLock;
00159
00160 details::container::SingleReaderList<Message> m_mailbox;
00161
00162
00163
00164 volatile Invoker* m_receptionist;
00165 volatile Invoker* m_timeoutReceptionist;
00166
00167
00168 volatile acedia::details::ContinuationInvoker *m_continuationInvoker;
00169
00170 Message m_lrm;
00171
00172 bool m_trapExit;
00173
00174
00175 std::list<ActorRef> m_links;
00176
00177 boost::mutex m_linksMutex;
00178
00179
00180 volatile bool m_lrmSet;
00181 boost::condition_variable m_lrmSetCondition;
00182
00183 void setLrm(const Message &msg);
00184
00185
00186 boost::int32_t m_timeoutRequestId;
00187
00188 protected:
00189
00198 bool filterTimeoutEvents(const Message &msg);
00199
00211 virtual bool filterIncomingMessage(const Message &msg);
00212
00216 void doExit(boost::int32_t reason);
00217
00221 void normalExit();
00222
00228 inline Message lastReceivedMessage() const { return m_lrm; }
00229
00235 inline void forwardLastReceivedMessage(ActorRef &whom) const
00236 {
00237 whom.send(m_lrm);
00238 }
00239
00243 virtual void act() = 0;
00244
00257 virtual void onExit();
00258
00267 void yield(ActorState mYieldState = READY);
00268
00273 void receiveAndInvoke(Invoker &imp);
00274
00278 template<class CaseClass>
00279 void waitFor()
00280 {
00281 Invoker inv;
00282 inv.add(on<CaseClass>() >> discard);
00283 receiveAndInvoke(inv);
00284 }
00285
00295 bool tryReceiveAndInvoke(Invoker &imp);
00296
00303 bool receiveAndInvokeWithin(Invoker &imp, boost::uint16_t msTimeout);
00304
00308 Message receive();
00309
00316 bool tryReceive(Message &storage);
00317
00324 bool receiveWithin(Message &storage, boost::uint16_t msTimeout);
00325
00331 void reply(const Any &val1);
00332
00333 void reply(const acedia::Any &val1, const acedia::Any &val2);
00334
00342 template<class A>
00343 ActorRef spawn_link()
00344 {
00345 ActorRef actor = spawn<A>();
00346 linkTo(actor);
00347 return actor;
00348 }
00349
00350 template<class A, typename T1>
00351 ActorRef spawn_link(const T1 &v1)
00352 {
00353 ActorRef actor = spawn<A>(v1);
00354 linkTo(actor);
00355 return actor;
00356 }
00357
00358 template<class A, typename T1, typename T2>
00359 ActorRef spawn_link(const T1 &v1, const T2 &v2)
00360 {
00361 ActorRef actor = spawn<A>(v1,v2);
00362 linkTo(actor);
00363 return actor;
00364 }
00365
00366 template<class A, typename T1, typename T2, typename T3>
00367 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3)
00368 {
00369 ActorRef actor = spawn<A>(v1,v2,v3);
00370 linkTo(actor);
00371 return actor;
00372 }
00373
00374 template<class A, typename T1, typename T2, typename T3, typename T4>
00375 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00376 const T1 &v4)
00377 {
00378 ActorRef actor = spawn<A>(v1,v2,v3,v4);
00379 linkTo(actor);
00380 return actor;
00381 }
00382
00383 template<class A, typename T1, typename T2, typename T3, typename T4,
00384 typename T5>
00385 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00386 const T1 &v4, const T2 &v5)
00387 {
00388 ActorRef actor = spawn<A>(v1,v2,v3,v4,v5);
00389 linkTo(actor);
00390 return actor;
00391 }
00392
00393 template<class A, typename T1, typename T2, typename T3, typename T4,
00394 typename T5, typename T6>
00395 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00396 const T1 &v4, const T2 &v5, const T3 &v6)
00397 {
00398 ActorRef actor = spawn<A>(v1,v2,v3,v4,v5,v6);
00399 linkTo(actor);
00400 return actor;
00401 }
00402
00403 template<class A, typename T1, typename T2, typename T3, typename T4,
00404 typename T5, typename T6, typename T7>
00405 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00406 const T1 &v4, const T2 &v5, const T3 &v6,
00407 const T1 &v7)
00408 {
00409 ActorRef actor = spawn<A>(v1,v2,v3,v4,v5,v6,v7);
00410 linkTo(actor);
00411 return actor;
00412 }
00413
00414 template<class A, typename T1, typename T2, typename T3, typename T4,
00415 typename T5, typename T6, typename T7, typename T8>
00416 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00417 const T1 &v4, const T2 &v5, const T3 &v6,
00418 const T1 &v7, const T2 &v8)
00419 {
00420 ActorRef actor = spawn<A>(v1,v2,v3,v4,v5,v6,v7,v8);
00421 linkTo(actor);
00422 return actor;
00423 }
00424
00425 template<class A, typename T1, typename T2, typename T3, typename T4,
00426 typename T5, typename T6, typename T7, typename T8, typename T9>
00427 ActorRef spawn_link(const T1 &v1, const T2 &v2, const T3 &v3,
00428 const T1 &v4, const T2 &v5, const T3 &v6,
00429 const T1 &v7, const T2 &v8, const T3 &v9)
00430 {
00431 ActorRef actor = spawn<A>(v1,v2,v3,v4,v5,v6,v7,v8,v9);
00432 linkTo(actor);
00433 return actor;
00434 }
00435
00439 void futureMessage(boost::uint32_t msTimeout, const Any& v1);
00440
00441 void futureMessage(boost::uint32_t msTimeout,
00442 const Any& v1, const Any& v2);
00443
00444 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00445 const Any& v2, const Any& v3);
00446
00447 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00448 const Any& v2, const Any& v3, const Any& v4);
00449
00450 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00451 const Any& v2, const Any& v3, const Any& v4,
00452 const Any& v5);
00453
00454 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00455 const Any& v2, const Any& v3, const Any& v4,
00456 const Any& v5, const Any& v6);
00457
00458 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00459 const Any& v2, const Any& v3, const Any& v4,
00460 const Any& v5, const Any& v6, const Any& v7);
00461
00462 void futureMessage(boost::uint32_t msTimeout, const Any& v1,
00463 const Any& v2, const Any& v3, const Any& v4,
00464 const Any& v5, const Any& v6, const Any& v7,
00465 const Any& v8);
00466
00467 public:
00468
00469 Actor *next;
00470
00474 inline const volatile ActorState &state() const { return m_state; }
00475
00476 String stateAsString() const;
00477
00478
00479
00480
00481
00482
00483
00484
00485 volatile ActorState *yieldState;
00486
00498 bool setState(ActorState oldState, ActorState nextState);
00499
00509 Actor(ActorState initialState = UNINITIALIZED, bool trapExit = false);
00510
00511 void initialize();
00512
00513 virtual ~Actor();
00514
00519 void resume(Context *schedulerCtx);
00520
00524 inline bool isBlocked() const { return m_state == BLOCKED; }
00525
00529 inline bool isDetached() const
00530 {
00531 return 0 != (m_state & (DETACHED | HIDDEN));
00532 }
00533
00534 virtual bool backlinkTo(ActorRef &who);
00535
00536 virtual void linkTo(const ActorRef &who);
00537
00538 virtual void enqueue(const Message &msg);
00539
00540 };
00541
00542 }
00543
00544 namespace acedia
00545 {
00552 struct Exit;
00553
00565 struct AddRemoteLink;
00566 }
00567
00568 ACEDIA_DECLARE_CASE_TUPLE1((acedia)(Exit), reason, boost::int32_t)
00569
00570 ACEDIA_DECLARE_CASE_CLASS((acedia)(AddRemoteLink))
00571
00572
00573 ACEDIA_DECLARE_CASE_TUPLE2((acedia)(TimeoutRequest), requestId, boost::int32_t, msTimeout, boost::uint32_t)
00574
00575
00576 ACEDIA_DECLARE_CASE_TUPLE1((acedia)(TimeoutEvent), requestId, boost::int32_t)
00577
00578 ACEDIA_DECLARE_CASE_TUPLE1((acedia)(FutureMessageRequest), msTimeout, boost::uint32_t)
00579
00580 #endif // ACEDIA_ACTOR_H_