[Twisted-Python] Daemon processes on windows
Žiga Seilnacht
ziga.seilnacht at gmail.com
Sat Nov 7 21:21:57 EST 2009
Brian Granger wrote:
> Hi,
>
> I have a server-like process that uses twisted. I need it to daemonize
> itself and on linux/os x I am simply
> using the daemonize function from twistd. This works fine. What about
> Windows though....I saw that the
> win32 version of twistd doesn't have (unless I am missing it) the ability to
> daemonize a process.
>
> Is is simply impossible to daemonize a process on windows? If so, is there
> any way to have a child
> process on windows ignore SIGINT send to the parent?
>
> Cheers and thanks,
>
> Brian
>
It is possible to daemonize a process on Windows. I experimented with
adding that support to the twistd script, but got swamped with other
work and couldn't finish it. Below is the code that I have so far. You
can save it in a module and call the daemonize() function from your script.
The process of daemonization is similar to the one on UNIX -- you have
to spawn a child process twice, the first child is responsible for
breaking away from any job objects (somewhat similar to becoming a
session leader on UNIX), becoming a new process group leader and closing
all handles (file descriptors) that might have been inherited.
The second child has to open dummy std* files and a new (hidden)
console, otherwise the signals stop working. There is a slight
complication with window stations and desktops. Each console creates at
least one window and some other user objects, so we have to create
a separate desktop, or other processes would be able to manipulate them
and send us arbitrary (Windows) messages.
Regards,
Ziga
import os
import sys
import msvcrt
import win32con
import win32process
import win32security
import win32service
from twisted.python import win32
def getPythonArgs():
"""
Return the list of command line args that were used to start
the current Python interpreter and were not stored in C{sys.argv}.
These are the options that control the Python interpreter itself,
like the Python executable, optimization level, warning filters,
division behaviour and literal string handling.
"""
args = [sys.executable]
for warnoption in sys.warnoptions:
args.append("-W")
args.append(warnoption)
if type(1 / 2) is not int:
args.append("-Qnew")
if type("") is not str:
args.append("-U")
if not __debug__:
if getPythonArgs.__doc__ is None:
args.append("-OO")
else:
args.append("-O")
return args
def daemonize():
args = [os.path.abspath(__file__)] + sys.argv
executable = sys.executable
cmdline = win32.quoteArguments(getPythonArgs() + args)
inherit = False
flags = (win32process.CREATE_BREAKAWAY_FROM_JOB | # session leader
win32process.CREATE_NEW_PROCESS_GROUP | # group leader
win32process.DETACHED_PROCESS) # no controlling terminal
info = win32process.STARTUPINFO()
win32process.CreateProcess(executable, cmdline, None, None,
inherit, flags, None, None, info)
# Do what exec* functions do, let the OS do the cleanup.
os._exit(0)
def daemonize2():
args = [sys.argv[1], "--nodaemon"] + sys.argv[2:]
executable = sys.executable
cmdline = win32.quoteArguments(getPythonArgs() + args)
inherit = True
# create an invisible console
flags = (win32process.CREATE_NO_WINDOW
attributes = win32security.SECURITY_ATTRIBUTES()
attributes.bInheritHandle = True
station = win32service.CreateWindowStation(None, 0,
win32con.GENERIC_READ |
win32con.GENERIC_WRITE,
attributes)
station.SetProcessWindowStation()
sname = win32service.GetUserObjectInformation(station,
win32service.UOI_NAME)
dname = str(os.getpid())
desktop = win32service.CreateDesktop(dname, 0,
win32con.GENERIC_READ |
win32con.GENERIC_WRITE,
attributes)
desktop.SetThreadDesktop()
null = os.open("NUL", os.O_RDWR)
handle = msvcrt.get_osfhandle(null)
info = win32process.STARTUPINFO()
info.lpDesktop = "%s\\%s" % (sname, dname)
info.dwFlags = win32process.STARTF_USESTDHANDLES
info.hStdInput = info.hStdOutput = info.hStdError = handle
win32process.CreateProcess(executable, cmdline, None, None,
inherit, flags, None, None, info)
# Same as above, exit as fast as possible.
os._exit(0)
if __name__ == "__main__":
daemonize2()
More information about the Twisted-Python
mailing list