[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