[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/, lib/portage/util/, lib/portage/tests/util/

2024-03-03 Thread Zac Medico
commit: 11c65496bd951c3b7778a3c1ea240e347b1f4c38
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar  3 21:06:13 2024 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Mar  3 21:10:49 2024 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=11c65496

socks5: Use run_coroutine_exitfuncs()

Since commit c3ebdbb42e72 the atexit_register(proxy.stop) call in
the get_socks5_proxy function can accept a coroutine function to
execute in run_coroutine_exitfuncs(), so convert the ProxyManager
stop method to a coroutine and use run_coroutine_exitfuncs().

Bug: https://bugs.gentoo.org/925240
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/tests/util/test_socks5.py |  5 ++-
 lib/portage/util/_eventloop/asyncio_event_loop.py | 12 ---
 lib/portage/util/socks5.py| 39 +++
 3 files changed, 7 insertions(+), 49 deletions(-)

diff --git a/lib/portage/tests/util/test_socks5.py 
b/lib/portage/tests/util/test_socks5.py
index 4a6d08169d..a8cd0c46c4 100644
--- a/lib/portage/tests/util/test_socks5.py
+++ b/lib/portage/tests/util/test_socks5.py
@@ -216,10 +216,9 @@ class Socks5ServerTestCase(TestCase):
 self.assertEqual(result, content)
 finally:
 try:
-# Also run_exitfuncs to test atexit hook cleanup.
-await socks5.proxy.stop()
+# Also run_coroutine_exitfuncs to test atexit hook cleanup.
 self.assertNotEqual(portage.process._exithandlers, [])
-portage.process.run_exitfuncs()
+await portage.process.run_coroutine_exitfuncs()
 self.assertEqual(portage.process._exithandlers, [])
 finally:
 portage.process._exithandlers = previous_exithandlers

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index a598b1b516..821cc7f102 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -15,7 +15,6 @@ except ImportError:
 PidfdChildWatcher = None
 
 import portage
-from portage.util import socks5
 
 
 class AsyncioEventLoop(_AbstractEventLoop):
@@ -75,17 +74,6 @@ class AsyncioEventLoop(_AbstractEventLoop):
 self._closing = False
 
 async def _close_main(self):
-# Even though this has an exit hook, invoke it here so that
-# we can properly wait for it and avoid messages like this:
-# [ERROR] Task was destroyed but it is pending!
-if socks5.proxy.is_running():
-# TODO: Convert socks5.proxy.stop() to a regular coroutine
-# function so that it doesn't need to be wrapped like this.
-async def stop_socks5_proxy():
-await socks5.proxy.stop()
-
-portage.process.atexit_register(stop_socks5_proxy)
-
 await portage.process.run_coroutine_exitfuncs()
 portage.process.run_exitfuncs()
 

diff --git a/lib/portage/util/socks5.py b/lib/portage/util/socks5.py
index f8fcdf9fca..c32ba77674 100644
--- a/lib/portage/util/socks5.py
+++ b/lib/portage/util/socks5.py
@@ -6,15 +6,8 @@ import asyncio
 import errno
 import os
 import socket
-from typing import Union
 
 import portage
-
-portage.proxy.lazyimport.lazyimport(
-globals(),
-"portage.util._eventloop.global_event_loop:global_event_loop",
-)
-
 import portage.data
 from portage import _python_interpreter
 from portage.data import portage_gid, portage_uid, userpriv_groups
@@ -65,41 +58,19 @@ class ProxyManager:
 **spawn_kwargs,
 )
 
-def stop(self) -> Union[None, asyncio.Future]:
+async def stop(self):
 """
-Stop the SOCKSv5 server.
-
-If there is a running asyncio event loop then asyncio.Future is
-returned which should be used to wait for the server process
-to exit.
+Stop the SOCKSv5 server. This method is a coroutine.
 """
-future = None
-try:
-loop = asyncio.get_running_loop()
-except RuntimeError:
-loop = None
 if self._proc is not None:
 self._proc.terminate()
-if loop is None:
-# In this case spawn internals would have used
-# portage's global loop when attaching a waiter to
-# self._proc, so we are obligated to use that.
-global_event_loop().run_until_complete(self._proc.wait())
-else:
-if self._proc_waiter is None:
-self._proc_waiter = asyncio.ensure_future(
-self._proc.wait(), loop=loop
-)
-future = asyncio.shield(self._proc_waiter)
-
-if loop is not None and future is None:
-future = loop.create_future()
-future.set_result(None)
+if self._proc_waiter is None:
+self._proc_waiter 

