How can one know if a process in Windows has exited or not? - winapi

I have an open process handle and PID of the process. Can I use this information to get status of the process if it has exited or not?

The process ID is fairly useless. It's the kind of crutch you'd be forced to use when targeting POSIX, for example.
It's the process handle that is valuable. You can either wait on the process handle using WaitForSingleObject, for example, or ask for the process' exit code with a call to GetExitCodeProcess.
Either API call is capable of reporting whether the process has terminated or not. Assuming that hProcess is the process handle, the following two snippets produce a value that indicates whether the process has terminated:
bool terminated = ::WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0;
DWORD exit_code{};
bool terminated = ::GetExitCodeProcess(hProcess, &exit_code) &&
(exit_code != STILL_ACTIVE);
Note that the first option is more robust. The second option cannot distinguish between a process that's still running, and a process that has terminated but set the exit code to a value of STILL_ACTIVE (259).

Related

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).

Windows JDK8: When will the windows system reuse the handle value of a process object?

Environment
jdk8 on windows
Steps
Create a Process instance with ProcessBuilder, and do some tasks using the process's output.
Call waitFor() to wait for this process to complete.
Use jna+cmd to forcibly kill the process. I do this in a finally block to make sure that the process is always terminated.
Field f = process.getClass().getDeclaredField("handle");
f.setAccessible(true);
long handleValue = f.getLong(process);
WinNT.HANDLE handle = new WinNT.HANDLE();
handle.setPointer(Pointer.createConstant(handleValue));
Kernel32 kernel = Kernel32.INSTANCE;
int pid = kernel.GetProcessId(handle);
Process killPr = Runtime.getRuntime().exec("cmd /c taskkill /pid " + pid + " /f /t");
killPr.waitFor();
killPr.destroy();
Question
Is it safe to do above steps? Will I kill another unrelated process in step 3? I debugged and notice that the handle value of ProcessImpl is still valid after the process is exited. I'm worried that windows system will reuse the same handle when the real process is exited but the process object is not recycled by the jvm.
Process handle becomes available for reuse only after the last handle to the process is closed. As long as you can ensure that process doesn't get cleaned up, killing the process by PID is fine. Also, there are more cleaner ways to kill the process since you are already using JNA, see kernel32.TerminateProcess.
The handle for the process will be closed in finalize, also Process class has a call to destroy() that will also trigger a TerminateProcess call. Mostly you don't have to do what you are doing here. Calling destroy followed by waitFor should do the job.

Trying to implement `signal.CTRL_C_EVENT` in Python3.6

