Why does my Windows Console Close Event Handler time out? - c++

I build the following program in VS2017/Windows 10. When I run it, I hit close and ctrl_handler() is called as expected, but after ~three seconds the process is forcefully terminated anyway.
This is a problem because my real application writes large log files and three seconds is not long enough to get them onto disk.
Where is the documentation that describes this behaviour? Its not in those for the CTRL+CLOSE signal.
Where is the timeout set? Can it be modified at the application level? Or with a group policy?
#include <Windows.h>
bool mainThreadRunning;
bool mainThreadFinished;
BOOL ctrl_handler(DWORD event)
{
if (event == CTRL_CLOSE_EVENT) {
mainThreadRunning = false;
while (!mainThreadFinished) {
Sleep(100);
}
return TRUE;
}
return FALSE;
}
int main()
{
mainThreadRunning = true;
mainThreadFinished = false;
SetConsoleCtrlHandler((PHANDLER_ROUTINE)(ctrl_handler), TRUE); // make sure when the user hits the close button in the console we shut down cleanly
while (true)
{
}
return 0;
}

I suppose this is the reference you were looking for:
Unfortunately, this is determined by the OS. There is documentation describing the behavior in the HandlerRoutine Callback docs:
" In this case, no other handler functions are called, and the system displays a pop-up dialog box that asks the user whether to terminate the process. The system also displays this dialog box if the process does not respond within a certain time-out period (5 seconds for CTRL_CLOSE_EVENT, and 20 seconds for CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT)."
There is no (at least public, documented) API to change this timeout.
Note:
A process can use the SetProcessShutdownParameters function to prevent the system from displaying a dialog box to the user during logoff or shutdown. In this case,the system terminates the process when HandlerRoutine returns TRUE or when the time-out period elapses.
The operating system intentionally forces termination if it considers handler is taking too much time to complete.
Important note pulled from comments below:
... Ctrl+C is not subject to the time-out (I've tested it, and that's what I am using now).

Related

Qt Process Events processing for longer than specified

I've hit a bit of an issue and I'm not sure what to make of it.
I'm running Qt 4.8.6, Qt creator 3.3.2, environment in Ubuntu 12.04 cross compiling to a Beaglebone Black running Debian 7 kernel 3.8.13.
The issue that I'm seeing is that this code:
if (qApp->hasPendingEvents())
{
qDebug() << "pending events";
}
qApp->processEvents(QEventLoop::AllEvents, 10);
does not function as it should according to (at least my interpretation of) the Qt documentation. I would expect the process events loop to function for AT MOST the 10 milliseconds specified.
What happens is the qDebug statement is never printed. I would then expect that there are therefore no events to be processed, and the process events statement goes in and out very quickly. Most of the time this is the case.
What happens (not every time, but often enough) the qDebug statement is skipped, and the processEvents statement executes for somewhere between 1 and 2 seconds.
Is there some way that I can dig into what is happening in the process events and find out what is causing the delay?
Qt is processing events for longer than specified for QApplication::processEvents call on Linux
system. Is there some way that I can dig into what is happening in the
process events and find out what is causing the delay?
Yes, observing Qt source code may help. The source code is in /home/myname/software/Qt/5.5/Src/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp or maybe somewhere around that:
bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherUNIX);
d->interrupt.store(0);
// we are awake, broadcast it
emit awake();
// This statement implies forcing events from system event queue
// to be processed now with doSelect below
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
int nevents = 0;
const bool canWait = (d->threadData->canWaitLocked()
&& !d->interrupt.load()
&& (flags & QEventLoop::WaitForMoreEvents));
if (canWait)
emit aboutToBlock();
if (!d->interrupt.load()) {
// return the maximum time we can wait for an event.
timespec *tm = 0;
timespec wait_tm = { 0l, 0l };
if (!(flags & QEventLoop::X11ExcludeTimers)) {
if (d->timerList.timerWait(wait_tm))
tm = &wait_tm;
}
if (!canWait) {
if (!tm)
tm = &wait_tm;
// no time to wait
tm->tv_sec = 0l;
tm->tv_nsec = 0l;
}
// runs actual event loop with POSIX select
nevents = d->doSelect(flags, tm);
It seems there system posted events that are not accounted for qApp->hasPendingEvents(). And then QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); flushes those events to be processed by d->doSelect. If I was solving this task I would try to either flush those posted events out or maybe realize if and why flags parameter has QEventLoop::WaitForMoreEvents bit set. I usually either build Qt from source code or provide debugger with the path to its symbols/source so it is possible to dig in there.
P.S. I glanced at Qt 5.5.1 source event processing code but that should be very similar to what you deal with. Or could that implementation actually be bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)? It is easy to find on an actual system.

