|
|
nono 1.5.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// VM (基本クラス)
//
#include "vm.h"
#include "debugger.h"
#include "event.h"
#include "mainapp.h"
#include "mainbus.h"
#include "scheduler.h"
#include "signalthread.h"
#include "syncer.h"
#include "uimessage.h"
// コンストラクタ
VM::VM(const char *vmname_)
{
vmname = vmname_;
assert(vmname);
// SignalThread は他のスレッドより先に起動する必要があるので、先頭。
// EventManager は Scheduler に必要。
// Scheduler は以降の他のデバイスからのイベント登録を受け付ける必要が
// あるためその次。
// Debugger は HostCOM と stdio ドライバが競合した場合に優先したいため
// もあって必ず先に配置する必要がある。
NEWDV(SignalThread, new SignalThread());
NEWDV(EventManager, new EventManager());
NEWDV(Scheduler, new Scheduler());
NEWDV(Syncer, new Syncer());
NEWDV(Debugger, new Debugger());
}
// デストラクタ
VM::~VM()
{
Dispose();
}
// 終了
void
VM::Dispose()
{
// (もう止まってるはずだが) 念のため UIMessage の送出を止める。
gMainApp.GetUIMessage()->StopUIMessage();
// スレッドを止める。
// デバッガスレッドがスケジューラスレッドにアクセスするのでデバッガが先。
if ((bool)pDebugger) {
GetDebugger()->TerminateThread();
}
if ((bool)pScheduler) {
GetScheduler()->TerminateThread();
}
// 残りのスレッドを停止
for (auto obj : gMainApp.GetObjects()) {
auto th = dynamic_cast<ThreadDevice *>(obj);
if (th) {
th->TerminateThread();
}
}
// 作ったときと逆順で解放する
if ((bool)pDebugger) {
pDebugger.reset();
}
if ((bool)pScheduler) {
pScheduler.reset();
}
if ((bool)pEventManager) {
pEventManager.reset();
}
// ほかのオブジェクトの解放はグローバルデストラクタにおまかせ。
// だめだったらまた考える。
}
// 動的コンストラクション。
bool
VM::Create(VM::CreationPhase phase)
{
// d->Create() は Object を追加する場合があるため、ここで
// ranged for は使えない。また追加されたデバイスの Create()/Create2() も
// 実行したいため、ループ終了条件で毎回 size() を取り出して比較する。
for (int i = 0; i < gMainApp.GetObjects().size(); i++) {
auto dev = dynamic_cast<Device *>(gMainApp.GetObjects()[i]);
if (dev) {
if (phase == CreationPhase::First) {
if (!dev->Create()) {
return false;
}
} else {
if (!dev->Create2()) {
return false;
}
}
}
}
// ログのためのメンバ変数初期化。
// 同じオブジェクトに対して複数回呼んでも副作用はない。
for (auto obj : gMainApp.GetObjects()) {
auto dev = dynamic_cast<Device *>(obj);
if (dev) {
dev->EarlyInit();
}
}
// 名無しオブジェクトがあれば開発中に検出したい。
// 名無しでも動作には影響ないのでリリース版では怒られないでほしい。
#if !defined(RELEASE)
for (auto obj : gMainApp.GetObjects()) {
if (obj->GetName().empty()) {
printf("Objects:\n");
for (auto o : gMainApp.GetObjects()) {
printf("%s\n", o->GetName().c_str());
}
assert(obj->GetName().empty() == false);
}
}
#endif
return true;
}
// 初期化
bool
VM::Init()
{
for (auto obj : gMainApp.GetObjects()) {
auto dev = dynamic_cast<Device *>(obj);
if (dev) {
if (!dev->Init()) {
return false;
}
}
}
// デバイスの初期化が全部出来たのでメインバスの初期化。
auto mainbus = dynamic_cast<MainbusDevice*>(pMainbus.get());
if (mainbus->InitMainbus() == false) {
return false;
}
// イベントが出揃ったのでスケジューラモニタの行数を確定。
auto scheduler = dynamic_cast<Scheduler*>(pScheduler.get());
if (scheduler->Init2() == false) {
return false;
}
return true;
}
// スレッド開始
bool
VM::StartThread()
{
for (auto obj : gMainApp.GetObjects()) {
auto th = dynamic_cast<ThreadDevice *>(obj);
if (th) {
if (!th->StartThread()) {
return false;
}
}
}
return true;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.