--- nono/vm/scheduler.cpp 2026/04/29 17:05:14 1.1.1.15 +++ nono/vm/scheduler.cpp 2026/04/29 17:05:18 1.1.1.16 @@ -12,7 +12,7 @@ // 仮想時間はすべて nsec で表し、StartTime() から単調増加する。 // VM 界からは仮想時間は gScheduler->GetVirtTime() で取得する。 // -// 実時間は Sync が管理し、こちらも nsec で表す。 +// 実時間は Syncer が管理し、こちらも nsec で表す。 // このストップウォッチも StartTime() から単調増加する。 // 実時間、仮想時間とも電源オフ中でも単調増加することに注意。 // @@ -33,7 +33,7 @@ #include "scheduler.h" #include "mpu.h" #include "rtc.h" -#include "sync.h" +#include "syncer.h" //#define CT_ON @@ -55,9 +55,6 @@ static uint64 ct_pslow; #define CT(name) #endif -// グローバル参照用 -Scheduler *gScheduler; - #define FORMAT_FULL 0 #define FORMAT_SEC 1 @@ -153,7 +150,7 @@ SecToStr(uint64 t) // コンストラクタ Scheduler::Scheduler() - : inherited("Scheduler") + : inherited(OBJ_SCHEDULER) { // オブジェクト名は Scheduler だがここのスレッド名は VM くらいのほうが // 通りがよさそうだ。 @@ -171,13 +168,18 @@ Scheduler::Scheduler() Scheduler::~Scheduler() { TerminateThread(); - gScheduler = NULL; } // 初期化 bool Scheduler::Init() { + if (inherited::Init() == false) { + return false; + } + + syncer = GetSyncer(); + // この時点でイベントの個数は確定しているはず(してなければならない) monitor.SetSize(80, 9 + all_events.size()); @@ -206,8 +208,14 @@ Scheduler::ThreadRun() if ((req & REQUEST_EXIT)) { break; } - if ((req & REQUEST_MESSAGE)) { - DispatchMessage(); + + for (; req; req &= req - 1) { + int id = __builtin_ctz(req); + if (id < MessageID::MAX_REQUEST) { + InvokeMessage(id, 0); + } else { + DispatchMessage(); + } } } @@ -248,8 +256,8 @@ Scheduler::StartTime() // 時間をリセットする。 // 呼び出しの依存関係に注意。 vtime = 0; // required by Sync - gSync->StartTime(); // required by RTC - gRTC->StartTime(); + syncer->StartTime(); // required by RTC + GetRTCDevice()->StartTime(); } // スレッド終了指示 @@ -345,7 +353,7 @@ Scheduler::StartRealtimeEvent(Event& ev, { // 実時間をもとに仮想時間軸上の推定を行う。 - uint64 rtime = gSync->GetRealTime(); + uint64 rtime = syncer->GetRealTime(); if (rtime > rt_now + rt_period) { // 実時間がさらに 1 period 以上進んでいる。 @@ -440,8 +448,11 @@ Scheduler::StopSlowEvent(Event& ev) void Scheduler::ConnectMessage(MessageID msgid, Device *dev, MessageCallback_t func) { + assert(msgid < MessageID::MAX); + auto& mh = message_handlers[msgid]; - assert(mh.dev == NULL); + assertmsg(mh.dev == NULL, + "%s: msgid=%d connected again", __func__, (int)msgid); mh.dev = dev; mh.func = func; } @@ -456,15 +467,30 @@ Scheduler::DispatchMessage() MessageID msgid = (MessageID)(msg & 0xff); uint32 arg = (msg >> 32); - assert(0 <= msgid && msgid < MessageID::MAX); - - auto& mh = message_handlers[msgid]; - if (mh.dev != NULL) { - ((mh.dev)->*(mh.func))(msgid, arg); + // MessageID::MPU_TRACE_ALL だけ特別対応。 + // MPU_TRACE メッセージの宛先は(最大)2つあるが、 + // スレッドを越える時は1メッセージにしておきたいので、 + // MPU_TRACE_ALL が来たらここで分岐。 + if (msgid == MessageID::MPU_TRACE_ALL) { + InvokeMessage(MessageID::MPU_TRACE_MAIN, arg); + InvokeMessage(MessageID::MPU_TRACE_XP, arg); + } else { + assert(msgid < MessageID::MAX); + InvokeMessage(msgid, arg); } } } +// メッセージハンドラを呼び出す。登録されてなければ何もしない。 +void +Scheduler::InvokeMessage(MessageID msgid, uint32 arg) +{ + auto h = message_handlers[msgid]; + if (h.dev != NULL) { + (h.dev->*(h.func))(msgid, arg); + } +} + // メッセージを送る。 // VM スレッド以外から呼び出しても良い。 void @@ -472,11 +498,15 @@ Scheduler::SendMessage(MessageID msgid, { std::unique_lock lock(mtx); - uint64 msg = (uint64)msgid | (((uint64)arg) << 32); - if (msgq.Enqueue(msg) == false) { - putlog(0, "Message queue exhausted !!"); + if (msgid < MessageID::MAX_REQUEST) { + request |= 1U << (uint)msgid; + } else { + uint64 msg = (uint64)msgid | (((uint64)arg) << 32); + if (msgq.Enqueue(msg) == false) { + putlog(0, "Message queue exhausted !! msgid=%d", (int)msgid); + } + request |= REQUEST_MESSAGE; } - request |= REQUEST_MESSAGE; cv.notify_one(); } @@ -498,9 +528,9 @@ Scheduler::MonitorUpdate(Monitor *, Text screen.Clear(); - y = gSync->MonitorUpdateSub(screen, vtime); + y = syncer->MonitorUpdateSub(screen, vtime); - int clock_khz = gMPU->GetClockSpeed(); + int clock_khz = mpu->GetClockSpeed(); screen.Print(0, y++, "MPU Speed: %d.%03dMHz", (clock_khz / 1000), (clock_khz % 1000));