How to properly handle SIGBREAK when closing console?

I have to catch the click on close button of console event, which corresponds to ctrl-break event SIGBREAK but apparently there is a kind of timeout which does not allows me to do anything longer than 5 seconds, after what program seems to be aborted (so the message "Properly ended !" will never happend).
How can I force the system to perform closing operations until the end (or to extend the timeout to 60 seconds) ?
Note: with the same method, I can successfully handle CTRL+C event (SIGINT) using fflush(stdout); just before doStuffs();
Note 2: my code is based on this answer: https://stackoverflow.com/a/181594/1529139
#include <csignal>
void foo(int sig)
{
signal(sig, foo); // (reset for next signal)
// do stuffs which takes aboutly 15 seconds
doStuffs();
cout << "Properly ended !";
}
int main(DWORD argc, LPWSTR *argv)
{
signal(SIGBREAK, foo);
myProgramLoop();
}
I believe the timeout is fixed and there is no way to modify it, see API reference:
The system also displays the dialog box if the process does not respond within a certain time-out period (5 seconds for CTRL_CLOSE_EVENT, and 20 seconds for CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT).
A process can use the SetProcessShutdownParameters function to prevent the CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT dialog box from being displayed. In this case, the system just terminates the process when a HandlerRoutine returns TRUE or when the time-out period elapses.
How about an alternative approach, just disable the close button of your console window:
GUITHREADINFO info = {0};
info.cbSize=sizeof(info);
GetGUIThreadInfo(NULL, &info);
HMENU hSysMenu = GetSystemMenu(info.hwndActive, FALSE);
EnableMenuItem(hSysMenu, SC_CLOSE, MF_GRAYED);
Now you can safely handling closing through Ctrl-C or other keyboard input instead.

WaitForSingleObject times out too fast

I have this piece of code in a secondary thread:
DWORD result = WaitForSingleObject(myhandle,10000);
if(result == WAIT_OBJECT_0){
AfxMessageBox(_T(...));
}
else if(result == WAIT_TIMEOUT){
AfxMessageBox(_T("Timeout"));
}
Sometimes, not always, the timeout will get called almost as soon as the WaitForSingleObject is called (not even 1s delay).
Am I doing something wrong ? Any suggestions for more stable alternatives ?
EDIT:
myhandle is created inside a class constructor as:
myhandle = CreateEvent(NULL,FALSE,FALSE,_T("myhandle"));
it would get called by another function:
SetEvent(myhandle);
The point is it works when I do the SetEvent, the problem is that it sometimes times out as soon as the WaitForSingleObject is called, even though it should wait 10s.
Do you really need/want a named event? Typically this is only required for inter-process concurrency control.
If you have multiple instances of this class they will all use the same event - see the docs for CreateEvent about calling for a named object that already exists.
It may be that all you need to do is remove the name here. This allows each class instance to have its own Event object and behaviour should be more predictable.
WaitForSingleObject will not wait the whole 10 seconds. It will wait for the first of:
The timeout value is elapsed
The event is signaled
The handle becomes invalid (closed in another thread)
If the event is set when you call WaitForSingleObject, condition #2 is true from the start and WaitForSingleObject returns immediatly.
If you want to always wait 10 seconds, you should use code like this :
//Always wait 10 seconds
Sleep(10000);
//Test the event without waiting
if(WaitForSingleObject(myhandle, 0) == WAIT_OBJECT_0) {
AfxMessageBox(_T("Event was set in the last 10 secondes"));
} else {
AfxMessageBox(_T("Timeout"));
}
Took awhile but the problem actually was that the program sometimes did multiple calls to WaitForSingleObject. So it's a previous call that is timing out.
Solution is to use WaitForMultipleObjects and set a cancelling event in the case it is known that the first event won't be set, so the timer is cancelled before is it re-invoked.

How to put a time limit on user input?

