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 #include "mockactor.hpp"
00031
00032 #include <boost/thread.hpp>
00033
00034 #include "actor.hpp"
00035
00036 namespace acedia
00037 {
00038 namespace details
00039 {
00040 struct MockActorPrivate : public AbstractActor
00041 {
00042 typedef boost::unique_lock<boost::mutex> ScopedLock;
00043
00044 typedef std::list<Message> Mailbox;
00045 typedef Mailbox::iterator MailboxIterator;
00046
00047 typedef std::list<ActorRef> LinkList;
00048 typedef LinkList::iterator LinkListIterator;
00049
00050 Message m_lrm;
00051
00052 Mailbox m_mailbox;
00053 boost::mutex m_mailboxMutex;
00054 boost::condition_variable m_mailboxCondition;
00055
00056 LinkList m_links;
00057 boost::mutex m_linksMutex;
00058
00059 void doExit(boost::int32_t exitReason)
00060 {
00061 ScopedLock lock(m_linksMutex);
00062 m_exitReason = exitReason;
00063 Any exitTuple = Exit(exitReason);
00064 for (LinkListIterator i = m_links.begin(); i != m_links.end(); ++i)
00065 {
00066 (*i).send(Message(self(), *i, exitTuple));
00067 }
00068 m_links.clear();
00069 }
00070
00071 virtual void enqueue(const Message &msg)
00072 {
00073 boost::mutex::scoped_lock lock(m_mailboxMutex);
00074 m_mailbox.push_back(msg);
00075 m_mailboxCondition.notify_all();
00076 }
00077
00078 bool tryDequeue(Message &msg, bool withTimeout = false, boost::uint16_t msTimeout = 0)
00079 {
00080 ScopedLock lock(m_mailboxMutex);
00081 if (!withTimeout)
00082 {
00083 if (!m_mailbox.empty())
00084 {
00085 msg = m_mailbox.front();
00086 m_mailbox.pop_front();
00087 return true;
00088 }
00089 }
00090 else
00091 {
00092 boost::system_time timeout;
00093 if (withTimeout)
00094 {
00095 timeout = boost::get_system_time();
00096 timeout += boost::posix_time::milliseconds(msTimeout);
00097 }
00098 while (m_mailbox.empty())
00099 {
00100 if (!m_mailboxCondition.timed_wait(lock, timeout))
00101 {
00102 return false;
00103 }
00104 }
00105 msg = m_mailbox.front();
00106 m_mailbox.pop_front();
00107 return true;
00108 }
00109 return false;
00110 }
00111
00112 Message dequeue()
00113 {
00114 ScopedLock lock(m_mailboxMutex);
00115 while (m_mailbox.empty())
00116 {
00117 m_mailboxCondition.wait(lock);
00118 }
00119 Message result = m_mailbox.front();
00120 m_mailbox.pop_front();
00121 return result;
00122 }
00123
00124 bool invoke(Invoker &inv, bool withTimeout = false, boost::uint16_t msTimeout = 0)
00125 {
00126 boost::system_time timeout;
00127 if (withTimeout)
00128 {
00129 timeout = boost::get_system_time();
00130 timeout += boost::posix_time::milliseconds(msTimeout);
00131 }
00132 ScopedLock lock(m_mailboxMutex);
00133 while (m_mailbox.empty())
00134 {
00135 m_mailboxCondition.wait(lock);
00136 }
00137 MailboxIterator i = m_mailbox.begin();
00138 for (;;)
00139 {
00140 if (inv(*i, true))
00141 {
00142
00143 m_mailbox.erase(i);
00144 return true;
00145 }
00146 else
00147 {
00148
00149
00150 MailboxIterator next = i;
00151 ++next;
00152 while (next == m_mailbox.end())
00153 {
00154 if (withTimeout)
00155 {
00156 if (!m_mailboxCondition.timed_wait(lock, timeout))
00157 {
00158 return false;
00159 }
00160 }
00161 else m_mailboxCondition.wait(lock);
00162 next = i;
00163 ++next;
00164 }
00165 }
00166 }
00167 }
00168
00169 bool tryInvoke(Invoker &inv)
00170 {
00171 ScopedLock lock(m_mailboxMutex);
00172 for (MailboxIterator i = m_mailbox.begin(); i != m_mailbox.end(); ++i)
00173 {
00174 if (inv(*i, true))
00175 {
00176 m_mailbox.erase(i);
00177 return true;
00178 }
00179 }
00180 return false;
00181 }
00182
00183 void linkTo(const ActorRef& who)
00184 {
00185 if (who == self()) return;
00186 ScopedLock lock(m_linksMutex);
00187 ActorRef s = self();
00188 if (m_exitReason != exit_reasons::NOT_EXITED)
00189 {
00190 ActorRef receiver = who;
00191 send(receiver, Exit(m_exitReason));
00192 }
00193 else if (who.actor->backlinkTo(s))
00194 {
00195 m_links.push_back(who);
00196 }
00197 }
00198
00199
00200 bool backlinkTo(ActorRef& who)
00201 {
00202 if (who == self()) return false;
00203 else
00204 {
00205 ScopedLock lock(m_linksMutex);
00206 if (m_exitReason != exit_reasons::NOT_EXITED)
00207 {
00208 send(who, Exit(m_exitReason));
00209 }
00210 else m_links.push_back(who);
00211 }
00212 return true;
00213 }
00214 };
00215 }
00216
00217 MockActor::MockActor() : d(new details::MockActorPrivate)
00218 {
00219 m_self = ActorRef(d);
00220 }
00221
00222 MockActor::~MockActor()
00223 {
00224 d->doExit(m_exitReason);
00225 }
00226
00227 void MockActor::setExitReason(boost::int32_t reason)
00228 {
00229 m_exitReason = reason;
00230 }
00231
00232 void MockActor::receiveAndInvoke(Invoker &imp)
00233 {
00234 (void) d->invoke(imp);
00235 }
00236
00237 bool MockActor::tryReceiveAndInvoke(Invoker &imp)
00238 {
00239 return d->tryInvoke(imp);
00240 }
00241
00242 bool MockActor::receiveAndInvokeWithin(Invoker &imp, boost::uint16_t msTimeout)
00243 {
00244 return d->invoke(imp, true, msTimeout);
00245 }
00246
00247 Message MockActor::receive()
00248 {
00249 return d->dequeue();
00250 }
00251
00252 bool MockActor::tryReceive(Message &storage)
00253 {
00254 return d->tryDequeue(storage);
00255 }
00256
00257 bool MockActor::receiveWithin(Message &storage, boost::uint16_t msTimeout)
00258 {
00259 return d->tryDequeue(storage, true, msTimeout);
00260 }
00261
00262 void MockActor::send(ActorRef& receiver, const Any& v1)
00263 {
00264 d->send(receiver,v1);
00265 }
00266
00267 void MockActor::send(ActorRef& receiver, const Any& v1, const Any& v2)
00268 {
00269 d->send(receiver,v1,v2);
00270 }
00271
00272 void MockActor::send(ActorRef& receiver, const Any& v1, const Any& v2,
00273 const Any& v3)
00274 {
00275 d->send(receiver,v1,v2,v3);
00276 }
00277
00278 void MockActor::send(ActorRef& receiver,
00279 const Any& v1, const Any& v2, const Any& v3, const Any& v4)
00280 {
00281 d->send(receiver,v1,v2,v3,v4);
00282 }
00283
00284 void MockActor::send(ActorRef& receiver,
00285 const Any& v1, const Any& v2, const Any& v3, const Any& v4,
00286 const Any& v5)
00287 {
00288 d->send(receiver,v1,v2,v3,v4,v5);
00289 }
00290
00291 void MockActor::send(ActorRef& receiver,
00292 const Any& v1, const Any& v2, const Any& v3, const Any& v4,
00293 const Any& v5, const Any& v6)
00294 {
00295 d->send(receiver,v1,v2,v3,v4,v5,v6);
00296 }
00297
00298 void MockActor::send(ActorRef& receiver,
00299 const Any& v1, const Any& v2, const Any& v3, const Any& v4,
00300 const Any& v5, const Any& v6, const Any& v7)
00301 {
00302 d->send(receiver,v1,v2,v3,v4,v5,v6,v7);
00303 }
00304
00305 void MockActor::send(ActorRef& receiver,
00306 const Any& v1, const Any& v2, const Any& v3, const Any& v4,
00307 const Any& v5, const Any& v6, const Any& v7, const Any& v8)
00308 {
00309 d->send(receiver,v1,v2,v3,v4,v5,v6,v7,v8);
00310 }
00311
00312 void MockActor::send(ActorRef& receiver,
00313 const Any& v1, const Any& v2, const Any& v3, const Any& v4,
00314 const Any& v5, const Any& v6, const Any& v7, const Any& v8,
00315 const Any& v9)
00316 {
00317 d->send(receiver,v1,v2,v3,v4,v5,v6,v7,v8,v9);
00318 }
00319
00320 }