[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2023-10-05 Thread Zac Medico
commit: c98240fba21b319e27fe595d70c671c9ddfb7fd0
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Oct  5 08:20:14 2023 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Oct  5 08:21:47 2023 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=c98240fb

AsyncioEventLoop: Put back _ChildWatcherThreadSafetyWrapper

In case there are multiple loops running in different threads,
use _ChildWatcherThreadSafetyWrapper. This partially reverts
commit 690ac6e78c4099e83b84ef11c0b4064b077a8ef0.

Bug: https://bugs.gentoo.org/914873
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 30 ++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index fe941b420a..2b21e6dfaf 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -112,7 +112,7 @@ class AsyncioEventLoop(_AbstractEventLoop):
 watcher = ThreadedChildWatcher()
 
 watcher.attach_loop(self._loop)
-self._child_watcher = watcher
+self._child_watcher = _ChildWatcherThreadSafetyWrapper(self, 
watcher)
 
 return self._child_watcher
 
@@ -153,3 +153,31 @@ class AsyncioEventLoop(_AbstractEventLoop):
 except ValueError:
 # This is intended to fail when not called in the main thread.
 pass
+
+
+class _ChildWatcherThreadSafetyWrapper:
+"""
+This class provides safety if multiple loops are running in different 
threads.
+"""
+
+def __init__(self, loop, real_watcher):
+self._loop = loop
+self._real_watcher = real_watcher
+
+def close(self):
+pass
+
+def __enter__(self):
+return self
+
+def __exit__(self, a, b, c):
+pass
+
+def _child_exit(self, pid, status, callback, *args):
+self._loop.call_soon_threadsafe(callback, pid, status, *args)
+
+def add_child_handler(self, pid, callback, *args):
+self._real_watcher.add_child_handler(pid, self._child_exit, callback, 
*args)
+
+def remove_child_handler(self, pid):
+return self._real_watcher.remove_child_handler(pid)



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2023-10-05 Thread Zac Medico
commit: 690ac6e78c4099e83b84ef11c0b4064b077a8ef0
Author: Zac Medico  gentoo  org>
AuthorDate: Thu Oct  5 06:27:27 2023 +
Commit: Zac Medico  gentoo  org>
CommitDate: Thu Oct  5 06:57:11 2023 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=690ac6e7

Eliminate deprecated asyncio.get_child_watcher() usage

Use PidfdChildWatcher if os.pidfd_open is available and works, and
otherwise use ThreadedChildWatcher which should work in any case.

The _ChildWatcherThreadSafetyWrapper class is not needed because
both PidfdChildWatcher and ThreadedChildWatcher use the running
event loop to invoke the child handler callback, and it is safe
to assume that the current AsyncioEventLoop instance is the
running loop when it is used to obtain a child watcher instance.

Bug: https://bugs.gentoo.org/914873
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 51 +++
 1 file changed, 24 insertions(+), 27 deletions(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index 37b5b2706c..fe941b420a 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -6,6 +6,12 @@ import signal
 
 import asyncio as _real_asyncio
 from asyncio.events import AbstractEventLoop as _AbstractEventLoop
+from asyncio.unix_events import ThreadedChildWatcher
+
+try:
+from asyncio.unix_events import PidfdChildWatcher
+except ImportError:
+PidfdChildWatcher = None
 
 import portage
 
@@ -90,9 +96,24 @@ class AsyncioEventLoop(_AbstractEventLoop):
 @return: the internal event loop's AbstractChildWatcher interface
 """
 if self._child_watcher is None:
-self._child_watcher = _ChildWatcherThreadSafetyWrapper(
-self, _real_asyncio.get_child_watcher()
-)
+pidfd_works = False
+if PidfdChildWatcher is not None and hasattr(os, "pidfd_open"):
+try:
+fd = os.pidfd_open(portage.getpid())
+except Exception:
+pass
+else:
+os.close(fd)
+pidfd_works = True
+
+if pidfd_works:
+watcher = PidfdChildWatcher()
+else:
+watcher = ThreadedChildWatcher()
+
+watcher.attach_loop(self._loop)
+self._child_watcher = watcher
+
 return self._child_watcher
 
 @property
@@ -132,27 +153,3 @@ class AsyncioEventLoop(_AbstractEventLoop):
 except ValueError:
 # This is intended to fail when not called in the main thread.
 pass
-
-
-class _ChildWatcherThreadSafetyWrapper:
-def __init__(self, loop, real_watcher):
-self._loop = loop
-self._real_watcher = real_watcher
-
-def close(self):
-pass
-
-def __enter__(self):
-return self
-
-def __exit__(self, a, b, c):
-pass
-
-def _child_exit(self, pid, status, callback, *args):
-self._loop.call_soon_threadsafe(callback, pid, status, *args)
-
-def add_child_handler(self, pid, callback, *args):
-self._real_watcher.add_child_handler(pid, self._child_exit, callback, 
*args)
-
-def remove_child_handler(self, pid):
-return self._real_watcher.remove_child_handler(pid)



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2023-09-25 Thread Zac Medico
commit: 34e4d5655360d135dbf2cd3a073d07d96e23cf74
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Sep 26 05:09:53 2023 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Sep 26 05:14:21 2023 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=34e4d565

Remove deprecated AbstractChildWatcher usage

Fixes this DeprecationWarning triggered by
lib/portage/tests/util/futures/asyncio/test_event_loop_in_fork.py:

lib/portage/util/_eventloop/asyncio_event_loop.py:138: DeprecationWarning: 
'AbstractChildWatcher' is deprecated as of Python 3.12 and will be removed in 
Python 3.14.
  class _ChildWatcherThreadSafetyWrapper(_AbstractChildWatcher):

Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index 88933af9d2..37b5b2706c 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2021 Gentoo Authors
+# Copyright 2018-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import os
@@ -6,7 +6,6 @@ import signal
 
 import asyncio as _real_asyncio
 from asyncio.events import AbstractEventLoop as _AbstractEventLoop
-from asyncio.unix_events import AbstractChildWatcher as _AbstractChildWatcher
 
 import portage
 
@@ -135,7 +134,7 @@ class AsyncioEventLoop(_AbstractEventLoop):
 pass
 
 
-class _ChildWatcherThreadSafetyWrapper(_AbstractChildWatcher):
+class _ChildWatcherThreadSafetyWrapper:
 def __init__(self, loop, real_watcher):
 self._loop = loop
 self._real_watcher = real_watcher



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2021-03-07 Thread Zac Medico
commit: e0b6fbdf6543c19c63bbca007278d48003b807ad
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar  7 09:28:08 2021 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Mar  7 09:28:37 2021 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=e0b6fbdf

AsyncioEventLoop: remove obsolete supports_multiprocessing attribute

Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 7 +--
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index b77728088..6dfac3569 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2020 Gentoo Authors
+# Copyright 2018-2021 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import os
@@ -17,11 +17,6 @@ class AsyncioEventLoop(_AbstractEventLoop):
event loop and is minimally compatible with _PortageEventLoop.
"""
 
-   # Use portage's internal event loop in subprocesses, as a workaround
-   # for https://bugs.python.org/issue22087, and also
-   # https://bugs.python.org/issue29703 which affects pypy3-5.10.1.
-   supports_multiprocessing = False
-
def __init__(self, loop=None):
loop = loop or _real_asyncio.get_event_loop()
self._loop = loop



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2021-03-06 Thread Zac Medico
commit: 4cf221840bb980305b48a329c693dd1a310d5248
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Mar  7 02:48:57 2021 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sun Mar  7 02:49:34 2021 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=4cf22184

Remove unused PollSelectAdapter and PollConstants classes

Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/PollConstants.py | 17 --
 lib/portage/util/_eventloop/PollSelectAdapter.py | 74 
 2 files changed, 91 deletions(-)

diff --git a/lib/portage/util/_eventloop/PollConstants.py 
b/lib/portage/util/_eventloop/PollConstants.py
deleted file mode 100644
index c5700d108..0
--- a/lib/portage/util/_eventloop/PollConstants.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 1999-2009 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-import select
-class PollConstants:
-
-   """
-   Provides POLL* constants that are equivalent to those from the
-   select module, for use by PollSelectAdapter.
-   """
-
-   names = ("POLLIN", "POLLPRI", "POLLOUT", "POLLERR", "POLLHUP", 
"POLLNVAL")
-   v = 1
-   for k in names:
-   locals()[k] = getattr(select, k, v)
-   v *= 2
-   del k, v

diff --git a/lib/portage/util/_eventloop/PollSelectAdapter.py 
b/lib/portage/util/_eventloop/PollSelectAdapter.py
deleted file mode 100644
index c4637a352..0
--- a/lib/portage/util/_eventloop/PollSelectAdapter.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 1999-2020 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-import select
-
-from .PollConstants import PollConstants
-
-class PollSelectAdapter:
-
-   """
-   Use select to emulate a poll object, for
-   systems that don't support poll().
-   """
-
-   def __init__(self):
-   self._registered = {}
-   self._select_args = [[], [], []]
-
-   def register(self, fd, *args):
-   """
-   Only POLLIN is currently supported!
-   """
-   if len(args) > 1:
-   raise TypeError(
-   "register expected at most 2 arguments, got " + 
\
-   repr(1 + len(args)))
-
-   eventmask = PollConstants.POLLIN | \
-   PollConstants.POLLPRI | PollConstants.POLLOUT
-   if args:
-   eventmask = args[0]
-
-   self._registered[fd] = eventmask
-   self._select_args = None
-
-   def unregister(self, fd):
-   self._select_args = None
-   del self._registered[fd]
-
-   def poll(self, *args):
-   if len(args) > 1:
-   raise TypeError(
-   "poll expected at most 2 arguments, got " + \
-   repr(1 + len(args)))
-
-   timeout = None
-   if args:
-   timeout = args[0]
-
-   select_args = self._select_args
-   if select_args is None:
-   select_args = [list(self._registered), [], []]
-
-   if timeout is not None:
-   select_args = select_args[:]
-   # Translate poll() timeout args to select() timeout 
args:
-   #
-   #  | units| value(s) for indefinite 
block
-   # 
-|--|--
-   #   poll   | milliseconds | omitted, negative, or None
-   # 
-|--|--
-   #   select | seconds  | omitted
-   # 
-|--|--
-
-   if timeout is not None and timeout < 0:
-   timeout = None
-   if timeout is not None:
-   select_args.append(timeout / 1000)
-
-   select_events = select.select(*select_args)
-   poll_events = []
-   for fd in select_events[0]:
-   poll_events.append((fd, PollConstants.POLLIN))
-   return poll_events



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2021-03-06 Thread Zac Medico
commit: 05e9b76523569f17c3cbf7465758656c3beb0be8
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Mar  6 10:39:31 2021 +
Commit: Zac Medico  gentoo  org>
CommitDate: Sat Mar  6 10:41:06 2021 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=05e9b765

Remove unused EventLoop class

Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/EventLoop.py | 1153 --
 1 file changed, 1153 deletions(-)

diff --git a/lib/portage/util/_eventloop/EventLoop.py 
b/lib/portage/util/_eventloop/EventLoop.py
deleted file mode 100644
index ff2b73255..0
--- a/lib/portage/util/_eventloop/EventLoop.py
+++ /dev/null
@@ -1,1153 +0,0 @@
-# Copyright 1999-2020 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-import asyncio as _real_asyncio
-import collections
-import errno
-import functools
-import logging
-import os
-import select
-import signal
-import time
-import traceback
-
-try:
-   import fcntl
-except ImportError:
-   #  http://bugs.jython.org/issue1074
-   fcntl = None
-
-try:
-   import threading
-except ImportError:
-   import dummy_threading as threading
-
-import portage
-portage.proxy.lazyimport.lazyimport(globals(),
-   'portage.util.futures:asyncio',
-   'portage.util.futures.executor.fork:ForkExecutor',
-   
'portage.util.futures.unix_events:_PortageEventLoop,_PortageChildWatcher',
-)
-
-from portage.util import writemsg_level
-from ..SlotObject import SlotObject
-from .PollConstants import PollConstants
-from .PollSelectAdapter import PollSelectAdapter
-
-class EventLoop:
-   """
-   An event loop, intended to be compatible with the GLib event loop.
-   Call the iteration method in order to execute one iteration of the
-   loop. The idle_add and timeout_add methods serve as thread-safe
-   means to interact with the loop's thread.
-   """
-
-   supports_multiprocessing = True
-
-   # TODO: Find out why SIGCHLD signals aren't delivered during poll
-   # calls, forcing us to wakeup in order to receive them.
-   _sigchld_interval = 250
-
-   class _child_callback_class(SlotObject):
-   __slots__ = ("callback", "data", "pid", "source_id")
-
-   class _idle_callback_class(SlotObject):
-   __slots__ = ("_args", "_callback", "_cancelled")
-
-   class _io_handler_class(SlotObject):
-   __slots__ = ("args", "callback", "f", "source_id")
-
-   class _timeout_handler_class(SlotObject):
-   __slots__ = ("args", "function", "calling", "interval", 
"source_id",
-   "timestamp")
-
-   class _handle:
-   """
-   A callback wrapper object, compatible with asyncio.Handle.
-   """
-   __slots__ = ("_callback_id", "_loop")
-
-   def __init__(self, callback_id, loop):
-   self._callback_id = callback_id
-   self._loop = loop
-
-   def cancel(self):
-   """
-   Cancel the call. If the callback is already canceled or 
executed,
-   this method has no effect.
-   """
-   self._loop.source_remove(self._callback_id)
-
-   class _call_soon_callback:
-   """
-   Wraps a call_soon callback, and always returns False, since 
these
-   callbacks are only supposed to run once.
-   """
-   __slots__ = ("_args", "_callback")
-
-   def __init__(self, callback, args):
-   self._callback = callback
-   self._args = args
-
-   def __call__(self):
-   self._callback(*self._args)
-   return False
-
-   class _selector_callback:
-   """
-   Wraps an callback, and always returns True, for callbacks that
-   are supposed to run repeatedly.
-   """
-   __slots__ = ("_args", "_callbacks")
-
-   def __init__(self, callbacks):
-   self._callbacks = callbacks
-
-   def __call__(self, fd, event):
-   for callback, mask in self._callbacks:
-   if event & mask:
-   callback()
-   return True
-
-   def __init__(self, main=True):
-   """
-   @param main: If True then this is a singleton instance for use
-   in the main thread, otherwise it is a local instance 
which
-   can safely be use in a non-main thread (default is 
True, so
-   that global_event_loop does not need constructor 
arguments)
-   @type main: bool
-   """
-   self._use_signal = main and fcntl is not None
-   

[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/, lib/portage/util/futures/_asyncio/

2021-01-11 Thread Zac Medico
commit: 386178481eb86ac603cd90ef1bb6ac6b68e51c50
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Jan  4 09:14:36 2021 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Jan 11 09:36:48 2021 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=38617848

global_event_loop: return running loop for current thread

Like asyncio.get_event_loop(), return the running loop for the
current thread if there is one, and otherwise construct a new
one if needed. This allows the _safe_loop function to become
synonymous with the global_event_loop function.

For the case of "loop running in non-main thread" of API
consumer, this change makes portage compatible with PEP
492 coroutines with async and await syntax. Portage
internals can safely begin using async / await syntax instead
of compat_coroutine.

Bug: https://bugs.gentoo.org/763339
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/global_event_loop.py | 28 +++---
 lib/portage/util/futures/_asyncio/__init__.py| 30 +---
 2 files changed, 24 insertions(+), 34 deletions(-)

diff --git a/lib/portage/util/_eventloop/global_event_loop.py 
b/lib/portage/util/_eventloop/global_event_loop.py
index 413011178..cb7a13078 100644
--- a/lib/portage/util/_eventloop/global_event_loop.py
+++ b/lib/portage/util/_eventloop/global_event_loop.py
@@ -1,28 +1,6 @@
-# Copyright 2012-2020 Gentoo Authors
+# Copyright 2012-2021 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
-import portage
-from portage.util._eventloop.asyncio_event_loop import AsyncioEventLoop
+__all__ = ('global_event_loop',)
 
-_instances = {}
-
-
-def global_event_loop():
-   """
-   Get a global EventLoop (or compatible object) instance which
-   belongs exclusively to the current process.
-   """
-
-   pid = portage.getpid()
-   instance = _instances.get(pid)
-   if instance is not None:
-   return instance
-
-   constructor = AsyncioEventLoop
-
-   # Use the _asyncio_wrapper attribute, so that unit tests can compare
-   # the reference to one retured from _wrap_loop(), since they should
-   # not close the loop if it refers to a global event loop.
-   instance = constructor()._asyncio_wrapper
-   _instances[pid] = instance
-   return instance
+from portage.util.futures._asyncio import _safe_loop as global_event_loop

diff --git a/lib/portage/util/futures/_asyncio/__init__.py 
b/lib/portage/util/futures/_asyncio/__init__.py
index d39f31786..5590963f1 100644
--- a/lib/portage/util/futures/_asyncio/__init__.py
+++ b/lib/portage/util/futures/_asyncio/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2020 Gentoo Authors
+# Copyright 2018-2021 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 __all__ = (
@@ -37,9 +37,6 @@ portage.proxy.lazyimport.lazyimport(globals(),
'portage.util.futures:compat_coroutine@_compat_coroutine',
 )
 from portage.util._eventloop.asyncio_event_loop import AsyncioEventLoop as 
_AsyncioEventLoop
-from portage.util._eventloop.global_event_loop import (
-   global_event_loop as _global_event_loop,
-)
 # pylint: disable=redefined-builtin
 from portage.util.futures.futures import (
CancelledError,
@@ -238,7 +235,7 @@ def _wrap_loop(loop=None):
# The default loop returned by _wrap_loop should be consistent
# with global_event_loop, in order to avoid accidental registration
# of callbacks with a loop that is not intended to run.
-   loop = loop or _global_event_loop()
+   loop = loop or _safe_loop()
return (loop if hasattr(loop, '_asyncio_wrapper')
else _AsyncioEventLoop(loop=loop))
 
@@ -267,13 +264,15 @@ def _safe_loop():
@rtype: asyncio.AbstractEventLoop (or compatible)
@return: event loop instance
"""
-   if portage._internal_caller or threading.current_thread() is 
threading.main_thread():
-   return _global_event_loop()
+   loop = _get_running_loop()
+   if loop is not None:
+   return loop
 
thread_key = threading.get_ident()
with _thread_weakrefs.lock:
if _thread_weakrefs.pid != portage.getpid():
_thread_weakrefs.pid = portage.getpid()
+   _thread_weakrefs.mainloop = None
_thread_weakrefs.loops = weakref.WeakValueDictionary()
try:
loop = _thread_weakrefs.loops[thread_key]
@@ -283,9 +282,23 @@ def _safe_loop():
except RuntimeError:

_real_asyncio.set_event_loop(_real_asyncio.new_event_loop())
loop = _thread_weakrefs.loops[thread_key] = 
_AsyncioEventLoop()
+
+   if _thread_weakrefs.mainloop is None and threading.current_thread() is 
threading.main_thread():
+   _thread_weakrefs.mainloop = loop
+

[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2021-01-10 Thread Zac Medico
commit: eeeb70bf50994c08ebcddac94474105f0635360c
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Jan 11 06:46:49 2021 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Jan 11 07:28:28 2021 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=eeeb70bf

AsyncioEventLoop: wrap child watcher for thread safety (bug 764905)

Use a child watcher wrapper to deliver the callbacks via the
call_soon_threadsafe method, since documentation for the asycio
AbstractChildWatcher class says that callbacks must be thread
safe.

Bug: https://bugs.gentoo.org/764905
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 30 ++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index 4d7047ae8..b77728088 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -6,6 +6,7 @@ import signal
 
 import asyncio as _real_asyncio
 from asyncio.events import AbstractEventLoop as _AbstractEventLoop
+from asyncio.unix_events import AbstractChildWatcher as _AbstractChildWatcher
 
 import portage
 
@@ -47,6 +48,7 @@ class AsyncioEventLoop(_AbstractEventLoop):
self.set_debug = loop.set_debug
self.get_debug = loop.get_debug
self._wakeup_fd = -1
+   self._child_watcher = None
 
if portage._internal_caller:

loop.set_exception_handler(self._internal_caller_exception_handler)
@@ -87,7 +89,9 @@ class AsyncioEventLoop(_AbstractEventLoop):
@rtype: asyncio.AbstractChildWatcher
@return: the internal event loop's AbstractChildWatcher 
interface
"""
-   return _real_asyncio.get_child_watcher()
+   if self._child_watcher is None:
+   self._child_watcher = 
_ChildWatcherThreadSafetyWrapper(self, _real_asyncio.get_child_watcher())
+   return self._child_watcher
 
@property
def _asyncio_wrapper(self):
@@ -126,3 +130,27 @@ class AsyncioEventLoop(_AbstractEventLoop):
except ValueError:
# This is intended to fail when not called in 
the main thread.
pass
+
+
+class _ChildWatcherThreadSafetyWrapper(_AbstractChildWatcher):
+   def __init__(self, loop, real_watcher):
+   self._loop = loop
+   self._real_watcher = real_watcher
+
+   def close(self):
+   pass
+
+   def __enter__(self):
+   return self
+
+   def __exit__(self, a, b, c):
+   pass
+
+   def _child_exit(self, pid, status, callback, *args):
+   self._loop.call_soon_threadsafe(callback, pid, status, *args)
+
+   def add_child_handler(self, pid, callback, *args):
+   self._real_watcher.add_child_handler(pid, self._child_exit, 
callback, *args)
+
+   def remove_child_handler(self, pid):
+   return self._real_watcher.remove_child_handler(pid)



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/, lib/portage/util/futures/_asyncio/

2020-12-06 Thread Zac Medico
commit: cecd2f8a259cf2991f2324c9a14e26170ba0ddcf
Author: Zac Medico  gentoo  org>
AuthorDate: Sun Dec  6 09:25:17 2020 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Dec  7 02:32:27 2020 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=cecd2f8a

Use default asyncio event loop implementation in API consumer threads

Make the _safe_loop function return an AsyncioEventLoop instance,
so that the default asyncio event loop implementation will be used
in API consumer threads. This is possible because the underlying
asyncio.get_event_loop() function returns a separate  event loop for
each thread. The AsyncioEventLoop _run_until_complete method will
now appropriately handle a ValueError from signal.set_wakeup_fd(-1)
if it is not called in the main thread.

For external API consumers calling from a non-main thread, an
asyncio loop must be registered for the current thread, or else an
error will be raised like this:

  RuntimeError: There is no current event loop in thread 'Thread-1'.

In order to avoid this RuntimeError, the external API consumer
is responsible for setting an event loop and managing its lifecycle.
For example, this code will set an event loop for the current thread:

  asyncio.set_event_loop(asyncio.new_event_loop())

In order to avoid a ResourceWarning, the caller should also close
the corresponding loop before the current thread terminates.

Bug: https://bugs.gentoo.org/758755
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py |  6 +-
 lib/portage/util/futures/_asyncio/__init__.py | 26 +--
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index 836f1c30a..4d7047ae8 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -121,4 +121,8 @@ class AsyncioEventLoop(_AbstractEventLoop):
try:
return self._loop.run_until_complete(future)
finally:
-   self._wakeup_fd = signal.set_wakeup_fd(-1)
+   try:
+   self._wakeup_fd = signal.set_wakeup_fd(-1)
+   except ValueError:
+   # This is intended to fail when not called in 
the main thread.
+   pass

diff --git a/lib/portage/util/futures/_asyncio/__init__.py 
b/lib/portage/util/futures/_asyncio/__init__.py
index a902ad895..6f3395a91 100644
--- a/lib/portage/util/futures/_asyncio/__init__.py
+++ b/lib/portage/util/futures/_asyncio/__init__.py
@@ -34,7 +34,6 @@ import portage
 portage.proxy.lazyimport.lazyimport(globals(),
'portage.util.futures.unix_events:_PortageEventLoopPolicy',
'portage.util.futures:compat_coroutine@_compat_coroutine',
-   'portage.util._eventloop.EventLoop:EventLoop@_EventLoop',
 )
 from portage.util._eventloop.asyncio_event_loop import AsyncioEventLoop as 
_AsyncioEventLoop
 from portage.util._eventloop.global_event_loop import (
@@ -246,14 +245,27 @@ def _wrap_loop(loop=None):
 def _safe_loop():
"""
Return an event loop that's safe to use within the current context.
-   For portage internal callers, this returns a globally shared event
-   loop instance. For external API consumers, this constructs a
-   temporary event loop instance that's safe to use in a non-main
-   thread (it does not override the global SIGCHLD handler).
+   For portage internal callers or external API consumers calling from
+   the main thread, this returns a globally shared event loop instance.
+
+   For external API consumers calling from a non-main thread, an
+   asyncio loop must be registered for the current thread, or else an
+   error will be raised like this:
+
+ RuntimeError: There is no current event loop in thread 'Thread-1'.
+
+   In order to avoid this RuntimeError, the external API consumer
+   is responsible for setting an event loop and managing its lifecycle.
+   For example, this code will set an event loop for the current thread:
+
+ asyncio.set_event_loop(asyncio.new_event_loop())
+
+   In order to avoid a ResourceWarning, the caller should also close the
+   corresponding loop before the current thread terminates.
 
@rtype: asyncio.AbstractEventLoop (or compatible)
@return: event loop instance
"""
-   if portage._internal_caller:
+   if portage._internal_caller or threading.current_thread() is 
threading.main_thread():
return _global_event_loop()
-   return _EventLoop(main=False)
+   return _AsyncioEventLoop()



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/, lib/portage/, lib/portage/util/futures/, ...

2020-07-17 Thread Michał Górny
commit: 070b5268486d5a1443a0dc6c1317c704c1298218
Author: Michał Górny  gentoo  org>
AuthorDate: Fri Jul 17 04:38:42 2020 +
Commit: Michał Górny  gentoo  org>
CommitDate: Fri Jul 17 06:36:19 2020 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=070b5268

Remove support code for Python < 3.4

Reviewed-by: Zac Medico  gentoo.org>
Closes: https://github.com/gentoo/portage/pull/576
Signed-off-by: Michał Górny  gentoo.org>

 lib/_emerge/AsynchronousLock.py  | 12 +-
 lib/_emerge/EbuildMetadataPhase.py   | 12 +-
 lib/_emerge/FifoIpcDaemon.py | 30 +---
 lib/_emerge/PipeReader.py| 12 +-
 lib/_emerge/SpawnProcess.py  | 16 -
 lib/portage/dbapi/_MergeProcess.py   | 10 
 lib/portage/locks.py | 11 -
 lib/portage/process.py   |  2 +-
 lib/portage/util/_async/PipeLogger.py| 10 
 lib/portage/util/_eventloop/EventLoop.py | 23 --
 lib/portage/util/_eventloop/global_event_loop.py | 15 +---
 lib/portage/util/futures/_asyncio/__init__.py| 26 +++-
 lib/portage/util/futures/unix_events.py  |  4 +---
 13 files changed, 20 insertions(+), 163 deletions(-)

diff --git a/lib/_emerge/AsynchronousLock.py b/lib/_emerge/AsynchronousLock.py
index aed1bcb15..d2a6773ff 100644
--- a/lib/_emerge/AsynchronousLock.py
+++ b/lib/_emerge/AsynchronousLock.py
@@ -1,4 +1,4 @@
-# Copyright 2010-2018 Gentoo Foundation
+# Copyright 2010-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import fcntl
@@ -192,16 +192,6 @@ class _LockProcess(AbstractPollTask):
fcntl.fcntl(in_pr, fcntl.F_SETFL,
fcntl.fcntl(in_pr, fcntl.F_GETFL) | os.O_NONBLOCK)
 
-   # FD_CLOEXEC is enabled by default in Python >=3.4.
-   if sys.hexversion < 0x304:
-   try:
-   fcntl.FD_CLOEXEC
-   except AttributeError:
-   pass
-   else:
-   fcntl.fcntl(in_pr, fcntl.F_SETFD,
-   fcntl.fcntl(in_pr, fcntl.F_GETFD) | 
fcntl.FD_CLOEXEC)
-
self.scheduler.add_reader(in_pr, self._output_handler)
self._registered = True
self._proc = SpawnProcess(

diff --git a/lib/_emerge/EbuildMetadataPhase.py 
b/lib/_emerge/EbuildMetadataPhase.py
index efe71892c..d00f194c2 100644
--- a/lib/_emerge/EbuildMetadataPhase.py
+++ b/lib/_emerge/EbuildMetadataPhase.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2018 Gentoo Foundation
+# Copyright 1999-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.SubProcess import SubProcess
@@ -93,16 +93,6 @@ class EbuildMetadataPhase(SubProcess):
fcntl.fcntl(master_fd, fcntl.F_SETFL,
fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
 
-   # FD_CLOEXEC is enabled by default in Python >=3.4.
-   if sys.hexversion < 0x304:
-   try:
-   fcntl.FD_CLOEXEC
-   except AttributeError:
-   pass
-   else:
-   fcntl.fcntl(master_fd, fcntl.F_SETFD,
-   fcntl.fcntl(master_fd, fcntl.F_GETFD) | 
fcntl.FD_CLOEXEC)
-
fd_pipes[slave_fd] = slave_fd
settings["PORTAGE_PIPE_FD"] = str(slave_fd)
 

diff --git a/lib/_emerge/FifoIpcDaemon.py b/lib/_emerge/FifoIpcDaemon.py
index 2ec69d1cb..ab1fdb572 100644
--- a/lib/_emerge/FifoIpcDaemon.py
+++ b/lib/_emerge/FifoIpcDaemon.py
@@ -1,14 +1,8 @@
-# Copyright 2010-2018 Gentoo Foundation
+# Copyright 2010-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import sys
 
-try:
-   import fcntl
-except ImportError:
-   #  http://bugs.jython.org/issue1074
-   fcntl = None
-
 from portage import os
 from _emerge.AbstractPollTask import AbstractPollTask
 from portage.cache.mappings import slot_dict_class
@@ -28,17 +22,6 @@ class FifoIpcDaemon(AbstractPollTask):
self._files.pipe_in = \
os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK)
 
-   # FD_CLOEXEC is enabled by default in Python >=3.4.
-   if sys.hexversion < 0x304 and fcntl is not None:
-   try:
-   fcntl.FD_CLOEXEC
-   except AttributeError:
-   pass
-   else:
-   fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFD,
-   

[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/, lib/portage/tests/util/futures/, ...

2020-07-14 Thread Michał Górny
commit: 4501ca0e3dd4b2924c2ee13b6203e2ad094557e9
Author: Michał Górny  gentoo  org>
AuthorDate: Tue Jul 14 18:39:58 2020 +
Commit: Michał Górny  gentoo  org>
CommitDate: Tue Jul 14 19:41:35 2020 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=4501ca0e

Remove unnecessary time.monotonic() compat

time.monotonic() is available since py3.3, so there's no need for
the compat anymore.

Reviewed-by: Zac Medico  gentoo.org>
Closes: https://github.com/gentoo/portage/pull/569
Signed-off-by: Michał Górny  gentoo.org>

 lib/portage/dbapi/vartree.py |  7 +++---
 lib/portage/tests/util/futures/test_retry.py |  8 +++
 lib/portage/util/_eventloop/EventLoop.py |  6 ++---
 lib/portage/util/monotonic.py| 34 
 4 files changed, 10 insertions(+), 45 deletions(-)

diff --git a/lib/portage/dbapi/vartree.py b/lib/portage/dbapi/vartree.py
index 3687b471b..80ca0ab80 100644
--- a/lib/portage/dbapi/vartree.py
+++ b/lib/portage/dbapi/vartree.py
@@ -1,4 +1,4 @@
-# Copyright 1998-2019 Gentoo Authors
+# Copyright 1998-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import division, unicode_literals
@@ -36,7 +36,6 @@ portage.proxy.lazyimport.lazyimport(globals(),
'portage.util.install_mask:install_mask_dir,InstallMask,_raise_exc',
'portage.util.listdir:dircache,listdir',
'portage.util.movefile:movefile',
-   'portage.util.monotonic:monotonic',
'portage.util.path:first_existing,iter_parents',
'portage.util.writeable_check:get_ro_checker',
'portage.util._xattr:xattr',
@@ -3616,7 +3615,7 @@ class dblink(object):
symlink_collisions = []
destroot = self.settings['ROOT']
totfiles = len(file_list) + len(symlink_list)
-   previous = monotonic()
+   previous = time.monotonic()
progress_shown = False
report_interval = 1.7  # seconds
falign = len("%d" % totfiles)
@@ -3625,7 +3624,7 @@ class dblink(object):
for i, (f, f_type) in enumerate(chain(
((f, "reg") for f in file_list),
((f, "sym") for f in symlink_list))):
-   current = monotonic()
+   current = time.monotonic()
if current - previous > report_interval:
showMessage(_("%3d%% done,  %*d files 
remaining ...\n") %
(i * 100 / totfiles, 
falign, totfiles - i))

diff --git a/lib/portage/tests/util/futures/test_retry.py 
b/lib/portage/tests/util/futures/test_retry.py
index 7a1e76280..4530bba83 100644
--- a/lib/portage/tests/util/futures/test_retry.py
+++ b/lib/portage/tests/util/futures/test_retry.py
@@ -1,4 +1,4 @@
-# Copyright 2018 Gentoo Foundation
+# Copyright 2018-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 try:
@@ -12,6 +12,7 @@ except ImportError:
import dummy_threading as threading
 
 import sys
+import time
 
 from portage.tests import TestCase
 from portage.util._eventloop.global_event_loop import global_event_loop
@@ -19,7 +20,6 @@ from portage.util.backoff import RandomExponentialBackoff
 from portage.util.futures import asyncio
 from portage.util.futures.retry import retry
 from portage.util.futures.executor.fork import ForkExecutor
-from portage.util.monotonic import monotonic
 
 
 class SucceedLaterException(Exception):
@@ -31,12 +31,12 @@ class SucceedLater(object):
A callable object that succeeds some duration of time has passed.
"""
def __init__(self, duration):
-   self._succeed_time = monotonic() + duration
+   self._succeed_time = time.monotonic() + duration
 
def __call__(self):
loop = global_event_loop()
result = loop.create_future()
-   remaining = self._succeed_time - monotonic()
+   remaining = self._succeed_time - time.monotonic()
if remaining > 0:
loop.call_soon_threadsafe(lambda: None if result.done() 
else
result.set_exception(SucceedLaterException(

diff --git a/lib/portage/util/_eventloop/EventLoop.py 
b/lib/portage/util/_eventloop/EventLoop.py
index ffd12cff9..a3bea97aa 100644
--- a/lib/portage/util/_eventloop/EventLoop.py
+++ b/lib/portage/util/_eventloop/EventLoop.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2018 Gentoo Foundation
+# Copyright 1999-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import division
@@ -11,6 +11,7 @@ import os
 import select
 import signal
 import sys
+import time
 import traceback
 
 try:

[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2020-03-01 Thread Zac Medico
commit: 30150206fb0b3e013ef5b163b8d2f24c70a9d977
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Mar  2 04:56:49 2020 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Mar  2 05:01:06 2020 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=30150206

AsyncioEventLoop: always die with SIGTERM in exception handler (bug 705910)

Remove call to pdb.set_trace() in exception handler, since it's
not very useful, and always die with a SIGTERM for unexpected
exceptions here.

Bug: https://bugs.gentoo.org/705910
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 31 +++
 1 file changed, 9 insertions(+), 22 deletions(-)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index a11a10205..ce7e06923 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -1,10 +1,8 @@
-# Copyright 2018 Gentoo Foundation
+# Copyright 2018-2020 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import os
-import pdb
 import signal
-import sys
 
 try:
import asyncio as _real_asyncio
@@ -69,25 +67,14 @@ class AsyncioEventLoop(_AbstractEventLoop):
"""
loop.default_exception_handler(context)
if 'exception' in context:
-   # If we have a tty then start the debugger, since in 
might
-   # aid in diagnosis of the problem. If there's no tty, 
then
-   # exit immediately.
-   if all(s.isatty() for s in (sys.stdout, sys.stderr, 
sys.stdin)):
-   # Restore default SIGINT handler, since 
emerge's Scheduler
-   # has a SIGINT handler which delays exit until 
after
-   # cleanup, and cleanup cannot occur here since 
the event
-   # loop is suspended (see bug 672540).
-   signal.signal(signal.SIGINT, signal.SIG_DFL)
-   pdb.set_trace()
-   else:
-   # Normally emerge will wait for all coroutines 
to complete
-   # after SIGTERM has been received. However, an 
unhandled
-   # exception will prevent the interrupted 
coroutine from
-   # completing, therefore use the default SIGTERM 
handler
-   # in order to ensure that emerge exits 
immediately (though
-   # uncleanly).
-   signal.signal(signal.SIGTERM, signal.SIG_DFL)
-   os.kill(os.getpid(), signal.SIGTERM)
+   # Normally emerge will wait for all coroutines to 
complete
+   # after SIGTERM has been received. However, an unhandled
+   # exception will prevent the interrupted coroutine from
+   # completing, therefore use the default SIGTERM handler
+   # in order to ensure that emerge exits immediately 
(though
+   # uncleanly).
+   signal.signal(signal.SIGTERM, signal.SIG_DFL)
+   os.kill(os.getpid(), signal.SIGTERM)
 
def _create_future(self):
"""



[gentoo-commits] proj/portage:master commit in: lib/portage/util/_eventloop/

2019-04-15 Thread Zac Medico
commit: ee1f6ff69887dfa02d5c3a3ab3d61163fa504d15
Author: Zac Medico  gentoo  org>
AuthorDate: Tue Apr 16 01:33:29 2019 +
Commit: Zac Medico  gentoo  org>
CommitDate: Tue Apr 16 01:40:29 2019 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=ee1f6ff6

AsyncioEventLoop: enable SIGINT in exception handler (bug 672540)

Before the exception handler invokes the pdb shell, enable SIGINT so
that the user can exit with Control-C (otherwise SIGKILL is needed).

Bug: https://bugs.gentoo.org/672540
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/_eventloop/asyncio_event_loop.py | 5 +
 1 file changed, 5 insertions(+)

diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py 
b/lib/portage/util/_eventloop/asyncio_event_loop.py
index ea0e03b23..a11a10205 100644
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
@@ -73,6 +73,11 @@ class AsyncioEventLoop(_AbstractEventLoop):
# aid in diagnosis of the problem. If there's no tty, 
then
# exit immediately.
if all(s.isatty() for s in (sys.stdout, sys.stderr, 
sys.stdin)):
+   # Restore default SIGINT handler, since 
emerge's Scheduler
+   # has a SIGINT handler which delays exit until 
after
+   # cleanup, and cleanup cannot occur here since 
the event
+   # loop is suspended (see bug 672540).
+   signal.signal(signal.SIGINT, signal.SIG_DFL)
pdb.set_trace()
else:
# Normally emerge will wait for all coroutines 
to complete