MCPcopy Create free account
hub / github.com/AutoHotkey/AutoHotkey / CheckScriptTimers

Function CheckScriptTimers

source/application.cpp:1492–1642  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1490
1491
1492bool CheckScriptTimers()
1493// Returns true if it launched at least one thread, and false otherwise.
1494// It's best to call this function only directly from MsgSleep() or when there is an instance of
1495// MsgSleep() closer on the call stack than the nearest dialog's message pump (e.g. MsgBox).
1496// This is because threads some events might get queued up for our thread during the execution
1497// of the timer subroutines here. When those subroutines finish, if we return directly to a dialog's
1498// message pump, and such pending messages might be discarded or mishandled.
1499// Caller should already have checked the value of g_script.mTimerEnabledCount to ensure it's
1500// greater than zero, since we don't check that here (for performance).
1501// This function will go through the list of timed subroutines only once and then return to its caller.
1502// It does it only once so that it won't keep a thread beneath it permanently suspended if the sum
1503// total of all timer durations is too large to be run at their specified frequencies.
1504// This function is allowed to be called recursively, which handles certain situations better:
1505// 1) A hotkey subroutine interrupted and "buried" one of the timer subroutines in the stack.
1506// In this case, we don't want all the timers blocked just because that one is, so recursive
1507// calls from ExecUntil() are allowed, and they might discover other timers to run.
1508// 2) If the script is idle but one of the timers winds up taking a long time to execute (perhaps
1509// it gets stuck in a long WinWait), we want a recursive call (from MsgSleep() in this example)
1510// to launch any other enabled timers concurrently with the first, so that they're not neglected
1511// just because one of the timers happens to be long-running.
1512// Of course, it's up to the user to design timers so that they don't cause problems when they
1513// interrupted hotkey subroutines, or when they themselves are interrupted by hotkey subroutines
1514// or other timer subroutines.
1515{
1516 // When the following is true, such as during a SendKeys() operation, it seems best not to launch any
1517 // new timed subroutines. The reasons for this are similar to the reasons for not allowing hotkeys
1518 // to fire during such times. Those reasons are discussed in other comments. In addition,
1519 // it seems best as a policy not to allow timed subroutines to run while the script's current
1520 // quasi-thread is paused. Doing so would make the tray icon flicker (were it even updated below,
1521 // which it currently isn't) and in any case is probably not what the user would want. Most of the
1522 // time, the user would want all timed subroutines stopped while the current thread is paused.
1523 // And even if this weren't true, the confusion caused by the subroutines still running even when
1524 // the current thread is paused isn't worth defaulting to the opposite approach. In the future,
1525 // and if there's demand, perhaps a config option can added that allows a different default behavior.
1526 // UPDATE: It seems slightly better (more consistent) to disallow all timed subroutines whenever
1527 // there is even one paused thread anywhere in the "stack".
1528 // v1.0.48: Since g_IdleIsPaused was removed (to simplify a lot of things), g_nPausedThreads now
1529 // counts the idle thread if it's paused. Also, to avoid array overflow, g_MaxThreadsTotal must not
1530 // be exceeded except where otherwise documented.
1531 // v2.0: g->AllowTimers is ignored when !g_nThreads so that its value can be retained for use as
1532 // the default for new threads, after the auto-execute thread finishes.
1533 if (g_nPausedThreads > 0 || (!g->AllowTimers && g_nThreads) || g_nThreads >= g_MaxThreadsTotal || !IsInterruptible()) // See above.
1534 return false;
1535
1536 ScriptTimer *ptimer, *next_timer;
1537 BOOL at_least_one_timer_launched;
1538 DWORD tick_start;
1539
1540 // Note: It seems inconsequential if a subroutine that the below loop executes causes a
1541 // new timer to be added to the linked list while the loop is still enumerating the timers.
1542
1543 for (at_least_one_timer_launched = FALSE, ptimer = g_script.mFirstTimer
1544 ; ptimer != NULL
1545 ; ptimer = next_timer)
1546 {
1547 ScriptTimer &timer = *ptimer; // For performance and convenience.
1548 if (!timer.mEnabled || timer.mExistingThreads > 0 || timer.mPriority < g->Priority) // thread priorities
1549 {

Callers

nothing calls this directly

Calls 7

IsInterruptibleFunction · 0.85
InitNewThreadFunction · 0.85
ResumeUnderlyingThreadFunction · 0.85
ExecuteInNewThreadMethod · 0.80
DeleteTimerMethod · 0.80
DisableMethod · 0.45
ToObjectMethod · 0.45

Tested by

no test coverage detected