I have tried various setups with input and my one second timer but nothing is working. The entire code is brought to a halt when it reaches the part asking for input. I have an unbuffered stream, so I don't need to press enter to send the input. Also the purpose of this is for a pac-man game I'm designing for terminal use. What I want is basically to have a one second interval where the user can enter a command. If no command is entered, I want the pac-man to continue moving the direction it was moving the last time a command was entered.
EDIT:
time_t startTime, curTime;
time(&startTime);
do
{
input=getchar();
time(&curTime);
} while((curTime - startTime) < 1);
You could try using alarm() (or similar timer function) to throw and have your application catch a SIGALRM, though this is definitely overkill for PacMac. Consider using a separate thread (POSIX thread) to control a timer.
On Unix, you can simply use select or poll with a timeout on the standard input file descriptor (STDIN_FILENO, or fileno(stdin)). I would not bring in mouse traps built of signals and threads just for this.
My gut feeling tells me this:
Have one thread dedicated to processing user input and putting key events into a queue
The timer-activated thread, on every activation, consumes all key events in the queue, using the one that happened last, at the point of thread activation.
Make sure your access to the queue is synchronized.
// I/O Thread:
while (!stop) {
input = getchar();
lock_queue();
queue.push_back(input);
unlock_queue();
}
// Timer Thread:
while (!stop) {
lock_queue();
if (queue.size() == 0) {
action = DEFAULT_ACTION;
} else {
// either handle multiple key events somehow
// or use the last key event:
action = queue.back();
queue.clear();
}
unlock_queue();
perform_action(action);
sleep();
}
Full example posted as a Github Gist.
You could use a non-blocking input function such as getch() but it isn't very cross platform compatible.
Ideally you should be using events to update the game state, depending on which OS you are targeting you could use the OS events for key press or maybe a library such as SDL.

SetConsoleCtrlHandler routine issue

I'm writting a console application in C++.
I use SetConsoleCtrlHandler to trap close and CTRL+C button. This allows for all my threads to stop and exit properly.
One of the thread performs some saving that require some time to complete and I have some code to wait in the console crtl handle routine. MSDN specify that a box should pop up after 5 seconds for CTRL_CLOSE_EVENT, but instead my process exits.
This is annoying for debugging console application too as the process exits before you can step through and I don't know what may be the problem (I have Windows 7 64bits).
Also, strangely if my routine returns TRUE (to simply disable the close action), it still closes the application. The routine does get called, so the SetConsoleCtrlHandler was successful installed.
e.g.:
BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_CLOSE_EVENT)
{
return TRUE;
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
BOOL ret = SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
while (true)
{
Sleep(1000);
}
return 0;
}
Any ideas?
It looks like you can no longer ignore close requests on Windows 7.
You do get the CTRL_CLOSE_EVENT event though, and from that moment on, you get 10 seconds to do whatever you need to do before it auto-closes. So you can either do whatever work you need to do in the handler or set a global flag.
case CTRL_CLOSE_EVENT: // CTRL-CLOSE: confirm that the user wants to exit.
close_flag = 1;
while(close_flag != 2)
Sleep(100);
return TRUE;
Fun fact: While the code in your CTRL_CLOSE_EVENT event runs, the main program keeps on running. So you'll be able to check for the flag and do a 'close_flag = 2;' somewhere. But remember, you only have 10 seconds. (So keep in mind you don't want to hang up your main program flow waiting on keyboard input for example.)
I suspect that this is by-design on Windows 7 - if the user wants to quit your application, you're not allowed to tell him "No".
There is no need to wait for any flag from the main thread, the handler terminates as soon as the main thread exits (or after 10s).
BOOL WINAPI ConsoleHandler(DWORD dwType)
{
switch(dwType) {
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
set_done();//signal the main thread to terminate
//Returning would make the process exit!
//We just make the handler sleep until the main thread exits,
//or until the maximum execution time for this handler is reached.
Sleep(10000);
return TRUE;
default:
break;
}
return FALSE;
}
Xavier's comment is slightly wrong.
Windows 7 allows your code in the event handler ~10 seconds. If you haven't exited the event handler in 10 seconds you are terminated. If you exit the event handler you are terminated immediately. Returning TRUE does not post a dialog. It just exits.
You're making this more complicated than it needs to be. I don't know exactly why your app is closing, but SetConsoleCtrlHandler(NULL, TRUE) should do what you want:
http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspx
If the HandlerRoutine parameter is NULL, a TRUE value causes the calling process to ignore CTRL+C input, and a FALSE value restores normal processing of CTRL+C input.