How to debug a forked process with pdb ?

Timothy Madden terminatorul at gmail.com
Sun Sep 6 19:07:27 CEST 2009


Hello

I am trying to write a daemon and I call os.fork() twice to detach from
the terminal and other staff.

Problem is after the second fork() the child immediately gives an
exception and although I get a traceback displayed the process should
terminate, the child proces is still live, and its parent is waiting in
a loop for the child to either exit or send SIGUSR1 to it to indicate
the daemon has started up and is in the running state.

The problem is the daemon script has terminated with an uncaught
exception and a traceback displayed, but the process is still hanging
there. Do you know why would it not exit ?

Trying to kill the daemon process, even as root, fails silently. Do you
know why that would happen ?

I would like to debug the scrip with
     python -m pdb pikantBlue.py
but after the first fork() call the debugger prompt is unusuable.
Probably the same prompt is shared by two instances of pdb, that have
forked once with my script. Do you know how can I debug a script that
forks ?

You have my script attached if you want to look it over. The child
failes and somehow freezes at the import line at the end of the file,
and its parent is livelocked in the while loop.

Thank you,
Timothy Madden

---
#!/usr/bin/env python

import sys, os, signal, time
from pikantBlueServer import PIDFile as PIDFile, pid_file as pid_file

serverRunning = False
def serverRunningSignal(usrSignal, stackFrame):
     global serverRunning

     if (usrSignal == signal.SIGUSR1):
	serverRunning = True

wait_message = False
def waitAlarm(sigAlarm, stackFrame):
     global wait_message

     sys.stdout.write('Starting daemon ... ')
     wait_message = True

def daemonize(loop, fileLst):
     exitCode = False

     sys.stdin.flush()
     sys.stdout.flush()
     sys.stderr.flush()

     pid = os.fork()

     if pid > 0:
	# the main process
	#
	# returns with the exit code of the proxy child
	print 'Proxy proces' , pid
	exitCode = (os.waitpid(pid,0) == 0)
     else:
	# the proxy child
	#
	# sets cwd, umask and sid, forks the server
	# waits for either it's termination or the ready signal
	os.setsid()

	signal.signal(signal.SIGUSR1, serverRunningSignal)

	sys.stdin.flush()
	sys.stdout.flush()
	sys.stderr.flush()

	pid = os.fork()

	if pid > 0:
	    #proxy process waits for termination of the child or the
	    #ready signal

	    print 'Daemon process', pid
	    signal.signal(signal.SIGALRM, waitAlarm)
	    signal.alarm(1)

	    waitPid = True
	    global serverRunning

	    if not serverRunning:
		try:
		    os.kill(pid, 0)
		except OSError, e:
		    if hasattr(e, 'errno') and e.errno == errno.ESRCH:
			waitPid = False
		    else:
			raise

	    while waitPid and not serverRunning:
		time.sleep(10)
		if not serverRunning:
		    try:
			sys.stdout.write('Checking child process ' + str(pid) + ' ... ')
			os.kill(pid, 0)
			print 'live.'
		    except OSError, e:
			if hasattr(e, 'errno') and e.errno == errno.ESRCH:
			    waitPid = False
			    print 'dead'
			else:
			    raise
	    signal.alarm(0)
	    global wait_message
	    if waitPid and wait_message:
		print 'done'
	    exitCode = serverRunning
	else:
	    # the server process
	    #
	    signal.signal(signal.SIGUSR1, signal.SIG_DFL)
	    os.chdir('/')
	    os.umask(0)

	    try:
		import pikantBlueSever
		exitCode = pikantBlueServer.start(loop, fileLst)
	    except:
		exitCode = False
     return exitCode




More information about the Python-list mailing list