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