Fork.py

From PeformIQ Upgrade
Jump to navigation Jump to search
#!/usr/bin/env python
#
#  Purpose: Check function of fork() with cygwin
#
#  $Id: fork2.py,v 1.1.1.1 2003/10/22 13:05:22 zyx Exp $
#
#---------------------------------------------------------------------

"""
  More complex fork framework

  fork() and in the child use setsid() and other calls to detach
  from the controllling terminal
"""

#---------------------------------------------------------------------

import getopt
import os
import sys
import signal
import time
import logging
import whrandom

#---------------------------------------------------------------------

__id__        = "@(#) fork2.py  [1.0.0] 14/10/2003"
__version__   = "1.0.0"

TRUE          =  1
FALSE         =  0

LOGFILE      = "fork2.log"
PIDFILE      = "fork2.pid"

daemonFlg     =  0
debugFlg      =  0
silentFlg     =  0
verboseFlg    =  0
waitFlg       =  0
inParent      =  0

pause         =  2
duration      = 10
noSessions    = 10

#=====================================================================

def now(): 
   return time.ctime(time.time())       # current time on the server

#---------------------------------------------------------------------

def shutdown():
   log.info("[fork2]  Suttting down")

   if inParent:
      os.unlink(PIDFILE)

   sys.exit(99)

#---------------------------------------------------------------------

def sigTerm(signum, frame):
   "SIGTERM handler"

   s = "[fork2]  Caught SIGTERM!"
   print s
   log.info(s)

   shutdown()

#---------------------------------------------------------------------

def readConfig():
   pass

#---------------------------------------------------------------------

def checkRunning():
   try:
      pfp = open(PIDFILE, 'r')
   except IOError, e:
      pfp = 0

   if pfp:
      line = pfp.readline()
      line = line.strip()

      serverPid   = int(line)

      noProcess    = 0

      try:
         os.kill(serverPid, 0)
      except OSError, e:
         if e.errno == 3:
            noProcess = 1
         else:
            print "kill() failed with errno %d" % e.errno
            sys.exit(0)

      if noProcess:
         print "[fork2]  Stale server pid file!"
         pfp.close()
         os.unlink(PIDFILE)

         return 0
      else:
         pfp.close()
         return serverPid

      return serverPid
   else:
      return 0

#---------------------------------------------------------------------

def writePidfile(pid):
   try:
      pfp = open(PIDFILE, 'w')
   except IOError, e:
      print "[fork2]  Could not open %s" % PIDFILE
      sys.exit(0)

   print >>pfp, "%d" % pid

   pfp.close()

   return pid

#---------------------------------------------------------------------

def becomeDaemon():
   pid = os.fork()

   if pid == 0:     # In child
      print "[fork2]  fork() -> 0 (%d)" % getpid()
      time.sleep(1)
      pass
   elif pid == -1:  # Error
      print "[fork2]  fork() failed!"
      time.sleep(1)
      sys.exit(0)
   else:            # In parent
      print "[fork2]  fork() ->", getpid()
      time.sleep(1)
      sys.exit(0)

   time.sleep(2)

   os.setsid()

   pid = os.getpid()

   return pid

#---------------------------------------------------------------------

def init():
   global ctrlPid

   ctrlPid = checkRunning()

   if ctrlPid:
      print "[fork2]  Server already running! (pid = %d)" % ctrlPid
      sys.exit(0)

   if daemonFlg:
      ctrlPid = becomeDaemon()
   else:
      ctrlPid = os.getpid()

   writePidfile(ctrlPid)

   global log

   log  = logging.getLogger('fork2')
   hdlr = logging.FileHandler(LOGFILE)
   fmtr = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

   hdlr.setFormatter(fmtr)
   log.addHandler(hdlr) 
   log.setLevel(logging.INFO)

   log.info("Server started processing")

   global uname

   readConfig()

   if (not silentFlg):
      print "[fork2]  Server pid is %d" % ctrlPid

   signal.signal(signal.SIGTERM, sigTerm)

#---------------------------------------------------------------------

def terminate():
   serverPid = checkRunning()

   if serverPid:
      if (not silentFlg):
         print "[fork2]  Terminating server with pid, %d\n" % serverPid

      os.kill(serverPid, signal.SIGTERM)

      if (waitFlg):
         while 1:
            try:
               kill(serverPid, 0)
            except OSError, e:
               if e.errno == 3:
                  break
               else:
                  print "[server:terminate]  kill() failed with errno %d" % e.errno
                  sys.exit(0)
 
            time.sleep(1)

   return 0

#=====================================================================

def doChild(no):
   global inParent

   inParent = 0

   toGo = float(duration + 10)

   #os.setsid()

   pid = os.getpid()

   signal.signal(signal.SIGTERM, sigTerm)

   while toGo > 0.0:
      t     = whrandom.randint(1, 1000) * 0.001

      toGo -= t
      time.sleep(t)
      s = "[fork2]  In child %3d [%d] - %5.2f" % (no, pid, t)
      log.info(s)
      print s

#---------------------------------------------------------------------

def spawn():
   global inParent

   inParent = 1

   pids = {}

   for i in range(noSessions):
      pid = os.fork()

      if pid == 0:     # In child
         doChild(i)
      elif pid == -1:  # Error
         print "[fork2]  fork() failed!"
         time.sleep(2)

         sys.exit(0)
      else:            # In parent
         pids[i]   = pid

   myPid = os.getpid()

   print "[fork2]  In parent [%d]: fork() -> %d" % (myPid, pid)
   print "[fork2]  In parent [%d]: waiting..." % myPid

   time.sleep(duration)

   print "[fork2]  *** In parent [%d]: Applying SIGTERM" % myPid

   for i in range(noSessions):
      os.kill(pids[i], signal.SIGTERM)

   while 1:
      try:
         (pid, status) = os.wait()
      except OSError, e:
         if e.errno == 10:  # No children
            break

      print "[fork2]  In parent - wait() --> (PID %d, Status %d, Signal %d)" % \
           (pid, ((status & 0xff00)>>8), (status & 0xff))

      i -= 1

   return 0

#---------------------------------------------------------------------

def main():
   global debugFlg
   global verboseFlg
   global waitFlg
   global duration
   global noSessions

   try:
      opts, args = getopt.getopt(sys.argv[1:], "dD:n:TvVw?")
   except getopt.error, e:
      print __doc__
      return 1

   wrk  = os.getcwd()
   base = os.path.basename(wrk)

   for o, a in opts:
      if o == '-d':
         debugFlg      = 1
      elif o == '-D':
         duration      = int(a)
      elif o == '-n':
         noSessons     = int(a)
      elif o == '-T':
         terminate()
         return 0
      elif o == '-v':
         verboseFlg    = 1
      elif o == '-V':
         print "[fork2]  Version: %s" % __version__
         return 1
      elif o == '-w':
         waitFlg       = 1
      elif o == '-?':
         print __doc__
         return 1

   print "[fork2]  Working directory is %s" % os.getcwd()

   if args:
      for arg in args:
         print arg

   init()

   spawn()

#---------------------------------------------------------------------

if __name__ == '__main__' or __name__ == sys.argv[0]:
   try:
      sys.exit(main())
   except KeyboardInterrupt, e:
      s = "[fork2]  Interrupted!"
      print s
      log.info(s)
      shutdown()

#---------------------------------------------------------------------

"""
Revision History:

     Date     Who   Description
   --------   ---   --------------------------------------------------
   20031018   plh   Initial implementation

Problems to fix:

To Do:

Issues:

"""