tinykernel
Toggle main menu visibility
読み取り中…
検索中…
一致する文字列を見つけられません
actor.hpp
[詳解]
1
#pragma once
2
3
#include "
kernel.hpp
"
4
#include <cstdint>
5
#include <cstddef>
6
#include <type_traits>
7
#include <utility>
8
9
namespace
tk
{
10
14
struct
Message
{
15
uint32_t
id
;
16
uintptr_t
arg
;
17
};
18
28
template
<
typename
MsgType,
size_t
MaxSubscribers = 4>
29
class
EventHub
{
30
struct
Subscriber {
31
void
* actor{
nullptr
};
32
bool (*post_fn)(
void
*,
const
MsgType&){
nullptr
};
33
};
34
35
static
inline
Subscriber subs_[MaxSubscribers]{};
36
static
inline
size_t
count_{0};
37
38
public
:
45
static
bool
subscribe
(
void
* actor,
bool
(*post_fn)(
void
*,
const
MsgType&)) {
46
uint32_t save =
detail::sched_lock
();
47
if
(count_ >= MaxSubscribers) {
48
detail::sched_unlock
(save);
49
return
false
;
50
}
51
for
(
size_t
i = 0; i < count_; ++i) {
52
if
(subs_[i].actor == actor) {
53
detail::sched_unlock
(save);
54
return
true
;
// 登録済み
55
}
56
}
57
subs_[count_++] = {actor, post_fn};
58
detail::sched_unlock
(save);
59
return
true
;
60
}
61
67
static
bool
unsubscribe
(
void
* actor) {
68
uint32_t save =
detail::sched_lock
();
69
for
(
size_t
i = 0; i < count_; ++i) {
70
if
(subs_[i].actor == actor) {
71
for
(
size_t
j = i; j + 1 < count_; ++j) {
72
subs_[j] = subs_[j + 1];
73
}
74
count_--;
75
detail::sched_unlock
(save);
76
return
true
;
77
}
78
}
79
detail::sched_unlock
(save);
80
return
false
;
81
}
82
89
static
size_t
publish
(
const
MsgType& msg) {
90
Subscriber local_subs[MaxSubscribers];
91
size_t
n = 0;
92
{
93
uint32_t save =
detail::sched_lock
();
94
n = count_;
95
for
(
size_t
i = 0; i < n; ++i) {
96
local_subs[i] = subs_[i];
97
}
98
detail::sched_unlock
(save);
99
}
100
101
size_t
delivered = 0;
102
for
(
size_t
i = 0; i < n; ++i) {
103
if
(local_subs[i].post_fn && local_subs[i].post_fn(local_subs[i].actor, msg)) {
104
delivered++;
105
}
106
}
107
return
delivered;
108
}
109
111
static
size_t
subscriber_count
() {
112
uint32_t save =
detail::sched_lock
();
113
size_t
n = count_;
114
detail::sched_unlock
(save);
115
return
n;
116
}
117
};
118
134
template
<
typename
MsgType>
135
inline
size_t
publish
(
const
MsgType& msg) {
136
return
EventHub<MsgType>::publish
(msg);
137
}
138
146
inline
size_t
publish
(uint32_t
id
, uintptr_t arg = 0) {
147
return
publish
(
Message
{id, arg});
148
}
149
173
template
<
typename
MsgType = Message,
size_t
QueueSize = 8>
174
class
Actor
{
175
static_assert
(QueueSize > 0,
"QueueSize must be greater than 0"
);
176
177
public
:
178
Actor
() =
default
;
179
virtual
~Actor
() {
180
EventHub<MsgType>::unsubscribe
(
this
);
181
}
182
191
bool
start
(uint32_t prio =
PRIO_NORMAL
) {
192
EventHub<MsgType>::subscribe
(
this
, [](
void
* obj,
const
MsgType& m) {
193
return
static_cast<
Actor<MsgType, QueueSize>
*
>
(obj)->
post
(m);
194
});
195
handle_ =
tk::create
(task_entry,
this
, prio);
196
return
handle_.is_valid();
197
}
198
207
bool
post
(
const
MsgType& msg) {
208
uint32_t save =
detail::sched_lock
();
209
if
(count_ >= QueueSize) {
210
detail::sched_unlock
(save);
211
return
false
;
212
}
213
queue_[tail_] = msg;
214
tail_ = (tail_ + 1) % QueueSize;
215
count_++;
216
if
(waiting_) {
217
waiting_ =
false
;
218
detail::wake_task_locked
(handle_);
219
}
220
detail::sched_unlock
(save);
221
return
true
;
222
}
223
230
bool
post
(MsgType&& msg) {
231
uint32_t save =
detail::sched_lock
();
232
if
(count_ >= QueueSize) {
233
detail::sched_unlock
(save);
234
return
false
;
235
}
236
queue_[tail_] = std::move(msg);
237
tail_ = (tail_ + 1) % QueueSize;
238
count_++;
239
if
(waiting_) {
240
waiting_ =
false
;
241
detail::wake_task_locked
(handle_);
242
}
243
detail::sched_unlock
(save);
244
return
true
;
245
}
246
254
template
<
typename
U = MsgType>
255
typename
std::enable_if<std::is_same<U, Message>::value,
bool
>::type
256
post
(uint32_t
id
, uintptr_t arg = 0) {
257
return
post
(
Message
{id, arg});
258
}
259
261
TaskHandle
handle
()
const
{
return
handle_; }
262
263
protected
:
270
virtual
void
on_start
() {}
271
280
virtual
void
on_message
(
const
MsgType& msg) = 0;
281
282
private
:
283
static
void
task_entry(
void
* arg) {
284
static_cast<
Actor<MsgType, QueueSize>
*
>
(arg)->event_loop();
285
}
286
287
void
event_loop() {
288
on_start
();
289
for
(;;) {
290
MsgType msg{};
291
uint32_t save =
detail::sched_lock
();
292
while
(count_ == 0) {
293
waiting_ =
true
;
294
detail::block_current_task_locked
();
295
detail::sched_unlock
(save);
296
// コンテキストスイッチされ、他のタスクが走る。
297
// wake_task_locked で起こされたらここに戻る。
298
save =
detail::sched_lock
();
299
}
300
msg = std::move(queue_[head_]);
301
head_ = (head_ + 1) % QueueSize;
302
count_--;
303
waiting_ =
false
;
304
detail::sched_unlock
(save);
305
306
// メッセージディスパッチ(ロック解除状態で実行)
307
on_message
(msg);
308
}
309
}
310
311
MsgType queue_[QueueSize]{};
312
size_t
head_{0};
313
size_t
tail_{0};
314
size_t
count_{0};
315
bool
waiting_{
false
};
316
TaskHandle handle_{};
317
};
318
319
}
// namespace tk
tk::Actor::on_message
virtual void on_message(const MsgType &msg)=0
メッセージ受信時に呼ばれるハンドラ関数
tk::Actor::post
bool post(const MsgType &msg)
この Actor のメッセージキューへ直接メッセージを送信します (コピー渡し)
定義
actor.hpp:207
tk::Actor::post
std::enable_if< std::is_same< U, Message >::value, bool >::type post(uint32_t id, uintptr_t arg=0)
tk::Message 型の場合のコンビニエンス送信関数
定義
actor.hpp:256
tk::Actor::handle
TaskHandle handle() const
定義
actor.hpp:261
tk::Actor::Actor
Actor()=default
tk::Actor::post
bool post(MsgType &&msg)
この Actor のメッセージキューへ直接メッセージを送信します (ムーブ渡し)
定義
actor.hpp:230
tk::Actor::~Actor
virtual ~Actor()
定義
actor.hpp:179
tk::Actor::start
bool start(uint32_t prio=PRIO_NORMAL)
Actor をタスクとして生成し、EventHub へ自動登録します
定義
actor.hpp:191
tk::Actor::on_start
virtual void on_start()
タスク起動時、イベントループ突入直前に1度だけ呼ばれる初期化関数
定義
actor.hpp:270
tk::EventHub
メッセージ型ごとの超軽量 Pub/Sub ディスパッチャ
定義
actor.hpp:29
tk::EventHub::unsubscribe
static bool unsubscribe(void *actor)
Actor の購読登録を解除します
定義
actor.hpp:67
tk::EventHub::publish
static size_t publish(const MsgType &msg)
このメッセージ型を購読しているすべての Actor へ同報配信します
定義
actor.hpp:89
tk::EventHub::subscribe
static bool subscribe(void *actor, bool(*post_fn)(void *, const MsgType &))
Actor をこのメッセージ型の購読者として登録します
定義
actor.hpp:45
tk::EventHub::subscriber_count
static size_t subscriber_count()
定義
actor.hpp:111
kernel.hpp
tk::detail::block_current_task_locked
void block_current_task_locked()
定義
scheduler.cpp:333
tk::detail::sched_lock
uint32_t sched_lock()
定義
scheduler.cpp:325
tk::detail::sched_unlock
void sched_unlock(uint32_t save)
定義
scheduler.cpp:329
tk::detail::wake_task_locked
void wake_task_locked(TaskHandle handle)
定義
scheduler.cpp:340
tk
定義
actor.hpp:9
tk::publish
size_t publish(const MsgType &msg)
メッセージの型を指定して、購読しているすべての Actor へ同報配信します
定義
actor.hpp:135
tk::PRIO_NORMAL
@ PRIO_NORMAL
通常優先度 (デフォルト)
定義
kernel.hpp:42
tk::create
TaskHandle create(TaskFn fn, void *arg=nullptr, uint32_t prio=PRIO_NORMAL)
タスクを生成・登録します
定義
scheduler.cpp:204
tk::Message
デフォルトの軽量メッセージ構造体
定義
actor.hpp:14
tk::Message::arg
uintptr_t arg
引数 (ポインタまたは整数値)
定義
actor.hpp:16
tk::Message::id
uint32_t id
メッセージ識別子 / コマンドID
定義
actor.hpp:15
tk::TaskHandle
タスクの識別ハンドル
定義
kernel.hpp:49
tinykernel
include
tinykernel
actor.hpp
構築:
1.18.0