| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Module implementing synchronization primitives | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # multiprocessing/synchronize.py | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2010-12-14 01:38:16 +00:00
										 |  |  | # Copyright (c) 2006-2008, R Oudkerk | 
					
						
							| 
									
										
										
										
											2012-04-30 12:13:55 +01:00
										 |  |  | # Licensed to PSF under a Contributor Agreement. | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = [ | 
					
						
							|  |  |  |     'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition', 'Event' | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import threading | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | import tempfile | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | import _multiprocessing | 
					
						
							| 
									
										
										
										
											2018-07-06 13:51:52 +02:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  | from . import context | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | from . import process | 
					
						
							|  |  |  | from . import util | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 00:06:14 -08:00
										 |  |  | # TODO: Do any platforms still lack a functioning sem_open? | 
					
						
							| 
									
										
											  
											
												Merged revisions 66670,66681,66688,66696-66699 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
  r66670 | georg.brandl | 2008-09-28 15:01:36 -0500 (Sun, 28 Sep 2008) | 2 lines
  Don't show version in title.
........
  r66681 | georg.brandl | 2008-09-29 11:51:35 -0500 (Mon, 29 Sep 2008) | 2 lines
  Update nasm location.
........
  r66688 | jesse.noller | 2008-09-29 19:15:45 -0500 (Mon, 29 Sep 2008) | 2 lines
  issue3770: if SEM_OPEN is 0, disable the mp.synchronize module, rev. Nick Coghlan, Damien Miller
........
  r66696 | andrew.kuchling | 2008-09-30 07:31:07 -0500 (Tue, 30 Sep 2008) | 1 line
  Edits, and add markup
........
  r66697 | andrew.kuchling | 2008-09-30 08:00:34 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fix
........
  r66698 | andrew.kuchling | 2008-09-30 08:00:51 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes
........
  r66699 | andrew.kuchling | 2008-09-30 08:01:46 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes.  (optparse.rst probably needs an entire revision pass.)
........
											
										 
											2008-10-04 22:00:42 +00:00
										 |  |  | try: | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     from _multiprocessing import SemLock, sem_unlink | 
					
						
							| 
									
										
										
										
											2024-11-07 00:06:14 -08:00
										 |  |  | except ImportError: | 
					
						
							| 
									
										
											  
											
												Merged revisions 66670,66681,66688,66696-66699 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
  r66670 | georg.brandl | 2008-09-28 15:01:36 -0500 (Sun, 28 Sep 2008) | 2 lines
  Don't show version in title.
........
  r66681 | georg.brandl | 2008-09-29 11:51:35 -0500 (Mon, 29 Sep 2008) | 2 lines
  Update nasm location.
........
  r66688 | jesse.noller | 2008-09-29 19:15:45 -0500 (Mon, 29 Sep 2008) | 2 lines
  issue3770: if SEM_OPEN is 0, disable the mp.synchronize module, rev. Nick Coghlan, Damien Miller
........
  r66696 | andrew.kuchling | 2008-09-30 07:31:07 -0500 (Tue, 30 Sep 2008) | 1 line
  Edits, and add markup
........
  r66697 | andrew.kuchling | 2008-09-30 08:00:34 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fix
........
  r66698 | andrew.kuchling | 2008-09-30 08:00:51 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes
........
  r66699 | andrew.kuchling | 2008-09-30 08:01:46 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes.  (optparse.rst probably needs an entire revision pass.)
........
											
										 
											2008-10-04 22:00:42 +00:00
										 |  |  |     raise ImportError("This platform lacks a functioning sem_open" + | 
					
						
							| 
									
										
										
										
											2024-11-07 00:06:14 -08:00
										 |  |  |                       " implementation. https://github.com/python/cpython/issues/48020.") | 
					
						
							| 
									
										
											  
											
												Merged revisions 66670,66681,66688,66696-66699 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
  r66670 | georg.brandl | 2008-09-28 15:01:36 -0500 (Sun, 28 Sep 2008) | 2 lines
  Don't show version in title.
