Jelajahi Sumber

modified: Actorをメッセージのテンプレートに

Satoshi Yoneda 1 bulan lalu
induk
melakukan
08d334becf
2 mengubah file dengan 54 tambahan dan 30 penghapusan
  1. 21 19
      main.cpp
  2. 33 11
      tinykernel/include/tinykernel/actor.hpp

+ 21 - 19
main.cpp

@@ -19,14 +19,16 @@
     } while (0)
 
 // ---------------------------------------------------------------------------
-// Actor demonstration: Receiver Actor waiting for messages.
-// It consumes 0 CPU cycles while waiting, and immediately wakes up on post().
-enum AppMsgId : uint32_t {
-    MSG_LED_TOGGLE = 1,
-    MSG_PING       = 2,
+// Actor demonstration: Receiver Actor waiting for typed messages by-value.
+// The message (including the embedded string payload) is copied directly into the
+// actor's queue, so sender tasks can pass local/stack variables safely without
+// lifetime or dangling pointer issues.
+struct AppMessage {
+    uint32_t seq;
+    char text[32];  // Embedded payload held safely by the queue!
 };
 
-class LedActor : public tk::Actor<8> {
+class LedActor : public tk::Actor<AppMessage, 8> {
 protected:
     void on_start() override {
         // Hardware initialization within task context
@@ -36,16 +38,11 @@ protected:
         P("LedActor: initialized GPIO 25 in on_start()\n");
     }
 
-    void on_message(const tk::Message& msg) override {
-        if (msg.id == MSG_LED_TOGGLE) {
-            bool state = !gpio_get(25);
-            gpio_put(25, state);
-            P("LedActor: received MSG_LED_TOGGLE (seq=%lu) -> LED %s, now=%llu ms\n",
-              (unsigned long)msg.arg, state ? "ON" : "OFF", (unsigned long long)tk::now_ms());
-        } else {
-            P("LedActor: received unknown msg id=%lu, arg=%lu\n",
-              (unsigned long)msg.id, (unsigned long)msg.arg);
-        }
+    void on_message(const AppMessage& msg) override {
+        bool state = !gpio_get(25);
+        gpio_put(25, state);
+        P("LedActor: received seq=%lu text=\"%s\" -> LED %s, now=%llu ms\n",
+          (unsigned long)msg.seq, msg.text, state ? "ON" : "OFF", (unsigned long long)tk::now_ms());
     }
 };
 
@@ -57,9 +54,14 @@ static void task_sender(void* arg) {
     uint32_t seq = 0;
     for (;;) {
         tk::sleep_ms(600);
-        P("Sender: posting MSG_LED_TOGGLE seq=%lu...\n", (unsigned long)seq);
-        g_led_actor.post(MSG_LED_TOGGLE, seq++);
-    }
+        // Local variable allocated on task_sender's stack
+        AppMessage msg{};
+        msg.seq = seq++;
+        snprintf(msg.text, sizeof(msg.text), "Ping #%lu", (unsigned long)msg.seq);
+
+        P("Sender: posting text=\"%s\"...\n", msg.text);
+        g_led_actor.post(msg);  // Copied by-value into g_led_actor's queue!
+    }  // msg on stack is destroyed here, but g_led_actor safely holds the copy!
 }
 
 // ---------------------------------------------------------------------------

+ 33 - 11
tinykernel/include/tinykernel/actor.hpp

@@ -3,6 +3,8 @@
 #include "kernel.hpp"
 #include <cstdint>
 #include <cstddef>
+#include <type_traits>
+#include <utility>
 
 namespace tk {
 
@@ -11,7 +13,7 @@ struct Message {
     uintptr_t arg;
 };
 
-template <size_t QueueSize = 8>
+template <typename MsgType = Message, size_t QueueSize = 8>
 class Actor {
     static_assert(QueueSize > 0, "QueueSize must be greater than 0");
 
@@ -25,8 +27,8 @@ public:
         return handle_.is_valid();
     }
 
-    // メッセージを送信する(非同期、スレッドセーフ、割り込みセーフ)
-    bool post(const Message& msg) {
+    // メッセージを送信する(非同期、スレッドセーフ、割り込みセーフ、値コピー)
+    bool post(const MsgType& msg) {
         uint32_t save = detail::sched_lock();
         if (count_ >= QueueSize) {
             detail::sched_unlock(save);
@@ -43,7 +45,28 @@ public:
         return true;
     }
 
-    bool post(uint32_t id, uintptr_t arg = 0) {
+    // ムーブセマンティクスによる送信
+    bool post(MsgType&& msg) {
+        uint32_t save = detail::sched_lock();
+        if (count_ >= QueueSize) {
+            detail::sched_unlock(save);
+            return false;
+        }
+        queue_[tail_] = std::move(msg);
+        tail_ = (tail_ + 1) % QueueSize;
+        count_++;
+        if (waiting_) {
+            waiting_ = false;
+            detail::wake_task_locked(handle_);
+        }
+        detail::sched_unlock(save);
+        return true;
+    }
+
+    // MsgType が tk::Message の場合のコンビニエンス関数
+    template <typename U = MsgType>
+    typename std::enable_if<std::is_same<U, Message>::value, bool>::type
+    post(uint32_t id, uintptr_t arg = 0) {
         return post(Message{id, arg});
     }
 
@@ -53,18 +76,18 @@ protected:
     // タスク起動時にイベントループ開始直前に呼ばれる初期化関数(タスクコンテキスト内)
     virtual void on_start() {}
 
-    // 派生クラスでオーバーライドしてメッセージを処理する
-    virtual void on_message(const Message& msg) = 0;
+    // 派生クラスでオーバーライドしてメッセージを処理する(値への参照で安全に渡される)
+    virtual void on_message(const MsgType& msg) = 0;
 
 private:
     static void task_entry(void* arg) {
-        static_cast<Actor<QueueSize>*>(arg)->event_loop();
+        static_cast<Actor<MsgType, QueueSize>*>(arg)->event_loop();
     }
 
     void event_loop() {
         on_start();
         for (;;) {
-            Message msg{};
+            MsgType msg{};
             uint32_t save = detail::sched_lock();
             while (count_ == 0) {
                 waiting_ = true;
@@ -74,7 +97,7 @@ private:
                 // wake_task_locked で起こされたらここに戻る。
                 save = detail::sched_lock();
             }
-            msg = queue_[head_];
+            msg = std::move(queue_[head_]);
             head_ = (head_ + 1) % QueueSize;
             count_--;
             waiting_ = false;
@@ -85,7 +108,7 @@ private:
         }
     }
 
-    Message queue_[QueueSize]{};
+    MsgType queue_[QueueSize]{};
     size_t head_{0};
     size_t tail_{0};
     size_t count_{0};
@@ -94,4 +117,3 @@ private:
 };
 
 }  // namespace tk
-