Reputation: 4511
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.
Upvotes: 3
Views: 6214
Reputation: 96
You can get pid via os.getpid()
os.kill(os.getpid(), signal.CTRL_C_EVENT)
Upvotes: 1
Reputation: 34260
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.
Upvotes: 7