........
  r66681 | georg.brandl | 2008-09-29 11:51:35 -0500 (Mon, 29 Sep 2008) | 2 lines
  Update nasm location.
........
  r66688 | jesse.noller | 2008-09-29 19:15:45 -0500 (Mon, 29 Sep 2008) | 2 lines
  issue3770: if SEM_OPEN is 0, disable the mp.synchronize module, rev. Nick Coghlan, Damien Miller
........
  r66696 | andrew.kuchling | 2008-09-30 07:31:07 -0500 (Tue, 30 Sep 2008) | 1 line
  Edits, and add markup
........
  r66697 | andrew.kuchling | 2008-09-30 08:00:34 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fix
........
  r66698 | andrew.kuchling | 2008-09-30 08:00:51 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes
........
  r66699 | andrew.kuchling | 2008-09-30 08:01:46 -0500 (Tue, 30 Sep 2008) | 1 line
  Markup fixes.  (optparse.rst probably needs an entire revision pass.)
........
											
										 
											2008-10-04 22:00:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Constants | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 00:06:14 -08:00
										 |  |  | # These match the enum in Modules/_multiprocessing/semaphore.c | 
					
						
							|  |  |  | RECURSIVE_MUTEX = 0 | 
					
						
							|  |  |  | SEMAPHORE = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | SEM_VALUE_MAX = _multiprocessing.SemLock.SEM_VALUE_MAX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Base class for semaphores and mutexes; wraps `_multiprocessing.SemLock` | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SemLock(object): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     _rand = tempfile._RandomNameSequence() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, kind, value, maxvalue, *, ctx): | 
					
						
							| 
									
										
										
										
											2014-03-23 11:54:15 +00:00
										 |  |  |         if ctx is None: | 
					
						
							|  |  |  |             ctx = context._default_context.get_context() | 
					
						
							| 
									
										
										
										
											2023-08-30 13:07:41 -04:00
										 |  |  |         self._is_fork_ctx = ctx.get_start_method() == 'fork' | 
					
						
							|  |  |  |         unlink_now = sys.platform == 'win32' or self._is_fork_ctx | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         for i in range(100): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 sl = self._semlock = _multiprocessing.SemLock( | 
					
						
							|  |  |  |                     kind, value, maxvalue, self._make_name(), | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |                     unlink_now) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             except FileExistsError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise FileExistsError('cannot find name for semaphore') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         util.debug('created semlock with handle %s' % sl.handle) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         self._make_methods() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if sys.platform != 'win32': | 
					
						
							|  |  |  |             def _after_fork(obj): | 
					
						
							|  |  |  |                 obj._semlock._after_fork() | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             util.register_after_fork(self, _after_fork) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self._semlock.name is not None: | 
					
						
							|  |  |  |             # We only get here if we are on Unix with forking | 
					
						
							|  |  |  |             # disabled.  When the object is garbage collected or the | 
					
						
							|  |  |  |             # process shuts down we unlink the semaphore name | 
					
						
							| 
									
										
										
										
											2019-05-10 22:59:08 +02:00
										 |  |  |             from .resource_tracker import register | 
					
						
							|  |  |  |             register(self._semlock.name, "semaphore") | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             util.Finalize(self, SemLock._cleanup, (self._semlock.name,), | 
					
						
							|  |  |  |                           exitpriority=0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _cleanup(name): | 
					
						
							| 
									
										
										
										
											2019-05-10 22:59:08 +02:00
										 |  |  |         from .resource_tracker import unregister | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         sem_unlink(name) | 
					
						
							| 
									
										
										
										
											2019-05-10 22:59:08 +02:00
										 |  |  |         unregister(name, "semaphore") | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _make_methods(self): | 
					
						
							|  |  |  |         self.acquire = self._semlock.acquire | 
					
						
							|  |  |  |         self.release = self._semlock.release | 
					
						
							| 
									
										
										
										
											2009-06-01 23:14:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 11:14:12 +03:00
										 |  |  |     def locked(self): | 
					
						
							| 
									
										
										
										
											2025-04-17 11:41:30 +02:00
										 |  |  |         return self._semlock._is_zero() | 
					
						
							| 
									
										
										
										
											2025-04-08 11:14:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-01 23:14:51 +00:00
										 |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self._semlock.__enter__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *args): | 
					
						
							|  |  |  |         return self._semlock.__exit__(*args) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getstate__(self): | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |         context.assert_spawning(self) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         sl = self._semlock | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         if sys.platform == 'win32': | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |             h = context.get_spawning_popen().duplicate_for_child(sl.handle) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-08-30 13:07:41 -04:00
										 |  |  |             if self._is_fork_ctx: | 
					
						
							| 
									
										
										
										
											2023-08-23 16:27:35 -04:00
										 |  |  |                 raise RuntimeError('A SemLock created in a fork context is being ' | 
					
						
							|  |  |  |                                    'shared with a process in a spawn context. This is ' | 
					
						
							|  |  |  |                                    'not supported. Please use the same context to create ' | 
					
						
							|  |  |  |                                    'multiprocessing objects and Process.') | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             h = sl.handle | 
					
						
							|  |  |  |         return (h, sl.kind, sl.maxvalue, sl.name) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __setstate__(self, state): | 
					
						
							|  |  |  |         self._semlock = _multiprocessing.SemLock._rebuild(*state) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         util.debug('recreated blocker with handle %r' % state[0]) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         self._make_methods() | 
					
						
							| 
									
										
										
										
											2023-08-30 13:07:41 -04:00
										 |  |  |         # Ensure that deserialized SemLock can be serialized again (gh-108520). | 
					
						
							|  |  |  |         self._is_fork_ctx = False | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _make_name(): | 
					
						
							| 
									
										
										
										
											2013-11-02 17:05:07 +00:00
										 |  |  |         return '%s-%s' % (process.current_process()._config['semprefix'], | 
					
						
							|  |  |  |                           next(SemLock._rand)) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Semaphore | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Semaphore(SemLock): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, value=1, *, ctx): | 
					
						
							|  |  |  |         SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_value(self): | 
					
						
							|  |  |  |         return self._semlock._get_value() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             value = self._semlock._get_value() | 
					
						
							|  |  |  |         except Exception: | 
					
						
							|  |  |  |             value = 'unknown' | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         return '<%s(value=%s)>' % (self.__class__.__name__, value) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Bounded semaphore | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BoundedSemaphore(Semaphore): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, value=1, *, ctx): | 
					
						
							|  |  |  |         SemLock.__init__(self, SEMAPHORE, value, value, ctx=ctx) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             value = self._semlock._get_value() | 
					
						
							|  |  |  |         except Exception: | 
					
						
							|  |  |  |             value = 'unknown' | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         return '<%s(value=%s, maxvalue=%s)>' % \ | 
					
						
							|  |  |  |                (self.__class__.__name__, value, self._semlock.maxvalue) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Non-recursive lock | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Lock(SemLock): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, *, ctx): | 
					
						
							|  |  |  |         SemLock.__init__(self, SEMAPHORE, 1, 1, ctx=ctx) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if self._semlock._is_mine(): | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                 name = process.current_process().name | 
					
						
							| 
									
										
										
										
											2008-08-19 19:17:39 +00:00
										 |  |  |                 if threading.current_thread().name != 'MainThread': | 
					
						
							|  |  |  |                     name += '|' + threading.current_thread().name | 
					
						
							| 
									
										
										
										
											2024-11-07 09:10:57 +01:00
										 |  |  |             elif not self._semlock._is_zero(): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |                 name = 'None' | 
					
						
							|  |  |  |             elif self._semlock._count() > 0: | 
					
						
							|  |  |  |                 name = 'SomeOtherThread' | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 name = 'SomeOtherProcess' | 
					
						
							|  |  |  |         except Exception: | 
					
						
							|  |  |  |             name = 'unknown' | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         return '<%s(owner=%s)>' % (self.__class__.__name__, name) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Recursive lock | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RLock(SemLock): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, *, ctx): | 
					
						
							|  |  |  |         SemLock.__init__(self, RECURSIVE_MUTEX, 1, 1, ctx=ctx) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if self._semlock._is_mine(): | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                 name = process.current_process().name | 
					
						
							| 
									
										
										
										
											2008-08-19 19:17:39 +00:00
										 |  |  |                 if threading.current_thread().name != 'MainThread': | 
					
						
							|  |  |  |                     name += '|' + threading.current_thread().name | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |                 count = self._semlock._count() | 
					
						
							| 
									
										
										
										
											2024-11-07 09:10:57 +01:00
										 |  |  |             elif not self._semlock._is_zero(): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |                 name, count = 'None', 0 | 
					
						
							|  |  |  |             elif self._semlock._count() > 0: | 
					
						
							|  |  |  |                 name, count = 'SomeOtherThread', 'nonzero' | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 name, count = 'SomeOtherProcess', 'nonzero' | 
					
						
							|  |  |  |         except Exception: | 
					
						
							|  |  |  |             name, count = 'unknown', 'unknown' | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         return '<%s(%s, %s)>' % (self.__class__.__name__, name, count) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Condition variable | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Condition(object): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, lock=None, *, ctx): | 
					
						
							|  |  |  |         self._lock = lock or ctx.RLock() | 
					
						
							|  |  |  |         self._sleeping_count = ctx.Semaphore(0) | 
					
						
							|  |  |  |         self._woken_count = ctx.Semaphore(0) | 
					
						
							|  |  |  |         self._wait_semaphore = ctx.Semaphore(0) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         self._make_methods() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getstate__(self): | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |         context.assert_spawning(self) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         return (self._lock, self._sleeping_count, | 
					
						
							|  |  |  |                 self._woken_count, self._wait_semaphore) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setstate__(self, state): | 
					
						
							|  |  |  |         (self._lock, self._sleeping_count, | 
					
						
							|  |  |  |          self._woken_count, self._wait_semaphore) = state | 
					
						
							|  |  |  |         self._make_methods() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-01 23:14:51 +00:00
										 |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self._lock.__enter__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *args): | 
					
						
							|  |  |  |         return self._lock.__exit__(*args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     def _make_methods(self): | 
					
						
							|  |  |  |         self.acquire = self._lock.acquire | 
					
						
							|  |  |  |         self.release = self._lock.release | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             num_waiters = (self._sleeping_count._semlock._get_value() - | 
					
						
							|  |  |  |                            self._woken_count._semlock._get_value()) | 
					
						
							|  |  |  |         except Exception: | 
					
						
							| 
									
										
										
										
											2013-05-15 18:06:56 +02:00
										 |  |  |             num_waiters = 'unknown' | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         return '<%s(%s, %s)>' % (self.__class__.__name__, self._lock, num_waiters) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def wait(self, timeout=None): | 
					
						
							|  |  |  |         assert self._lock._semlock._is_mine(), \ | 
					
						
							|  |  |  |                'must acquire() condition before using wait()' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # indicate that this thread is going to sleep | 
					
						
							|  |  |  |         self._sleeping_count.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # release lock | 
					
						
							|  |  |  |         count = self._lock._semlock._count() | 
					
						
							|  |  |  |         for i in range(count): | 
					
						
							|  |  |  |             self._lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # wait for notification or timeout | 
					
						
							| 
									
										
										
										
											2012-06-04 18:59:07 +01:00
										 |  |  |             return self._wait_semaphore.acquire(True, timeout) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             # indicate that this thread has woken | 
					
						
							|  |  |  |             self._woken_count.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # reacquire lock | 
					
						
							|  |  |  |             for i in range(count): | 
					
						
							|  |  |  |                 self._lock.acquire() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-04 08:59:22 +02:00
										 |  |  |     def notify(self, n=1): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         assert self._lock._semlock._is_mine(), 'lock is not owned' | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |         assert not self._wait_semaphore.acquire( | 
					
						
							| 
									
										
										
										
											2020-08-17 09:38:55 -04:00
										 |  |  |             False), ('notify: Should not have been able to acquire ' | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |                      + '_wait_semaphore') | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # to take account of timeouts since last notify*() we subtract | 
					
						
							|  |  |  |         # woken_count from sleeping_count and rezero woken_count | 
					
						
							|  |  |  |         while self._woken_count.acquire(False): | 
					
						
							|  |  |  |             res = self._sleeping_count.acquire(False) | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |             assert res, ('notify: Bug in sleeping_count.acquire' | 
					
						
							|  |  |  |                          + '- res should not be False') | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         sleepers = 0 | 
					
						
							| 
									
										
										
										
											2017-07-04 08:59:22 +02:00
										 |  |  |         while sleepers < n and self._sleeping_count.acquire(False): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             self._wait_semaphore.release()        # wake up one sleeper | 
					
						
							|  |  |  |             sleepers += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if sleepers: | 
					
						
							|  |  |  |             for i in range(sleepers): | 
					
						
							|  |  |  |                 self._woken_count.acquire()       # wait for a sleeper to wake | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # rezero wait_semaphore in case some timeouts just happened | 
					
						
							|  |  |  |             while self._wait_semaphore.acquire(False): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-04 08:59:22 +02:00
										 |  |  |     def notify_all(self): | 
					
						
							|  |  |  |         self.notify(n=sys.maxsize) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:45:57 +02:00
										 |  |  |     def wait_for(self, predicate, timeout=None): | 
					
						
							|  |  |  |         result = predicate() | 
					
						
							|  |  |  |         if result: | 
					
						
							|  |  |  |             return result | 
					
						
							|  |  |  |         if timeout is not None: | 
					
						
							| 
									
										
										
										
											2018-07-06 13:51:52 +02:00
										 |  |  |             endtime = time.monotonic() + timeout | 
					
						
							| 
									
										
										
										
											2012-04-17 18:45:57 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             endtime = None | 
					
						
							|  |  |  |             waittime = None | 
					
						
							|  |  |  |         while not result: | 
					
						
							|  |  |  |             if endtime is not None: | 
					
						
							| 
									
										
										
										
											2018-07-06 13:51:52 +02:00
										 |  |  |                 waittime = endtime - time.monotonic() | 
					
						
							| 
									
										
										
										
											2012-04-17 18:45:57 +02:00
										 |  |  |                 if waittime <= 0: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             self.wait(waittime) | 
					
						
							|  |  |  |             result = predicate() | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Event | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Event(object): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, *, ctx): | 
					
						
							|  |  |  |         self._cond = ctx.Condition(ctx.Lock()) | 
					
						
							|  |  |  |         self._flag = ctx.Semaphore(0) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_set(self): | 
					
						
							| 
									
										
										
										
											2014-05-25 14:12:12 +01:00
										 |  |  |         with self._cond: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             if self._flag.acquire(False): | 
					
						
							|  |  |  |                 self._flag.release() | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set(self): | 
					
						
							| 
									
										
										
										
											2014-05-25 14:12:12 +01:00
										 |  |  |         with self._cond: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             self._flag.acquire(False) | 
					
						
							|  |  |  |             self._flag.release() | 
					
						
							|  |  |  |             self._cond.notify_all() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def clear(self): | 
					
						
							| 
									
										
										
										
											2014-05-25 14:12:12 +01:00
										 |  |  |         with self._cond: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             self._flag.acquire(False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def wait(self, timeout=None): | 
					
						
							| 
									
										
										
										
											2014-05-25 14:12:12 +01:00
										 |  |  |         with self._cond: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             if self._flag.acquire(False): | 
					
						
							|  |  |  |                 self._flag.release() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self._cond.wait(timeout) | 
					
						
							| 
									
										
										
											
												Merged revisions 70908,70939,71009,71022,71036 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
  r70908 | jesse.noller | 2009-03-31 17:20:35 -0500 (Tue, 31 Mar 2009) | 1 line
  Issue 5619: Pass MS CRT debug flags into subprocesses
........
  r70939 | jesse.noller | 2009-03-31 22:45:50 -0500 (Tue, 31 Mar 2009) | 1 line
  Fix multiprocessing.event to match the new threading.Event API
........
  r71009 | jesse.noller | 2009-04-01 19:03:28 -0500 (Wed, 01 Apr 2009) | 1 line
  issue5545: Switch to Autoconf for multiprocessing; special thanks to Martin Lowis for help
........
  r71022 | jesse.noller | 2009-04-01 21:32:55 -0500 (Wed, 01 Apr 2009) | 1 line
  Issue 3110: Additional protection for SEM_VALUE_MAX on platforms, thanks to Martin Loewis
........
  r71036 | jesse.noller | 2009-04-01 23:22:09 -0500 (Wed, 01 Apr 2009) | 1 line
  Issue 3551: Raise ValueError if the size causes ERROR_NO_SYSTEM_RESOURCES
........
											
										 
											2009-04-05 21:24:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if self._flag.acquire(False): | 
					
						
							|  |  |  |                 self._flag.release() | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2012-06-15 18:26:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-30 00:31:54 -08:00
										 |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2021-12-09 18:46:45 +05:30
										 |  |  |         set_status = 'set' if self.is_set() else 'unset' | 
					
						
							|  |  |  |         return f"<{type(self).__qualname__} at {id(self):#x} {set_status}>" | 
					
						
							| 
									
										
										
										
											2012-06-15 18:26:07 +01:00
										 |  |  | # | 
					
						
							|  |  |  | # Barrier | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Barrier(threading.Barrier): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |     def __init__(self, parties, action=None, timeout=None, *, ctx): | 
					
						
							| 
									
										
										
										
											2012-06-15 18:26:07 +01:00
										 |  |  |         import struct | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         from .heap import BufferWrapper | 
					
						
							| 
									
										
										
										
											2012-06-15 18:26:07 +01:00
										 |  |  |         wrapper = BufferWrapper(struct.calcsize('i') * 2) | 
					
						
							| 
									
										
										
										
											2013-10-16 16:41:56 +01:00
										 |  |  |         cond = ctx.Condition() | 
					
						
							| 
									
										
										
										
											2012-06-15 18:26:07 +01:00
										 |  |  |         self.__setstate__((parties, action, timeout, cond, wrapper)) | 
					
						
							|  |  |  |         self._state = 0 | 
					
						
							|  |  |  |         self._count = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __setstate__(self, state): | 
					
						
							|  |  |  |         (self._parties, self._action, self._timeout, | 
					
						
							|  |  |  |          self._cond, self._wrapper) = state | 
					
						
							|  |  |  |         self._array = self._wrapper.create_memoryview().cast('i') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getstate__(self): | 
					
						
							|  |  |  |         return (self._parties, self._action, self._timeout, | 
					
						
							|  |  |  |                 self._cond, self._wrapper) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def _state(self): | 
					
						
							|  |  |  |         return self._array[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @_state.setter | 
					
						
							|  |  |  |     def _state(self, value): | 
					
						
							|  |  |  |         self._array[0] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def _count(self): | 
					
						
							|  |  |  |         return self._array[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @_count.setter | 
					
						
							|  |  |  |     def _count(self, value): | 
					
						
							|  |  |  |         self._array[1] = value |