program calling Sleep doesn't wakup on signals - winapi

In Linux when an executing thread calling 'sleep' suspends its execution. As soon as a signal is sent to the process the 'sleep' function returns immediately. I can install my signal handler and set the flag below properly to exit the while loop.
// a signal handler set 'flag' on CTRL-C
while(flag) {
sleep(10); // returns on signal caught
}
In Windows I cannot see that. I am using 'Sleep(DWORD milliseconds)' and I have installed my signal handler using 'signal' function. Essentially the sleeping threads resumes only at the end of 'Sleep'.
What do I have to do to allow 'Sleep' to return before hand in my code?
Am I using the right approach (using a flag to exit the while loop) or do I have to look at something else?

You should be using an event object.
Replace your loop with a call to WaitForSingleObject, and have the control-C handler call SetEvent.
(Of course, in practice it is unlikely that you really want your program to sit and wait, doing nothing, until the user presses control-C. But that's the scenario the question presents, and this answer gives you a starting point for more realistic scenarios.)

Related

Why is "kill" is not exiting a thread immediately?

I am trying to write a simple script that spawns a thread that performs a task that may timeout. (For the sake of writing a simple example for StackOverflow I replaced the actual process with a sleep command).
This program spawns a thread and then uses a cond_timedwait to monitor the thread and check if it has timed out. If a timeout occurs it calls the kill method on the thread with a "STOP" signal to notify the thread that it should exit.
use strict;
use threads;
use threads::shared;
use warnings;
my $var :shared;
my $thread = threads->create(sub {
# Tell the thread how to handle the STOP signal
local $SIG{'STOP'} = sub {
print "Stop signal received\n";
threads->exit();
};
# Perform a process that takes some time
sleep 10;
# Signal that the thread is complete
lock($var); cond_signal($var);
});
# Current time + 1 second
my $wait_time = time() + 1;
my $timeout;
{
# Wait for the thread to complete or until a timeout has occurred
lock($var); $timeout = !cond_timedwait($var, $wait_time);
}
# Check if a timeout occurred
if ($timeout) {
print "A timeout has occurred\n";
# Signal the thread to stop
$thread->kill('STOP')->join();
}
else {
$thread->join();
}
This code runs successfully and prints the following output:
1 second passes...
A timeout has occurred
9 seconds pass...
Stop signal received
The problem is, even though a timeout is detected and the "STOP" signal is sent to the thread, the program still seems to be waiting the full 10 seconds before printing "Stop signal received" and exiting.
I tried changing it so it calls detach instead of join after killing the thread, but then the "Stop signal received" message is never printed which means the program is exiting before the thread cleanly exits. I want to make sure the thread is actually interrupted and exits, because in the real program I will want to kill and retry the process after the timeout has occurred and the process won't work if there is another instance already running on a detached thread.
How can I make it so the thread instantly prints the message and exits when it receives the "STOP" signal?
These "signals" aren't the actual OS signals, and there are operations they won't interrupt
CAVEAT: The thread signalling capability provided by this module does not actually send signals via the OS. It emulates signals at the Perl-level such that signal handlers are called in the appropriate thread. For example, sending $thr->kill('STOP') does not actually suspend a thread (or the whole process), but does cause a $SIG{'STOP'} handler to be called in that thread (as illustrated above).
...
Correspondingly, sending a signal to a thread does not disrupt the operation the thread is currently working on: The signal will be acted upon after the current operation has completed. For instance, if the thread is stuck on an I/O call, sending it a signal will not cause the I/O call to be interrupted such that the signal is acted up immediately.
The granularity of what the "operation" is isn't stated but sleep is clearly uninterruptable so the signal handler runs only after it completes. With a different job to interrupt
use warnings;
use strict;
use feature 'say';
use threads;
say "Start at ", scalar localtime, " (", time, ")";
my $thread = threads->create(sub {
# Tell the thread how to handle the STOP signal
$SIG{'STOP'} = sub {
say "\tStop signal received. Exiting at ", time;
threads->exit();
};
say "\tIn the thread ", threads->tid;
# Perform a process that takes some time
#sleep 10;
do { sleep 1; say "\tnappin'... ($_ sec)" } for 1..10;
});
sleep 3;
$thread->kill('STOP')->join(); # works differently with detach()
say "Main thread done, exiting at ", time;
Output
Start at Thu Jul 7 11:11:27 2022 (1657217487)
In the thread 1
nappin'... (1 sec)
nappin'... (2 sec)
Stop signal received. Exiting at 1657217490
Main thread done, exiting at 1657217490
With detach instead of join it still stops that loop at the right time but I see no indication that a signal handler ran. (In my tests I have the signal handler also write a file and with detach it doesn't.) It all works the same for me with a shared variable etc, like in the question.
This sleep doesn't matter of course -- but it is all a warning to carefully test with actual jobs that the signal is aimed to stop.
Signals can only be sent to processes. As such, $thread->kill('STOP') can't possibly be sending an actual signal. As such, nothing interrupts sleep.
Between each statement, Perl checks if a "signal" came in. If it has, it handles it. So the "signal" is only handled once sleep completes.
If you had ten one second sleeps instead of one ten second sleep, the wait would be at most one second.

How to check if a process started in the background still running?

It looks like if you create a subprocess via exec.Cmd and Start() it, the Cmd.Process field is populated right away, however Cmd.ProcessState field remains nil until the process exits.
// ProcessState contains information about an exited process,
// available after a call to Wait or Run.
ProcessState *os.ProcessState
So it looks like I can't actually check the status of a process I Start()ed while it's still running?
It makes no sense to me ProcessState is set when the process exits. There's an ProcessState.Exited() method which will always return true in this case.
So I tried to go this route instead: cmd.Process.Pid field exists right after I cmd.Start(), however it looks like os.Process doesn't expose any mechanisms to check if the process is running.
os.FindProcess says:
On Unix systems, FindProcess always succeeds and returns a Process for the given pid, regardless of whether the process exists.
which isn't useful –and it seems like there's no way to go from os.Process to an os.ProcessState unless you .Wait() which defeats the whole purpose (I want to know if the process is running or not before it has exited).
I think you have two reasonable options here:
Spin off a goroutine that waits for the process to exit. When the wait is done, you know the process exited. (Positive: pretty easy to code correctly; negative: you dedicate an OS thread to waiting.)
Use syscall.Wait4() on the published Pid. A Wait4 with syscall.WNOHANG set returns immediately, filling in the status.
It might be nice if there were an exported os or cmd function that did the Wait4 for you and filled in the ProcessState. You could supply WNOHANG or not, as you see fit. But there isn't.
The point of ProcessState.Exited() is to distinguish between all the various possibilities, including:
process exited normally (with a status byte)
process died due to receiving an unhandled signal
See the stringer for ProcessState. Note that there are more possibilities than these two ... only there seems to be no way to get the others into a ProcessState. The only calls to syscall.Wait seem to be:
syscall/exec_unix.go: after a failed exec, to collect zombies before returning an error; and
os/exec_unix.go: after a call to p.blockUntilWaitable().
If it were not for the blockUntilWaitable, the exec_unix.go implementation variant for wait() could call syscall.Wait4 with syscall.WNOHANG, but blockUntilWaitable itself ensures that this is pointless (and the goal of this particular wait is to wait for exit anyway).

Is waiting for an event subject to spurious wakeups?

The MSDN page for SleepConditionVariableCS states that
Condition variables are subject to spurious wakeups (those not
associated with an explicit wake) and stolen wakeups (another thread
manages to run before the woken thread). Therefore, you should recheck
a predicate (typically in a while loop) after a sleep operation
returns.
As a result the conditional wait has to be enclosed in a while loop i.e.
while (check_predicate())
{
SleepConditionVariableCS(...)
}
If I were to use events instead of Conditional Variables can I do away with the while loop while waiting (WaitForSingleObject) for the event to be signaled?
For WaitForSingleObject(), there are no spurious wakeups, so you can eliminate the loop.
If you use WaitForMultipleObjectsEx() with bAlertable=TRUE, MsgWaitForMultipleObjects() with a wake mask, or MsgWaitForMultipleObjectsEx() with bAlertable=TRUE or a wake mask, then the wait can end on other conditions before the event is actually signaled.

WaitForSingleObject returning ERROR_IO_PENDING

Does anyone know why WaitForSingleObject() or WaitForMultipleObjects() would return ERROR_IO_PENDING where the object i'm waiting on is an event created with CreateEvent()?
In my testing i've tried WFSO and WFMO, manual and auto, INFINITE and 5000, and as soon as I call WaitFor* I get immediately back ERROR_IO_PENDING.
What on earth can be pending about an event object? The point of them is that you wait on them. This event is not part of an OVERLAPPED and nothing to do with an IO call. It is just being used as a one-shot flag for my worker thread to exit (which is SetEvent()ed by another thread).
So - question is - ERROR_IO_PENDING coming back from WFSO - and ideas?
Rich

Is there a way to sleep unless a message is received?

I'm working in a service whose main loop looks like this:
while (fServer.ServerState = ssStarted) and (Self.Terminated = false) do
begin
Self.ServiceThread.ProcessRequests(false);
ProcessFiles;
Sleep(3000);
end;
ProcessRequests is a lot like Application.ProcessMessages. I can't pass true to it because if I do then it blocks until a message is received from Windows, and ProcessFiles won't run, and it has to run continually. The Sleep is there to keep the CPU usage down.
This works just fine until I try to shut down the service from Windows's service management list. When I hit Stop, it sends a message and expects to get a response almost immediately, and if it's in the middle of that Sleep command, Windows will give me an error that the service didn't respond to the Stop command.
So what I need is to say "Sleep for 3000 or until you receive a message, whichever comes first." I'm sure there's an API for that, but I'm not sure what it is. Does anyone know?
This kind of stuff is hard to get right, so I usually start at the API documentation at MSDN.
The WaitForSingleObject documention specifically directs to MsgWaitForMultipleObjects for these kinds of situations:
Use caution when calling the wait
functions and code that directly or
indirectly creates windows. If a
thread creates any windows, it must
process messages. Message broadcasts
are sent to all windows in the system.
A thread that uses a wait function
with no time-out interval may cause
the system to become deadlocked. Two
examples of code that indirectly
creates windows are DDE and the
CoInitialize function. Therefore, if
you have a thread that creates
windows, use MsgWaitForMultipleObjects
or MsgWaitForMultipleObjectsEx, rather
than WaitForSingleObject.
In MsgWaitForMultipleObjects, you have a dwWakeMask parameter specifying on which queued messages to return, and a table describing the masks you can use.
Edit because of comment by Warren P:
If your main loop can be continued because of a ReadFileEx, WriteFileEx or QueueUserAPC, then you can use SleepEx.
--jeroen
MsgWaitForMultipleObjects() is the way to go, ie:
while (fServer.ServerState = ssStarted) and (not Self.Terminated) do
begin
ProcessFiles;
if MsgWaitForMultipleObjects(0, nil, FALSE, 3000, QS_ALLINPUT) = WAIT_OBJECT_0 then
Self.ServiceThread.ProcessRequests(false);
end;
If you want to call ProcessFiles() at 3 second intervals regardless of any messages arriving, then you can use a waitable timer for that, ie:
var
iDue: TLargeInteger;
hTimer: array[0..0] of THandle;
begin
iDue := -30000000; // 3 second relative interval, specified in nanoseconds
hTimer[0] := CreateWaitableTimer(nil, False, nil);
SetWaitableTimer(hTimer[0], iDue, 0, nil, nil, False);
while (fServer.ServerState = ssStarted) and (not Self.Terminated) do
begin
// using a timeout interval so the loop conditions can still be checked periodically
case MsgWaitForMultipleObjects(1, hTimer, False, 1000, QS_ALLINPUT) of
WAIT_OBJECT_0:
begin
ProcessFiles;
SetWaitableTimer(hTimer[0], iDue, 0, nil, nil, False);
end;
WAIT_OBJECT_0+1: Self.ServiceThread.ProcessRequests(false);
end;
end;
CancelWaitableTimer(hTimer[0]);
CloseHandle(hTimer[0]);
end;
Use a timer to run ProcessFiles instead of hacking it into main application loop. Then ProcessFiles will run in the interval you want and the messages will be processed correctly, not taking 100 % CPU.
I used a TTimer in a multithreaded application with strange results, so now i use Events.
while (fServer.ServerState = ssStarted) and (Self.Terminated = false) do
begin
Self.ServiceThread.ProcessRequests(false);
ProcessFiles;
if ExitEvent.WaitFor(3000) <> wrTimeout then
Exit;
end;
You create the event with
ExitEvent := TEvent.Create(nil, False, False, '');
Now the last thing is to fire the event in case of service stop. I think the Stop event of the service is the right place to put this.
ExitEvent.SetEvent;
I use this code for an cleanup thread in my DB connections pooling system, but it should work well in your case too.
You don't need to sleep for 3 full seconds to keep the CPU usage low. Even something like Sleep(500) should keep your usage pretty low (if there are no messages waiting to process it should blow through the loop pretty quick and hit the sleep again. If your loop takes a few ms to run it still means your thread is spending the vast majority of time in sleep.
That being said, your code may benefit from some refactoring. You say you don't want ProcessRequests to block waiting for a message? The only other thing in that loop is ProcessFiles. If that is dependent on the message being processed then why can't it block? And if it's not dependent on the message being processed then can it be split onto another thread? (the previous suggestion of firing ProcessFiles via a timer is an excellent suggestion on how to do this).
Use an TEvent that you signal when the thread should wake up. Then block on the tevent (using waitformultiple as Jeroen says if you have multiple events to wait on)
Is it not possible to move ProcessFiles to a seperate thread? In your MainThread you just wait for messages and when the service is being terminated you terminate the ProcessFiles thread.

Resources