public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH] atexit does not work with os.execv
@ 2006-02-06  7:11 Zac Medico
  0 siblings, 0 replies; only message in thread
From: Zac Medico @ 2006-02-06  7:11 UTC (permalink / raw
  To: gentoo-portage-dev

[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi everyone,

While auditing the code related to bug 117988, I've noticed that it calls portageexit() directly because the normal atexit hooks do not work with the os.execv call when portage restarts itself.  Currently, several other atexit hooks exist but never get called when portage restarts itself.

Unfortunately, python's atexit module does not have a public interface for anything but the register() function (_exithandlers and _run_exitfuncs are accessible but undocumented).  In the attached patch, I've copied the private code (GPL compatible) directly from /usr/lib/python2.4/atexit.py so that the functionality is duplicated in our portage_exec module.  Then I've wrapped all relevant access to the atexit module in calls to the new portage_exec.atexit_register() function.  The last hunk uses the new function portage_exec.run_exitfuncs() to manually call the registered functions prior to the os.execv call. Feedback would be appreciated.

Zac
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFD5vaC/ejvha5XGaMRAmvFAJ90D3b5N6t8YiVjy4Qp0woo/tFm9wCeNwYH
QDCajTK1JPea2fg+AT7WDEs=
=8DuV
-----END PGP SIGNATURE-----

[-- Attachment #2: atexit_register.patch --]
[-- Type: text/x-patch, Size: 4490 bytes --]

Index: pym/portage_locks.py
===================================================================
--- pym/portage_locks.py	(revision 2671)
+++ pym/portage_locks.py	(working copy)
@@ -4,7 +4,6 @@
 # $Id: /var/cvsroot/gentoo-src/portage/pym/portage_locks.py,v 1.18.2.2 2005/01/16 02:35:33 carpaski Exp $
 
 
-import atexit
 import errno
 import os
 import stat
@@ -12,6 +11,7 @@
 import time
 import types
 import portage_exception
+import portage_exec
 import portage_file
 import portage_util
 import portage_data
@@ -30,7 +30,7 @@
 	if os.path.isdir(mypath):
 		hardlock_path_list = mypath[:]
 
-atexit.register(clean_my_hardlocks)
+portage_exec.atexit_register(clean_my_hardlocks)
 
 def lockdir(mydir):
 	return lockfile(mydir,wantnewlockfile=1)
Index: pym/portage.py
===================================================================
--- pym/portage.py	(revision 2671)
+++ pym/portage.py	(working copy)
@@ -19,7 +19,7 @@
 	raise SystemExit, 127
 
 try:
-	import os,string,types,atexit,signal,fcntl
+	import os,string,types,signal,fcntl
 	import time,cPickle,traceback,copy
 	import re,pwd,grp,commands
 	import shlex,shutil
@@ -6901,7 +6901,7 @@
 		close_portdbapi_caches()
 		commit_mtimedb()
 
-atexit.register(portageexit)
+portage_exec.atexit_register(portageexit)
 
 if (secpass==2) and (not os.environ.has_key("SANDBOX_ACTIVE")):
 	if settings["PORTAGE_CALLER"] in ["emerge","fixpackages"]:
Index: pym/portage_exec.py
===================================================================
--- pym/portage_exec.py	(revision 2671)
+++ pym/portage_exec.py	(working copy)
@@ -39,6 +39,41 @@
 	args.append(mycommand)
 	return spawn(args, opt_name=opt_name, **keywords)
 
+_exithandlers = []
+def atexit_register(func, *args, **kargs):
+	"""Wrapper around atexit.register that is needed in order to track
+	what is registered.  For example, when portage restarts itself via
+	os.execv, the atexit module does not work so we have to do it
+	manually by calling the run_exitfuncs() function in this module."""
+	_exithandlers.append((func, args, kargs))
+
+def run_exitfuncs():
+	"""This is should behave identically to the routine performed by
+	the atexit module at exit time.  It's only necessary to call this
+	function when atexit will not work (because of os.execv, for
+	example)."""
+
+	# This function is a copy of the private atexit._run_exitfuncs()
+	# from the python 2.4.2 sources.  The only difference from the
+	# original function is the string in the print statement.
+	exc_info = None
+	while _exithandlers:
+		func, targs, kargs = _exithandlers.pop()
+		try:
+			func(*targs, **kargs)
+		except SystemExit:
+			exc_info = sys.exc_info()
+		except:
+			import traceback
+			print >> sys.stderr, "Error in portage_exec.run_exitfuncs:"
+			traceback.print_exc()
+			exc_info = sys.exc_info()
+
+	if exc_info is not None:
+		raise exc_info[0], exc_info[1], exc_info[2]
+
+atexit.register(run_exitfuncs)
+
 # We need to make sure that any processes spawned are killed off when
 # we exit. spawn() takes care of adding and removing pids to this list
 # as it creates and cleans up processes.
@@ -55,7 +90,7 @@
 			# of spawn().
 			pass
 
-atexit.register(cleanup)
+atexit_register(cleanup)
 
 def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False,
           uid=None, gid=None, groups=None, umask=None, logfile=None,
Index: bin/emerge
===================================================================
--- bin/emerge	(revision 2672)
+++ bin/emerge	(working copy)
@@ -9,7 +9,7 @@
 
 import portage
 
-import emergehelp,xpak,string,re,commands,time,shutil,traceback,atexit,signal,socket,types
+import emergehelp,xpak,string,re,commands,time,shutil,traceback,signal,socket,types
 from stat import *
 from output import *
 
@@ -492,7 +492,7 @@
 		emergelog(" *** terminating.")
 	if "notitles" not in portage.features:
 		xtermTitleReset()
-atexit.register(emergeexit)
+portage.portage_exec.atexit_register(emergeexit)
 
 def emergeexitsig(signum, frame):
 	signal.signal(signal.SIGINT, signal.SIG_IGN)
@@ -2119,7 +2119,7 @@
 							if len(mymergelist) > mergecount:
 								emergelog(" *** RESTARTING emerge via exec() after change of portage version.")
 								del portage.mtimedb["resume"]["mergelist"][0]
-								portage.portageexit()
+								portage.portage_exec.run_exitfuncs()
 								mynewargv=["/usr/lib/portage/bin/emerge","--resume"]
 								badlongopts = ("--ask","--tree","--changelog","--skipfirst","--resume")
 								for arg in myopts:

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-02-06  7:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-06  7:11 [gentoo-portage-dev] [PATCH] atexit does not work with os.execv Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox