public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Zac Medico <zmedico@gentoo.org>
To: gentoo-portage-dev@lists.gentoo.org
Subject: [gentoo-portage-dev] [PATCH] atexit does not work with os.execv
Date: Sun, 05 Feb 2006 23:11:02 -0800	[thread overview]
Message-ID: <43E6F686.1040709@gentoo.org> (raw)

[-- 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:

                 reply	other threads:[~2006-02-06  7:05 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=43E6F686.1040709@gentoo.org \
    --to=zmedico@gentoo.org \
    --cc=gentoo-portage-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox