From: Zac Medico Date: Sat, 6 Jul 2013 00:09:30 +0000 (-0700) Subject: Disable global spawned_pids (avoid memory leak) X-Git-Tag: v2.2.0_alpha187~15 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=898a57546953983b8888581bf888054163d9faa9;p=portage.git Disable global spawned_pids (avoid memory leak) It used to be necessary for API consumers to remove pids from the global spawned_pids, since otherwise it would accumulate a pids endlessly. Now, spawned_pids is just an empty dummy list, so for backward compatibility, ignore ValueError for removal on non-existent items. --- diff --git a/pym/_emerge/EbuildMetadataPhase.py b/pym/_emerge/EbuildMetadataPhase.py index 4c7d772d4..7418aba9f 100644 --- a/pym/_emerge/EbuildMetadataPhase.py +++ b/pym/_emerge/EbuildMetadataPhase.py @@ -128,7 +128,6 @@ class EbuildMetadataPhase(SubProcess): return self.pid = retval[0] - portage.process.spawned_pids.remove(self.pid) def _output_handler(self, fd, event): diff --git a/pym/_emerge/SpawnProcess.py b/pym/_emerge/SpawnProcess.py index 25859a9cd..c57bd2e47 100644 --- a/pym/_emerge/SpawnProcess.py +++ b/pym/_emerge/SpawnProcess.py @@ -114,7 +114,6 @@ class SpawnProcess(SubProcess): return self.pid = retval[0] - portage.process.spawned_pids.remove(self.pid) stdout_fd = None if can_log and not self.background: diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 9463be8b9..034613e9f 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -2423,8 +2423,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): exitcode = (exitcode & 0xff) << 8 else: exitcode = exitcode >> 8 - if mypids: - portage.process.spawned_pids.remove(mypids[0]) + if content: try: servertimestamp = time.mktime(time.strptime( diff --git a/pym/portage/dbapi/_MergeProcess.py b/pym/portage/dbapi/_MergeProcess.py index 1442d56ac..76108c882 100644 --- a/pym/portage/dbapi/_MergeProcess.py +++ b/pym/portage/dbapi/_MergeProcess.py @@ -174,7 +174,6 @@ class MergeProcess(ForkProcess): self.vartree.dbapi._pkgs_changed = True self.vartree.dbapi._clear_pkg_cache(mylink) - portage.process.spawned_pids.append(pid) return [pid] os.close(elog_reader_fd) diff --git a/pym/portage/process.py b/pym/portage/process.py index 7fdc1333a..728a01daf 100644 --- a/pym/portage/process.py +++ b/pym/portage/process.py @@ -156,26 +156,23 @@ def run_exitfuncs(): 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. -spawned_pids = [] -def cleanup(): - while spawned_pids: - pid = spawned_pids.pop() +# It used to be necessary for API consumers to remove pids from spawned_pids, +# since otherwise it would accumulate a pids endlessly. Now, spawned_pids is +# just an empty dummy list, so for backward compatibility, ignore ValueError +# for removal on non-existent items. +class _dummy_list(list): + def remove(self, item): + # TODO: Trigger a DeprecationWarning here, after stable portage + # has dummy spawned_pids. try: - # With waitpid and WNOHANG, only check the - # first element of the tuple since the second - # element may vary (bug #337465). - if os.waitpid(pid, os.WNOHANG)[0] == 0: - os.kill(pid, signal.SIGTERM) - os.waitpid(pid, 0) - except OSError: - # This pid has been cleaned up outside - # of spawn(). + list.remove(self, item) + except ValueError: pass -atexit_register(cleanup) +spawned_pids = _dummy_list() + +def cleanup(): + pass def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False, uid=None, gid=None, groups=None, umask=None, logfile=None, @@ -309,7 +306,6 @@ def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False, # Add the pid to our local and the global pid lists. mypids.append(pid) - spawned_pids.append(pid) # If we started a tee process the write side of the pipe is no # longer needed, so close it. @@ -332,10 +328,6 @@ def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False, # and wait for it. retval = os.waitpid(pid, 0)[1] - # When it's done, we can remove it from the - # global pid list as well. - spawned_pids.remove(pid) - if retval: # If it failed, kill off anything else that # isn't dead yet. @@ -346,7 +338,6 @@ def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False, if os.waitpid(pid, os.WNOHANG)[0] == 0: os.kill(pid, signal.SIGTERM) os.waitpid(pid, 0) - spawned_pids.remove(pid) # If it got a signal, return the signal that was sent. if (retval & 0xff): diff --git a/pym/portage/util/_async/ForkProcess.py b/pym/portage/util/_async/ForkProcess.py index 17be02a6e..be856d039 100644 --- a/pym/portage/util/_async/ForkProcess.py +++ b/pym/portage/util/_async/ForkProcess.py @@ -26,7 +26,6 @@ class ForkProcess(SpawnProcess): if not isinstance(pid, int): raise AssertionError( "fork returned non-integer: %s" % (repr(pid),)) - portage.process.spawned_pids.append(pid) return [pid] rval = 1