I'm reading about signals and am attempting to implement signal.CTRL_C_EVENT
From what I"m understanding, if the user presses CTRC + C while the program is running, a signal will be sent to kill a program. I can specify the program as a parameter?
My attempt to test out the usage:
import sys
import signal
import time
import os
os.kill('python.exe', signal.CTRL_C_EVENT)
while(1):
print ("Wait...")
time.sleep(10)
However, it seems I need a pid number and 'python.exe' doesn't work. I looked under processes and I can't seem to find a PID number. I did see a PID column under services, but there were so many services -- I couldn't find a python one.
So how do I find PID number?
Also, does signal_CTRL_C_EVENT always have to be used within os.kill?
Can It be used for other purposes?
Thank you.
Windows doesn't implement Unix signals, so Python fakes os.kill. Unfortunately its implementation is confusing. It should have been split up into os.kill and os.killpg, but we're stuck with an implementation that mixes the two. To send Ctrl+C or Ctrl+Break, you need to use os.kill as if it were really os.killpg.
When its signal argument is either CTRL_C_EVENT (0) or CTRL_BREAK_EVENT (1), os.kill calls WinAPI GenerateConsoleCtrlEvent. This instructs the console (i.e. the conhost.exe instance that's hosting the console window of the current process) to send the event to a given process group ID (PGID). Group ID 0 is special cased to broadcast the event to all processes attached to the console. Otherwise
a process group ID is the ID of the lead process in a process group. Every process is either created as the leader of a new group or inherits the group of its parent. A new group can be created via the CreateProcess creation flag CREATE_NEW_PROCESS_GROUP.
If either calling GenerateConsoleCtrlEvent fails (e.g. the current process isn't attached to a console) or the signal argument isn't one of the above-mentioned control events, then os.kill instead attempts to open a handle for the given process ID (PID) with terminate access and call WinAPI TerminateProcess. This function is like sending a SIGKILL signal in Unix, but with a variable exit code. Note the confusion in that it operates on an individual process (i.e. kill), not a process group (i.e. killpg).
Windows doesn't provide a function to get the group ID of a process, so generally the only way to get a valid PGID is to create the process yourself. You can pass the CREATE_NEW_PROCESS_GROUP flag to subprocess.Popen via its creationflags parameter. Then you can send Ctrl+Break to the child process and all of its children that are in the same group, but only if it's a console process that's attached to the same console as your current process, i.e. it won't work if you also also use any of these flags: CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, or DETACHED_PROCESS. Also, Ctrl+C is disabled in such a process, unless the child manually enables it via WinAPI SetConsoleCtrlHandler.
Only use os.kill(os.getpid(), signal.CTRL_C_EVENT) when you know for certain that your current process was started as the lead process of a group. Otherwise the behavior is undefined, and in practice it works like sending to process group ID 0.
You can get pid via os.getpid()
os.kill(os.getpid(), signal.CTRL_C_EVENT)

CreateProcess returns non 0 but GetExitCodeProcess() returns 128

I am creating an application that will start another process using CreateProcess(). And in the parent process I will use GetExitCodeProcess() to check whether the process active or not.
Here CreateProcess() is successful (returned a non negative value) but GetExitCodeProcess() returns 128 (There are no child processes to wait for). I am not seeing any trace of the child process started(usually some debugs). It happens intermittently.
Any idea what really happened to the child process?. Where we get more information (in system/application event logs?).
Please guide me.
Thanks,
Naga
Thanks for your comments.
I have found the following MSDN articles that gives the same symptoms and resolution for the problem.
Cmd.exe, Perl.exe, or other console-mode applications may fail to initialize properly and terminate prematurely when launched by a service using the CreateProcess() or CreateProcessAsUser() APIs. The calling process has no way of knowing that the launched console-mode application has terminated prematurely.
In some instances, calling GetExitCode() against the failed process indicates the following exit code:
128L ERROR_WAIT_NO_CHILDREN - There are no child processes to wait for.
http://support.microsoft.com/kb/156484
http://support.microsoft.com/kb/142676/EN-US
http://support.microsoft.com/kb/175687/EN-US
Thanks,
Naga

fork() and wait() connection to pid

I know that fork() creates a child process, returns 0 to child and returns child's pid to parent.
From what I understand wait() also returns some kind of pid of the child process that's terminated. Is this the same pid as the one that's returned to parent after fork?
I don't understand how to use wait().
My textbook just shows
int ReturnCode;
while (pid!=wait(&ReturnCode));
/*the child has terminated with Returncode as its return code*/
I don't even understand what this means.
How do I use wait()? I am using execv to create a child process but I want parent to wait. Someone please explain and give an example.
Thanks
wait() does indeed return the PID of the child process that died. If you only have one child process, you don't really need to check the PID (do check that it's not zero or negative though; there are some conditions that may cause the wait call to fail). You can find an example here: http://www.csl.mtu.edu/cs4411/www/NOTES/process/fork/wait.html
wait() takes the address of an integer
variable and returns the process ID of
the completed process.
More about the wait() system call
The
while (pid!=wait(&ReturnCode));
loop is comparing the process id (pid) returned by wait() to the pid received earlier from a fork or any other process starter. If it finds out that the process that has ended IS NOT the same as the one this parent process has been waiting for, it keeps on wait()ing.

Resources