| 1376 | |
| 1377 | |
| 1378 | ResultType Script::ExitApp(ExitReasons aExitReason, int aExitCode) |
| 1379 | // Normal exit (if aBuf is NULL), or a way to exit immediately on error (which is mostly |
| 1380 | // for times when it would be unsafe to call MsgBox() due to the possibility that it would |
| 1381 | // make the situation even worse). |
| 1382 | { |
| 1383 | mExitReason = aExitReason; |
| 1384 | // Note that currently, mOnExit.Count() can only be non-zero if the script is in a runnable |
| 1385 | // state (since registering an OnExit function requires that the script calls OnExit()). |
| 1386 | // If this ever changes, the !mIsReadyToExecute condition should be added below: |
| 1387 | if (!mOnExit.Count() || g_OnExitIsRunning) |
| 1388 | { |
| 1389 | // In the case of g_OnExitIsRunning == true: |
| 1390 | // There is another instance of this function beneath us on the stack. Since we have |
| 1391 | // been called, this is a true exit condition and we exit immediately. |
| 1392 | // MUST NOT create a new thread when g_OnExitIsRunning because g_array allows only one |
| 1393 | // extra thread for ExitApp() (which allows it to run even when MAX_THREADS_EMERGENCY has |
| 1394 | // been reached). See TOTAL_ADDITIONAL_THREADS. |
| 1395 | TerminateApp(aExitReason, aExitCode); |
| 1396 | } |
| 1397 | |
| 1398 | // Otherwise, the script contains the special OnExit function that we will run here instead |
| 1399 | // of exiting. And since it does, we know that the script is in a ready-to-execute state |
| 1400 | // because that is the only way an OnExit function could have been defined in the first place. |
| 1401 | // The OnExit function may return true in order to abort the Exit sequence (e.g. it could |
| 1402 | // display an "Are you sure?" prompt, and if the user chooses "No", it returns true, letting |
| 1403 | // the thread we create below end normally). |
| 1404 | |
| 1405 | // Next, save the current state of the globals so that they can be restored just prior |
| 1406 | // to returning to our caller: |
| 1407 | InitNewThread(0, true, true); // Uninterruptibility is handled below. Since this special thread should always run, no checking of g_MaxThreadsTotal is done before calling this. |
| 1408 | |
| 1409 | // Turn on uninterruptibility to forbid any hotkeys, timers, or user defined menu items |
| 1410 | // to interrupt. This is mainly done for peace-of-mind (since possible interactions due to |
| 1411 | // interruptions have not been studied) and the fact that this most users would not want this |
| 1412 | // subroutine to be interruptible (it usually runs quickly anyway). Another reason to make |
| 1413 | // it non-interruptible is that some OnExit functions might destruct things used by the |
| 1414 | // script's hotkeys/timers/menu items, and activating these items during the deconstruction |
| 1415 | // would not be safe. Finally, if a logoff or shutdown is occurring, it seems best to prevent |
| 1416 | // timed subroutines from running -- which might take too much time and prevent the exit from |
| 1417 | // occurring in a timely fashion. An option can be added via the FutureUse param to make it |
| 1418 | // interruptible if there is ever a demand for that. |
| 1419 | // UPDATE: g_AllowInterruption is now used instead of g->AllowThreadToBeInterrupted for two reasons: |
| 1420 | // 1) It avoids the need to do "int mUninterruptedLineCountMax_prev = g_script.mUninterruptedLineCountMax;" |
| 1421 | // (Disable this item so that ExecUntil() won't automatically make our new thread uninterruptible |
| 1422 | // after it has executed a certain number of lines). |
| 1423 | // 2) Mostly obsolete: If the thread we're interrupting is uninterruptible, the uninterruptible timer |
| 1424 | // might be currently pending. When it fires, it would make the OnExit function interruptible |
| 1425 | // rather than the underlying subroutine. The above fixes the first part of that problem. |
| 1426 | // The 2nd part is fixed by reinstating the timer when the uninterruptible thread is resumed. |
| 1427 | // This special handling is only necessary here -- not in other places where new threads are |
| 1428 | // created -- because OnExit is the only type of thread that can interrupt an uninterruptible |
| 1429 | // thread. |
| 1430 | BOOL g_AllowInterruption_prev = g_AllowInterruption; // Save current setting. |
| 1431 | g_AllowInterruption = FALSE; // Mark the thread just created above as permanently uninterruptible (i.e. until it finishes and is destroyed). |
| 1432 | |
| 1433 | g_OnExitIsRunning = true; |
| 1434 | DEBUGGER_STACK_PUSH(_T("OnExit")) |
| 1435 |
no test coverage detected