actor.hpp kernel.hpp cstdint cstddef type_traits utility tk::Message tk::EventHub tk::EventHub::Subscriber tk::Actor tk #pragmaonce #include"kernel.hpp" #include<cstdint> #include<cstddef> #include<type_traits> #include<utility> namespacetk{ structMessage{ uint32_tid; uintptr_targ; }; template<typenameMsgType,size_tMaxSubscribers=4> classEventHub{ structSubscriber{ void*actor{nullptr}; bool(*post_fn)(void*,constMsgType&){nullptr}; }; staticinlineSubscribersubs_[MaxSubscribers]{}; staticinlinesize_tcount_{0}; public: staticboolsubscribe(void*actor,bool(*post_fn)(void*,constMsgType&)){ uint32_tsave=detail::sched_lock(); if(count_>=MaxSubscribers){ detail::sched_unlock(save); returnfalse; } for(size_ti=0;i<count_;++i){ if(subs_[i].actor==actor){ detail::sched_unlock(save); returntrue;//登録済み } } subs_[count_++]={actor,post_fn}; detail::sched_unlock(save); returntrue; } staticboolunsubscribe(void*actor){ uint32_tsave=detail::sched_lock(); for(size_ti=0;i<count_;++i){ if(subs_[i].actor==actor){ for(size_tj=i;j+1<count_;++j){ subs_[j]=subs_[j+1]; } count_--; detail::sched_unlock(save); returntrue; } } detail::sched_unlock(save); returnfalse; } staticsize_tpublish(constMsgType&msg){ Subscriberlocal_subs[MaxSubscribers]; size_tn=0; { uint32_tsave=detail::sched_lock(); n=count_; for(size_ti=0;i<n;++i){ local_subs[i]=subs_[i]; } detail::sched_unlock(save); } size_tdelivered=0; for(size_ti=0;i<n;++i){ if(local_subs[i].post_fn&&local_subs[i].post_fn(local_subs[i].actor,msg)){ delivered++; } } returndelivered; } staticsize_tsubscriber_count(){ uint32_tsave=detail::sched_lock(); size_tn=count_; detail::sched_unlock(save); returnn; } }; template<typenameMsgType> inlinesize_tpublish(constMsgType&msg){ returnEventHub<MsgType>::publish(msg); } inlinesize_tpublish(uint32_tid,uintptr_targ=0){ returnpublish(Message{id,arg}); } template<typenameMsgType=Message,size_tQueueSize=8> classActor{ static_assert(QueueSize>0,"QueueSizemustbegreaterthan0"); public: Actor()=default; virtual~Actor(){ EventHub<MsgType>::unsubscribe(this); } boolstart(uint32_tprio=PRIO_NORMAL){ EventHub<MsgType>::subscribe(this,[](void*obj,constMsgType&m){ returnstatic_cast<Actor<MsgType, QueueSize>*>(obj)->post(m); }); handle_=tk::create(task_entry,this,prio); returnhandle_.is_valid(); } boolpost(constMsgType&msg){ uint32_tsave=detail::sched_lock(); if(count_>=QueueSize){ detail::sched_unlock(save); returnfalse; } queue_[tail_]=msg; tail_=(tail_+1)%QueueSize; count_++; if(waiting_){ waiting_=false; detail::wake_task_locked(handle_); } detail::sched_unlock(save); returntrue; } boolpost(MsgType&&msg){ uint32_tsave=detail::sched_lock(); if(count_>=QueueSize){ detail::sched_unlock(save); returnfalse; } queue_[tail_]=std::move(msg); tail_=(tail_+1)%QueueSize; count_++; if(waiting_){ waiting_=false; detail::wake_task_locked(handle_); } detail::sched_unlock(save); returntrue; } template<typenameU=MsgType> typenamestd::enable_if<std::is_same<U,Message>::value,bool>::type post(uint32_tid,uintptr_targ=0){ returnpost(Message{id,arg}); } TaskHandlehandle()const{returnhandle_;} protected: virtualvoidon_start(){} virtualvoidon_message(constMsgType&msg)=0; private: staticvoidtask_entry(void*arg){ static_cast<Actor<MsgType, QueueSize>*>(arg)->event_loop(); } voidevent_loop(){ on_start(); for(;;){ MsgTypemsg{}; uint32_tsave=detail::sched_lock(); while(count_==0){ waiting_=true; detail::block_current_task_locked(); detail::sched_unlock(save); //コンテキストスイッチされ、他のタスクが走る。 //wake_task_lockedで起こされたらここに戻る。 save=detail::sched_lock(); } msg=std::move(queue_[head_]); head_=(head_+1)%QueueSize; count_--; waiting_=false; detail::sched_unlock(save); //メッセージディスパッチ(ロック解除状態で実行) on_message(msg); } } MsgTypequeue_[QueueSize]{}; size_thead_{0}; size_ttail_{0}; size_tcount_{0}; boolwaiting_{false}; TaskHandlehandle_{}; }; }//namespacetk