| 1 |
#include "AfterCommand.hh" |
| 2 |
|
| 3 |
#include "CliComm.hh" |
| 4 |
#include "CommandController.hh" |
| 5 |
#include "CommandException.hh" |
| 6 |
#include "EmuTime.hh" |
| 7 |
#include "Event.hh" |
| 8 |
#include "EventDistributor.hh" |
| 9 |
#include "InputEventFactory.hh" |
| 10 |
#include "MSXMotherBoard.hh" |
| 11 |
#include "ObjectPool.hh" |
| 12 |
#include "RTSchedulable.hh" |
| 13 |
#include "Reactor.hh" |
| 14 |
#include "Schedulable.hh" |
| 15 |
#include "TclObject.hh" |
| 16 |
|
| 17 |
#include "strCat.hh" |
| 18 |
#include "StringOp.hh" |
| 19 |
#include "stl.hh" |
| 20 |
#include "unreachable.hh" |
| 21 |
|
| 22 |
#include <algorithm> |
| 23 |
#include <format> |
| 24 |
#include <iterator> |
| 25 |
#include <ranges> |
| 26 |
#include <variant> |
| 27 |
|
| 28 |
namespace openmsx { |
| 29 |
|
| 30 |
class AfterCmd; |
| 31 |
class AfterCommand; |
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
struct DelayedCommand { |
| 38 |
TclObject command; |
| 39 |
AfterCommand& afterCommand; |
| 40 |
|
| 41 |
void execute() { |
| 42 |
try { |
| 43 |
command.executeCommand(afterCommand.getInterpreter()); |
| 44 |
} catch (CommandException& e) { |
| 45 |
afterCommand.getCommandController().getCliComm().printWarning( |
| 46 |
"Error executing delayed command: ", e.getMessage()); |
| 47 |
} |
| 48 |
} |
| 49 |
}; |
| 50 |
|
| 51 |
class AfterCmd |
| 52 |
{ |
| 53 |
public: |
| 54 |
[[nodiscard]] const auto& getCommand() const { return command; } |
| 55 |
[[nodiscard]] auto getId() const { return id; } |
| 56 |
[[nodiscard]] auto getIdStr() const { return tmpStrCat("after#", id); } |
| 57 |
[[nodiscard]] DelayedCommand extractCommand(); |
| 58 |
protected: |
| 59 |
AfterCmd(AfterCommand& afterCommand, |
| 60 |
TclObject command); |
| 61 |
AfterCommand::Index removeSelf(); |
| 62 |
|
| 63 |
AfterCommand& afterCommand; |
| 64 |
TclObject command; |
| 65 |
const unsigned id; |
| 66 |
static inline unsigned lastAfterId = 0; |
| 67 |
}; |
| 68 |
|
| 69 |
class AfterTimedCmd : public AfterCmd, private Schedulable |
| 70 |
{ |
| 71 |
public: |
| 72 |
[[nodiscard]] double getTime() const; |
| 73 |
void reschedule(); |
| 74 |
protected: |
| 75 |
AfterTimedCmd(Scheduler& scheduler, |
| 76 |
AfterCommand& afterCommand, |
| 77 |
TclObject command, double time); |
| 78 |
private: |
| 79 |
void executeUntil(EmuTime time) override; |
| 80 |
void schedulerDeleted() override; |
| 81 |
|
| 82 |
double time; |
| 83 |
|
| 84 |
}; |
| 85 |
|
| 86 |
class AfterTimeCmd final : public AfterTimedCmd |
| 87 |
{ |
| 88 |
public: |
| 89 |
AfterTimeCmd(Scheduler& scheduler, |
| 90 |
AfterCommand& afterCommand, |
| 91 |
TclObject command, double time); |
| 92 |
}; |
| 93 |
|
| 94 |
class AfterIdleCmd final : public AfterTimedCmd |
| 95 |
{ |
| 96 |
public: |
| 97 |
AfterIdleCmd(Scheduler& scheduler, |
| 98 |
AfterCommand& afterCommand, |
| 99 |
TclObject command, double time); |
| 100 |
}; |
| 101 |
|
| 102 |
class AfterSimpleEventCmd final : public AfterCmd |
| 103 |
{ |
| 104 |
public: |
| 105 |
AfterSimpleEventCmd(AfterCommand& afterCommand, |
| 106 |
TclObject command, |
| 107 |
EventType type); |
| 108 |
[[nodiscard]] std::string_view getType() const; |
| 109 |
[[nodiscard]] EventType getTypeEnum() const { return type; } |
| 110 |
private: |
| 111 |
EventType type; |
| 112 |
}; |
| 113 |
|
| 114 |
class AfterInputEventCmd final : public AfterCmd |
| 115 |
{ |
| 116 |
public: |
| 117 |
AfterInputEventCmd(AfterCommand& afterCommand, |
| 118 |
Event event, |
| 119 |
TclObject command); |
| 120 |
[[nodiscard]] const Event& getEvent() const { return event; } |
| 121 |
private: |
| 122 |
Event event; |
| 123 |
}; |
| 124 |
|
| 125 |
class AfterRealTimeCmd final : public AfterCmd, private RTSchedulable |
| 126 |
{ |
| 127 |
public: |
| 128 |
AfterRealTimeCmd(RTScheduler& rtScheduler, AfterCommand& afterCommand, |
| 129 |
TclObject command, double time); |
| 130 |
|
| 131 |
private: |
| 132 |
void executeRT() override; |
| 133 |
}; |
| 134 |
|
| 135 |
using AllAfterCmds = std::variant<AfterTimeCmd, |
| 136 |
AfterIdleCmd, |
| 137 |
AfterSimpleEventCmd, |
| 138 |
AfterInputEventCmd, |
| 139 |
AfterRealTimeCmd>; |
| 140 |
static ObjectPool<AllAfterCmds> afterCmdPool; |
| 141 |
|
| 142 |
|
| 143 |
AfterCommand::AfterCommand(Reactor& reactor_, |
| 144 |
EventDistributor& eventDistributor_, |
| 145 |
CommandController& commandController_) |
| 146 |
: Command(commandController_, "after") |
| 147 |
, reactor(reactor_) |
| 148 |
, eventDistributor(eventDistributor_) |
| 149 |
{ |
| 150 |
|
| 151 |
|
| 152 |
using enum EventType; |
| 153 |
for (auto type : {KEY_UP, KEY_DOWN, |
| 154 |
MOUSE_MOTION, MOUSE_BUTTON_UP, MOUSE_BUTTON_DOWN, MOUSE_WHEEL, |
| 155 |
JOY_AXIS_MOTION, JOY_HAT, JOY_BUTTON_UP, JOY_BUTTON_DOWN, |
| 156 |
FINISH_FRAME, BREAK, QUIT, BOOT, MACHINE_LOADED, AFTER_TIMED}) { |
| 157 |
eventDistributor.registerEventListener(type, *this); |
| 158 |
} |
| 159 |
} |
| 160 |
|
| 161 |
AfterCommand::~AfterCommand() |
| 162 |
{ |
| 163 |
for (auto idx : afterCmds) { |
| 164 |
afterCmdPool.remove(idx); |
| 165 |
} |
| 166 |
|
| 167 |
using enum EventType; |
| 168 |
for (auto type : {AFTER_TIMED, MACHINE_LOADED, BOOT, QUIT, BREAK, FINISH_FRAME, |
| 169 |
JOY_BUTTON_DOWN, JOY_BUTTON_UP, JOY_HAT, JOY_AXIS_MOTION, MOUSE_WHEEL, |
| 170 |
MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP, MOUSE_MOTION, |
| 171 |
KEY_DOWN, KEY_UP}) { |
| 172 |
eventDistributor.unregisterEventListener(type, *this); |
| 173 |
} |
| 174 |
} |
| 175 |
|
| 176 |
void AfterCommand::execute(std::span<const TclObject> tokens, TclObject& result) |
| 177 |
{ |
| 178 |
if (tokens.size() < 2) { |
| 179 |
throw CommandException("Missing argument"); |
| 180 |
} |
| 181 |
std::string_view subCmd = tokens[1].getString(); |
| 182 |
if (subCmd == "time") { |
| 183 |
afterTime(tokens, result); |
| 184 |
} else if (subCmd == "realtime") { |
| 185 |
afterRealTime(tokens, result); |
| 186 |
} else if (subCmd == "idle") { |
| 187 |
afterIdle(tokens, result); |
| 188 |
} else if (subCmd == "frame") { |
| 189 |
afterSimpleEvent(tokens, result, EventType::FINISH_FRAME); |
| 190 |
} else if (subCmd == "break") { |
| 191 |
afterSimpleEvent(tokens, result, EventType::BREAK); |
| 192 |
} else if (subCmd == "quit") { |
| 193 |
afterSimpleEvent(tokens, result, EventType::QUIT); |
| 194 |
} else if (subCmd == "boot") { |
| 195 |
afterSimpleEvent(tokens, result, EventType::BOOT); |
| 196 |
} else if (subCmd == "machine_switch") { |
| 197 |
afterSimpleEvent(tokens, result, EventType::MACHINE_LOADED); |
| 198 |
} else if (subCmd == "info") { |
| 199 |
afterInfo(tokens, result); |
| 200 |
} else if (subCmd == "cancel") { |
| 201 |
afterCancel(tokens, result); |
| 202 |
} else { |
| 203 |
|
| 204 |
if (auto time = tokens[1].getOptionalInt()) { |
| 205 |
afterTclTime(*time, tokens, result); |
| 206 |
} else { |
| 207 |
|
| 208 |
try { |
| 209 |
afterInputEvent( |
| 210 |
InputEventFactory::createInputEvent( |
| 211 |
tokens[1], getInterpreter()), |
| 212 |
tokens, result); |
| 213 |
} catch (MSXException&) { |
| 214 |
throw SyntaxError(); |
| 215 |
} |
| 216 |
} |
| 217 |
} |
| 218 |
} |
| 219 |
|
| 220 |
static double getTime(Interpreter& interp, const TclObject& obj) |
| 221 |
{ |
| 222 |
double time = obj.getDouble(interp); |
| 223 |
if (time < 0) { |
| 224 |
throw CommandException("Not a valid time specification"); |
| 225 |
} |
| 226 |
return time; |
| 227 |
} |
| 228 |
|
| 229 |
void AfterCommand::afterTime(std::span<const TclObject> tokens, TclObject& result) |
| 230 |
{ |
| 231 |
checkNumArgs(tokens, 4, Prefix{2}, "seconds command"); |
| 232 |
MSXMotherBoard* motherBoard = reactor.getMotherBoard(); |
| 233 |
if (!motherBoard) return; |
| 234 |
double time = getTime(getInterpreter(), tokens[2]); |
| 235 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 236 |
std::in_place_type_t<AfterTimeCmd>{}, |
| 237 |
motherBoard->getScheduler(), *this, tokens[3], time); |
| 238 |
result = std::get<AfterTimeCmd>(*ptr).getIdStr(); |
| 239 |
afterCmds.push_back(idx); |
| 240 |
} |
| 241 |
|
| 242 |
void AfterCommand::afterRealTime(std::span<const TclObject> tokens, TclObject& result) |
| 243 |
{ |
| 244 |
checkNumArgs(tokens, 4, Prefix{2}, "seconds command"); |
| 245 |
double time = getTime(getInterpreter(), tokens[2]); |
| 246 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 247 |
std::in_place_type_t<AfterRealTimeCmd>{}, |
| 248 |
reactor.getRTScheduler(), *this, tokens[3], time); |
| 249 |
result = std::get<AfterRealTimeCmd>(*ptr).getIdStr(); |
| 250 |
afterCmds.push_back(idx); |
| 251 |
} |
| 252 |
|
| 253 |
void AfterCommand::afterTclTime( |
| 254 |
int ms, std::span<const TclObject> tokens, TclObject& result) |
| 255 |
{ |
| 256 |
TclObject command; |
| 257 |
command.addListElements(std::views::drop(tokens, 2)); |
| 258 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 259 |
std::in_place_type_t<AfterRealTimeCmd>{}, |
| 260 |
reactor.getRTScheduler(), *this, command, ms * (1.0 / 1000.0)); |
| 261 |
result = std::get<AfterRealTimeCmd>(*ptr).getIdStr(); |
| 262 |
afterCmds.push_back(idx); |
| 263 |
} |
| 264 |
|
| 265 |
void AfterCommand::afterSimpleEvent(std::span<const TclObject> tokens, TclObject& result, EventType type) |
| 266 |
{ |
| 267 |
checkNumArgs(tokens, 3, "command"); |
| 268 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 269 |
std::in_place_type_t<AfterSimpleEventCmd>{}, |
| 270 |
*this, tokens[2], type); |
| 271 |
result = std::get<AfterSimpleEventCmd>(*ptr).getIdStr(); |
| 272 |
afterCmds.push_back(idx); |
| 273 |
} |
| 274 |
|
| 275 |
void AfterCommand::afterInputEvent( |
| 276 |
Event event, std::span<const TclObject> tokens, TclObject& result) |
| 277 |
{ |
| 278 |
checkNumArgs(tokens, 3, "command"); |
| 279 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 280 |
std::in_place_type_t<AfterInputEventCmd>{}, |
| 281 |
*this, std::move(event), tokens[2]); |
| 282 |
result = std::get<AfterInputEventCmd>(*ptr).getIdStr(); |
| 283 |
afterCmds.push_back(idx); |
| 284 |
} |
| 285 |
|
| 286 |
void AfterCommand::afterIdle(std::span<const TclObject> tokens, TclObject& result) |
| 287 |
{ |
| 288 |
checkNumArgs(tokens, 4, Prefix{2}, "seconds command"); |
| 289 |
MSXMotherBoard* motherBoard = reactor.getMotherBoard(); |
| 290 |
if (!motherBoard) return; |
| 291 |
double time = getTime(getInterpreter(), tokens[2]); |
| 292 |
auto [idx, ptr] = afterCmdPool.emplace( |
| 293 |
std::in_place_type_t<AfterIdleCmd>{}, |
| 294 |
motherBoard->getScheduler(), *this, tokens[3], time); |
| 295 |
result = std::get<AfterIdleCmd>(*ptr).getIdStr(); |
| 296 |
afterCmds.push_back(idx); |
| 297 |
} |
| 298 |
|
| 299 |
void AfterCommand::afterInfo(std::span<const TclObject> , TclObject& result) const |
| 300 |
{ |
| 301 |
std::string str; |
| 302 |
for (auto idx : afterCmds) { |
| 303 |
const auto& var = afterCmdPool[idx]; |
| 304 |
std::visit([&](const AfterCmd& cmd) { strAppend(str, cmd.getIdStr(), ": "); }, var); |
| 305 |
std::visit(overloaded { |
| 306 |
[&](const AfterTimeCmd& cmd ) { str += std::format("time {:.3f} ", cmd.getTime()); }, |
| 307 |
[&](const AfterIdleCmd& cmd ) { str += std::format("idle {:.3f} ", cmd.getTime()); }, |
| 308 |
[&](const AfterSimpleEventCmd& cmd ) { strAppend(str, cmd.getType(), ' '); }, |
| 309 |
[&](const AfterInputEventCmd& cmd ) { strAppend(str, toString(cmd.getEvent()), ' '); }, |
| 310 |
[&](const AfterRealTimeCmd& ) { str += "realtime "; } |
| 311 |
}, var); |
| 312 |
std::visit([&](const AfterCmd& cmd) { strAppend(str, cmd.getCommand().getString(), '\n'); }, var); |
| 313 |
} |
| 314 |
result = str; |
| 315 |
} |
| 316 |
|
| 317 |
void AfterCommand::afterCancel(std::span<const TclObject> tokens, TclObject& ) |
| 318 |
{ |
| 319 |
checkNumArgs(tokens, AtLeast{3}, "id|command"); |
| 320 |
if (tokens.size() == 3) { |
| 321 |
if (auto idStr = tokens[2].getString(); idStr.starts_with("after#")) { |
| 322 |
if (auto id = StringOp::stringTo<unsigned>(idStr.substr(6))) { |
| 323 |
auto equalId = [id = *id](Index idx) { |
| 324 |
return std::visit([&](const AfterCmd& cmd) { |
| 325 |
return cmd.getId() == id; |
| 326 |
}, afterCmdPool[idx]); |
| 327 |
}; |
| 328 |
if (auto it = std::ranges::find_if(afterCmds, equalId); |
| 329 |
it != end(afterCmds)) { |
| 330 |
auto idx = *it; |
| 331 |
afterCmds.erase(it); |
| 332 |
afterCmdPool.remove(idx); |
| 333 |
return; |
| 334 |
} |
| 335 |
} |
| 336 |
} |
| 337 |
} |
| 338 |
TclObject command; |
| 339 |
command.addListElements(std::views::drop(tokens, 2)); |
| 340 |
std::string_view cmdStr = command.getString(); |
| 341 |
auto equalCmd = [&](Index idx) { |
| 342 |
return std::visit([&](const AfterCmd& cmd) { |
| 343 |
return cmd.getCommand() == cmdStr; |
| 344 |
}, afterCmdPool[idx]); |
| 345 |
}; |
| 346 |
if (auto it = std::ranges::find_if(afterCmds, equalCmd); |
| 347 |
it != end(afterCmds)) { |
| 348 |
auto idx = *it; |
| 349 |
afterCmds.erase(it); |
| 350 |
afterCmdPool.remove(idx); |
| 351 |
|
| 352 |
|
| 353 |
|
| 354 |
|
| 355 |
return; |
| 356 |
} |
| 357 |
|
| 358 |
} |
| 359 |
|
| 360 |
std::string AfterCommand::help(std::span<const TclObject> ) const |
| 361 |
{ |
| 362 |
return "after time <seconds> <command> execute a command after some time (MSX time)\n" |
| 363 |
"after realtime <seconds> <command> execute a command after some time (realtime)\n" |
| 364 |
"after idle <seconds> <command> execute a command after some time being idle\n" |
| 365 |
"after frame <command> execute a command after a new frame is drawn\n" |
| 366 |
"after break <command> execute a command after a breakpoint is reached\n" |
| 367 |
"after boot <command> execute a command after a (re)boot\n" |
| 368 |
"after machine_switch <command> execute a command after a switch to a new machine\n" |
| 369 |
"after quit <command> execute a command after a quit event\n" |
| 370 |
"after info list all postponed commands\n" |
| 371 |
"after cancel <id> cancel the postponed command with given id\n"; |
| 372 |
} |
| 373 |
|
| 374 |
void AfterCommand::tabCompletion(std::vector<std::string>& tokens) const |
| 375 |
{ |
| 376 |
if (tokens.size() == 2) { |
| 377 |
using namespace std::literals; |
| 378 |
static constexpr std::array cmds = { |
| 379 |
"time"sv, "realtime"sv, "idle"sv, "frame"sv, "break"sv, "boot"sv, |
| 380 |
"machine_switch"sv, "quit"sv, "info"sv, "cancel"sv, |
| 381 |
}; |
| 382 |
completeString(tokens, cmds); |
| 383 |
} |
| 384 |
|
| 385 |
} |
| 386 |
|
| 387 |
|
| 388 |
void AfterCommand::executeMatches(std::predicate<Index> auto pred) |
| 389 |
{ |
| 390 |
static std::vector<Index> matches; |
| 391 |
assert(matches.empty()); |
| 392 |
|
| 393 |
|
| 394 |
|
| 395 |
auto p = partition_copy_remove(afterCmds, std::back_inserter(matches), pred); |
| 396 |
afterCmds.erase(p.second, end(afterCmds)); |
| 397 |
for (auto idx : matches) { |
| 398 |
auto delayed = std::visit([](AfterCmd& cmd) { return cmd.extractCommand(); }, |
| 399 |
afterCmdPool[idx]); |
| 400 |
afterCmdPool.remove(idx); |
| 401 |
delayed.execute(); |
| 402 |
} |
| 403 |
matches.clear(); |
| 404 |
} |
| 405 |
|
| 406 |
struct AfterSimpleEventPred { |
| 407 |
bool operator()(AfterCommand::Index idx) const { |
| 408 |
return std::visit(overloaded { |
| 409 |
[&](const AfterSimpleEventCmd& cmd) { return cmd.getTypeEnum() == type; }, |
| 410 |
[&](const AfterCmd& ) { return false; } |
| 411 |
}, afterCmdPool[idx]); |
| 412 |
} |
| 413 |
const EventType type; |
| 414 |
}; |
| 415 |
void AfterCommand::executeSimpleEvents(EventType type) |
| 416 |
{ |
| 417 |
executeMatches(AfterSimpleEventPred{type}); |
| 418 |
} |
| 419 |
|
| 420 |
struct AfterEmuTimePred { |
| 421 |
bool operator()(AfterCommand::Index idx) const { |
| 422 |
return std::visit(overloaded { |
| 423 |
[&](const AfterTimedCmd& cmd) { return cmd.getTime() == 0.0; }, |
| 424 |
[&](const AfterCmd& ) { return false; } |
| 425 |
}, afterCmdPool[idx]); |
| 426 |
} |
| 427 |
}; |
| 428 |
|
| 429 |
struct AfterInputEventPred { |
| 430 |
explicit AfterInputEventPred(const Event& event_) |
| 431 |
: event(event_) {} |
| 432 |
bool operator()(AfterCommand::Index idx) const { |
| 433 |
return std::visit(overloaded { |
| 434 |
[&](const AfterInputEventCmd& cmd) { return matches(cmd.getEvent(), event); }, |
| 435 |
[&](const AfterCmd& ) { return false; } |
| 436 |
}, afterCmdPool[idx]); |
| 437 |
} |
| 438 |
const Event& event; |
| 439 |
}; |
| 440 |
|
| 441 |
bool AfterCommand::signalEvent(const Event& event) |
| 442 |
{ |
| 443 |
std::visit(overloaded{ |
| 444 |
[&](const SimpleEvent&) { |
| 445 |
executeSimpleEvents(getType(event)); |
| 446 |
}, |
| 447 |
[&](const FinishFrameEvent&) { |
| 448 |
executeSimpleEvents(EventType::FINISH_FRAME); |
| 449 |
}, |
| 450 |
[&](const QuitEvent&) { |
| 451 |
executeSimpleEvents(EventType::QUIT); |
| 452 |
}, |
| 453 |
[&](const AfterTimedEvent&) { |
| 454 |
executeMatches(AfterEmuTimePred()); |
| 455 |
}, |
| 456 |
[&](const EventBase&) { |
| 457 |
executeMatches(AfterInputEventPred(event)); |
| 458 |
for (auto idx : afterCmds) { |
| 459 |
std::visit(overloaded { |
| 460 |
[](AfterIdleCmd& cmd) { cmd.reschedule(); }, |
| 461 |
[](const AfterCmd& ) { } |
| 462 |
}, afterCmdPool[idx]); |
| 463 |
} |
| 464 |
} |
| 465 |
}, event); |
| 466 |
return false; |
| 467 |
} |
| 468 |
|
| 469 |
|
| 470 |
|
| 471 |
|
| 472 |
AfterCmd::AfterCmd(AfterCommand& afterCommand_, TclObject command_) |
| 473 |
: afterCommand(afterCommand_), command(std::move(command_)), id(++lastAfterId) |
| 474 |
{ |
| 475 |
} |
| 476 |
|
| 477 |
DelayedCommand AfterCmd::extractCommand() |
| 478 |
{ |
| 479 |
return DelayedCommand{.command = std::move(command), .afterCommand = afterCommand}; |
| 480 |
} |
| 481 |
|
| 482 |
AfterCommand::Index AfterCmd::removeSelf() |
| 483 |
{ |
| 484 |
auto equalThis = [&](AfterCommand::Index idx) { |
| 485 |
return std::visit([&](const AfterCmd& cmd) { return &cmd == this; }, |
| 486 |
afterCmdPool[idx]); |
| 487 |
}; |
| 488 |
auto it = rfind_if_unguarded(afterCommand.afterCmds, equalThis); |
| 489 |
auto idx = *it; |
| 490 |
afterCommand.afterCmds.erase(it); |
| 491 |
return idx; |
| 492 |
} |
| 493 |
|
| 494 |
|
| 495 |
|
| 496 |
|
| 497 |
AfterTimedCmd::AfterTimedCmd( |
| 498 |
Scheduler& scheduler_, |
| 499 |
AfterCommand& afterCommand_, |
| 500 |
TclObject command_, double time_) |
| 501 |
: AfterCmd(afterCommand_, std::move(command_)) |
| 502 |
, Schedulable(scheduler_) |
| 503 |
, time(time_) |
| 504 |
{ |
| 505 |
reschedule(); |
| 506 |
} |
| 507 |
|
| 508 |
double AfterTimedCmd::getTime() const |
| 509 |
{ |
| 510 |
return time; |
| 511 |
} |
| 512 |
|
| 513 |
void AfterTimedCmd::reschedule() |
| 514 |
{ |
| 515 |
removeSyncPoint(); |
| 516 |
setSyncPoint(getCurrentTime() + EmuDuration::sec(time)); |
| 517 |
} |
| 518 |
|
| 519 |
void AfterTimedCmd::executeUntil(EmuTime ) |
| 520 |
{ |
| 521 |
time = 0.0; |
| 522 |
afterCommand.eventDistributor.distributeEvent(AfterTimedEvent()); |
| 523 |
} |
| 524 |
|
| 525 |
void AfterTimedCmd::schedulerDeleted() |
| 526 |
{ |
| 527 |
auto idx = removeSelf(); |
| 528 |
afterCmdPool.remove(idx); |
| 529 |
} |
| 530 |
|
| 531 |
|
| 532 |
|
| 533 |
|
| 534 |
AfterTimeCmd::AfterTimeCmd( |
| 535 |
Scheduler& scheduler_, |
| 536 |
AfterCommand& afterCommand_, |
| 537 |
TclObject command_, double time_) |
| 538 |
: AfterTimedCmd(scheduler_, afterCommand_, std::move(command_), time_) |
| 539 |
{ |
| 540 |
} |
| 541 |
|
| 542 |
|
| 543 |
|
| 544 |
|
| 545 |
AfterIdleCmd::AfterIdleCmd( |
| 546 |
Scheduler& scheduler_, |
| 547 |
AfterCommand& afterCommand_, |
| 548 |
TclObject command_, double time_) |
| 549 |
: AfterTimedCmd(scheduler_, afterCommand_, std::move(command_), time_) |
| 550 |
{ |
| 551 |
} |
| 552 |
|
| 553 |
|
| 554 |
|
| 555 |
|
| 556 |
AfterSimpleEventCmd::AfterSimpleEventCmd( |
| 557 |
AfterCommand& afterCommand_, TclObject command_, |
| 558 |
EventType type_) |
| 559 |
: AfterCmd(afterCommand_, std::move(command_)), type(type_) |
| 560 |
{ |
| 561 |
} |
| 562 |
|
| 563 |
std::string_view AfterSimpleEventCmd::getType() const |
| 564 |
{ |
| 565 |
switch (type) { |
| 566 |
using enum EventType; |
| 567 |
case FINISH_FRAME: return "frame"; |
| 568 |
case BREAK: return "break"; |
| 569 |
case BOOT: return "boot"; |
| 570 |
case QUIT: return "quit"; |
| 571 |
case MACHINE_LOADED: return "machine_switch"; |
| 572 |
default: UNREACHABLE; |
| 573 |
} |
| 574 |
} |
| 575 |
|
| 576 |
|
| 577 |
|
| 578 |
|
| 579 |
AfterInputEventCmd::AfterInputEventCmd( |
| 580 |
AfterCommand& afterCommand_, |
| 581 |
Event event_, |
| 582 |
TclObject command_) |
| 583 |
: AfterCmd(afterCommand_, std::move(command_)) |
| 584 |
, event(std::move(event_)) |
| 585 |
{ |
| 586 |
} |
| 587 |
|
| 588 |
|
| 589 |
|
| 590 |
|
| 591 |
AfterRealTimeCmd::AfterRealTimeCmd( |
| 592 |
RTScheduler& rtScheduler, AfterCommand& afterCommand_, |
| 593 |
TclObject command_, double time) |
| 594 |
: AfterCmd(afterCommand_, std::move(command_)) |
| 595 |
, RTSchedulable(rtScheduler) |
| 596 |
{ |
| 597 |
scheduleRT(uint64_t(time * 1e6)); |
| 598 |
} |
| 599 |
|
| 600 |
void AfterRealTimeCmd::executeRT() |
| 601 |
{ |
| 602 |
|
| 603 |
|
| 604 |
|
| 605 |
auto idx = removeSelf(); |
| 606 |
auto delayed = extractCommand(); |
| 607 |
afterCmdPool.remove(idx); |
| 608 |
delayed.execute(); |
| 609 |
} |
| 610 |
|
| 611 |
} |