|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2017 [email protected]
4: //
5:
6: #pragma once
7:
8: #include <atomic>
9: #include <condition_variable>
10: #include <mutex>
11: #include <pthread.h>
12: #include "device.h"
13: #include "event.h"
14: #include "mpu.h"
15:
16: // スケジューラ
17: class Scheduler : public Device
18: {
19: typedef Device inherited;
20:
21: // リクエストフラグ
22: static const uint REQ_SYNC = 0x0001; // スケジューラを同期モードに
23: static const uint REQ_FAST = 0x0002; // スケジューラを高速モードに
24: static const uint REQ_RUN = 0x0004; // MPU が通常状態になった
25: static const uint REQ_STOP = 0x0008; // MPU が STOP 状態になった
26: static const uint REQ_MODEMASK = 0x000f; // mode マスク
27: static const uint REQ_POWER_ON = 0x0010; // 電源オン
28: static const uint REQ_POWER_OFF = 0x0020; // 電源オフ
29: static const uint REQ_EXIT = 0x0040; // アプリケーション終了
30:
31: // 動作モード
32: // 動作モード変数 (mode) は高速モードか通常モードかと、MPU が通常状態が
33: // STOP 状態かを同時に保持している。高速走行中であっても MPU が STOP 状態
34: // なら通常走行するというロジックを比較1回で済ませるため。
35: static const uint32 SCHED_STOP = 0x0001; // スケジューラが STOP 状態
36: static const uint32 SCHED_SYNC = 0x0002; // 同期(%1)/高速(%0)モード
37: // 演算を1回で済ませるために、同じ値にすること
38: static_assert(SCHED_STOP == CPU_REQ_STOP, "must be the same");
39:
40: public:
41: Scheduler();
42: virtual ~Scheduler();
43:
44: virtual bool Init();
45:
46: virtual bool MonitorUpdate();
47:
48: // スレッド開始
49: void ThreadRun();
50:
51: // スレッド終了指示
52: void Terminate();
53:
54: // スケジューラを開始 (電源オン時に vm から呼ばれる)
55: void Run();
56:
57: // 電源オフ要求
58: void RequestPowerOff() {
59: atomic_reqflag |= REQ_POWER_OFF;
60: }
61:
62: // サイクル数を仮想時間 [nsec] に変換
63: uint64 Cycle2Vtime(uint64 cycle) const {
64: return cycle * 1000 * 1000 / mpu_clock;
65: }
66:
67: // 仮想時間 [nsec] をサイクル数に変換
68: uint64 Vtime2Cycle(uint64 vtime) const {
69: return vtime * mpu_clock / (1000 * 1000);
70: }
71:
72: // 仮想時刻取得
73: uint64 GetVirtTime() const {
74: return Cycle2Vtime(gMPU->total_cycle());
75: }
76:
77: // スケジューラが高速モードなら true を返す。
78: // ここでいう高速モードは STOP 状態中でも高速モード。
79: bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }
80:
81: // スケジューラの動作モードを設定する。
82: // true なら高速モード、false なら同期モード。
83: void SetFullSpeed(bool enable);
84:
85: // イベントを登録する
86: void AddEvent(Event *newev);
87: // イベントを削除する
88: void DelEvent(Event *event);
89:
90: std::list<Event *> eventlist {}; // 有効なイベントリスト
91: std::mutex evcs {}; // イベントリストのロック
92:
93: // 状態変更要求
94: // スケジューラループの状態を変更したい場合はこのフラグを立てる。
95: // REQ_MODE_* の相反するビット以外は同時に複数立ててもいいはず。
96: // 処理されると再び 0 になる。
97: std::atomic<uint32> atomic_reqflag {};
98: std::condition_variable cv {};
99: std::mutex cvmtx {};
100:
101: private:
102: // スケジューラの動作モード。SCHED_*
103: uint32 mode = 0;
104:
105: int mpu_clock = 0; // MPU クロック [kHz]
106:
107: uint64 rtimestart = 0; // スケジューラ開始実時刻
108: uint64 rtimebase = 0; // 実時間の基準時刻
109: uint64 vtimebase = 0; // 仮想時間の基準時刻
110:
111: // 前回 RTC へ 32Hz 入力パルスを入れた時刻 (実時間の絶対時刻系)
112: uint64 rtc_last_clock = 0;
113: };
114:
115: extern Scheduler *gScheduler;
116:
117: // 現在時刻 [nsec] を取得する
118: static inline uint64 GetRealTime()
119: {
120: struct timeval tv;
121: gettimeofday(&tv, NULL);
122: return (uint64)(tv.tv_sec * 1000 * 1000 + tv.tv_usec) * 1000;
123: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.