Title: [278380] trunk/Tools
Revision
278380
Author
jbed...@apple.com
Date
2021-06-02 16:10:10 -0700 (Wed, 02 Jun 2021)

Log Message

[webkitcorepy] TaskPool shouldn't fork when 1 process is needed
https://bugs.webkit.org/show_bug.cgi?id=226506
<rdar://problem/78724554>

Reviewed by Dewei Zhu.

* Scripts/libraries/webkitcorepy/setup.py: Bump version.
* Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Ditto.
* Scripts/libraries/webkitcorepy/webkitcorepy/task_pool.py:
(TaskPool.__init__): Allow user to force fork, even with a single process.
(TaskPool.__enter__): If only a single worker is needed and the caller is not forcing
a fork, run the setup function in the parent process.
(TaskPool.do): If no queue has been constructed, we're running in the parent process.
(TaskPool.wait): Nothing to wait for if we're running in the parent process.
(TaskPool.__exit__): If no queue has been constructed, we're running in the parent process,
so run the teardown in this process and reset the process name.
* Scripts/libraries/webkitcorepy/webkitcorepy/tests/task_pool_unittest.py:
(TaskPoolUnittest.test_single): Force fork.
(TaskPoolUnittest.test_single_no_fork):
(TaskPoolUnittest.test_exception): Force fork.
(TaskPoolUnittest.test_exception_no_fork):
(TaskPoolUnittest.test_invalid_shutdown): Force fork.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (278379 => 278380)


--- trunk/Tools/ChangeLog	2021-06-02 22:31:09 UTC (rev 278379)
+++ trunk/Tools/ChangeLog	2021-06-02 23:10:10 UTC (rev 278380)
@@ -1,3 +1,28 @@
+2021-06-02  Jonathan Bedard  <jbed...@apple.com>
+
+        [webkitcorepy] TaskPool shouldn't fork when 1 process is needed
+        https://bugs.webkit.org/show_bug.cgi?id=226506
+        <rdar://problem/78724554>
+
+        Reviewed by Dewei Zhu.
+
+        * Scripts/libraries/webkitcorepy/setup.py: Bump version.
+        * Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Ditto.
+        * Scripts/libraries/webkitcorepy/webkitcorepy/task_pool.py:
+        (TaskPool.__init__): Allow user to force fork, even with a single process.
+        (TaskPool.__enter__): If only a single worker is needed and the caller is not forcing
+        a fork, run the setup function in the parent process.
+        (TaskPool.do): If no queue has been constructed, we're running in the parent process.
+        (TaskPool.wait): Nothing to wait for if we're running in the parent process.
+        (TaskPool.__exit__): If no queue has been constructed, we're running in the parent process,
+        so run the teardown in this process and reset the process name.
+        * Scripts/libraries/webkitcorepy/webkitcorepy/tests/task_pool_unittest.py:
+        (TaskPoolUnittest.test_single): Force fork.
+        (TaskPoolUnittest.test_single_no_fork):
+        (TaskPoolUnittest.test_exception): Force fork.
+        (TaskPoolUnittest.test_exception_no_fork):
+        (TaskPoolUnittest.test_invalid_shutdown): Force fork.
+
 2021-06-02  W.D. Xiong  <w_xi...@apple.com>
         
         [resultsdbpy] "legend" is misspelled as "lengend"

Modified: trunk/Tools/Scripts/libraries/webkitcorepy/setup.py (278379 => 278380)


--- trunk/Tools/Scripts/libraries/webkitcorepy/setup.py	2021-06-02 22:31:09 UTC (rev 278379)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/setup.py	2021-06-02 23:10:10 UTC (rev 278380)
@@ -30,7 +30,7 @@
 
 setup(
     name='webkitcorepy',
-    version='0.5.15',
+    version='0.5.16',
     description='Library containing various Python support classes and functions.',
     long_description=readme(),
     classifiers=[

Modified: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py (278379 => 278380)


--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py	2021-06-02 22:31:09 UTC (rev 278379)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py	2021-06-02 23:10:10 UTC (rev 278380)
@@ -37,7 +37,7 @@
 from webkitcorepy.task_pool import TaskPool
 from webkitcorepy.credentials import credentials
 
-version = Version(0, 5, 15)
+version = Version(0, 5, 16)
 
 from webkitcorepy.autoinstall import Package, AutoInstall
 if sys.version_info > (3, 0):

Modified: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/task_pool.py (278379 => 278380)


--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/task_pool.py	2021-06-02 22:31:09 UTC (rev 278379)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/task_pool.py	2021-06-02 23:10:10 UTC (rev 278380)
@@ -159,6 +159,19 @@
             self.incoming.join_thread()
 
 
+class _DummyQueue(object):
+    def send(self, object):
+        if isinstance(object, _Message):
+            object(None)
+        return True
+
+    def receive(self, blocking=True):
+        pass
+
+    def close(self):
+        pass
+
+
 class _Process(object):
     name = None
     working = False
@@ -317,6 +330,7 @@
         self, workers=1, name=None, setup=None, teardown=None, grace_period=5, block_size=1000,
         setupargs=None, setupkwargs=None,
         teardownargs=None, teardownkwargs=None,
+        force_fork=False,
     ):
         # Ensure tblib is installed before creating child processes
         import tblib
@@ -332,8 +346,8 @@
         self.queue = None
         self.workers = []
 
-        self._setup_args = (setup, setupargs, setupkwargs)
-        self._teardown_args = (teardown, teardownargs, teardownkwargs)
+        self._setup_args = (setup, setupargs or [], setupkwargs or {})
+        self._teardown_args = (teardown, teardownargs or [], teardownkwargs or {})
         self._num_workers = int(workers)
 
         self._started = 0
@@ -342,8 +356,20 @@
         self._id_count = 0
         self.grace_period = grace_period
         self.block_size = block_size
+        self.force_fork = force_fork
 
+        if not self.force_fork and self._num_workers == 1 and TaskPool.Process.queue:
+            raise ValueError('Illegal single-process TaskPool nesting')
+
     def __enter__(self):
+        if not self.force_fork and self._num_workers == 1:
+            TaskPool.Process.queue = _DummyQueue()
+            TaskPool.Process.name = TaskPool.Process.name or '{}/0'.format(self.name)
+            if self._setup_args[0]:
+                self._setup_args[0](*self._setup_args[1], **self._setup_args[2])
+            TaskPool.Process.working = True
+            return self
+
         from mock import patch
 
         self.queue = self.BiDirectionalQueue()
@@ -362,10 +388,17 @@
                 worker.start()
             while self._started < len(self.workers):
                 self.queue.receive()(self)
+
         return self
 
     def do(self, function, *args, **kwargs):
         callback = kwargs.pop('callback', None)
+        if not self.queue:
+            result = function(*args, **kwargs)
+            if callback:
+                callback(result)
+            return
+
         if callback:
             self.callbacks[self._id_count] = callback
         self.queue.send(self.Task(function, self._id_count, *args, **kwargs))
@@ -380,6 +413,9 @@
                     break
 
     def wait(self):
+        if not self.queue:
+            return
+
         for _ in self.workers:
             self.queue.send(None)
 
@@ -387,6 +423,16 @@
             self.queue.receive()(self)
 
     def __exit__(self, *args, **kwargs):
+        if not self.queue:
+            TaskPool.Process.working = False
+            try:
+                if self._teardown_args[0]:
+                    self._teardown_args[0](*self._teardown_args[1], **self._teardown_args[2])
+            finally:
+                TaskPool.Process.queue = None
+                TaskPool.Process.name = None
+            return
+
         from six import reraise
         try:
             inflight = sys.exc_info()

Modified: trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/task_pool_unittest.py (278379 => 278380)


--- trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/task_pool_unittest.py	2021-06-02 22:31:09 UTC (rev 278379)
+++ trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/tests/task_pool_unittest.py	2021-06-02 23:10:10 UTC (rev 278380)
@@ -61,7 +61,7 @@
 
     def test_single(self):
         with OutputCapture(level=logging.WARNING) as captured:
-            with TaskPool(workers=1) as pool:
+            with TaskPool(workers=1, force_fork=True) as pool:
                 pool.do(action, 'a')
                 pool.do(log, logging.WARNING, '1')
                 pool.wait()
@@ -69,6 +69,16 @@
         self.assertEqual(captured.stdout.getvalue(), 'action(a)\n')
         self.assertEqual(captured.webkitcorepy.log.getvalue(), 'worker/0 1\n')
 
+    def test_single_no_fork(self):
+        with OutputCapture(level=logging.WARNING) as captured:
+            with TaskPool(workers=1, force_fork=False) as pool:
+                pool.do(action, 'a')
+                pool.do(log, logging.WARNING, '1')
+                pool.wait()
+
+        self.assertEqual(captured.stdout.getvalue(), 'action(a)\n')
+        self.assertEqual(captured.webkitcorepy.log.getvalue(), '1\n')
+
     def test_multiple(self):
         with OutputCapture(level=logging.INFO) as captured:
             with TaskPool(workers=4) as pool:
@@ -99,7 +109,7 @@
     def test_exception(self):
         with OutputCapture(level=logging.INFO) as captured:
             with self.assertRaises(RuntimeError):
-                with TaskPool(workers=1) as pool:
+                with TaskPool(workers=1, force_fork=True) as pool:
                     pool.do(exception, 'Testing exception')
                     pool.wait()
         self.assertEqual(
@@ -107,6 +117,14 @@
             ['worker/0 starting', 'worker/0 stopping'],
         )
 
+    def test_exception_no_fork(self):
+        with OutputCapture(level=logging.INFO) as captured:
+            with self.assertRaises(RuntimeError):
+                with TaskPool(workers=1, force_fork=False) as pool:
+                    pool.do(exception, 'Testing exception')
+                    pool.wait()
+        self.assertEqual(captured.webkitcorepy.log.getvalue(), '')
+
     def test_setup(self):
         with OutputCapture() as captured:
             with TaskPool(workers=4, setup=setup) as pool:
@@ -154,5 +172,5 @@
     def test_invalid_shutdown(self):
         with OutputCapture():
             with self.assertRaises(TaskPool.Exception):
-                with TaskPool(workers=1, teardown=teardown, grace_period=1) as pool:
+                with TaskPool(workers=1, teardown=teardown, grace_period=1, force_fork=True) as pool:
                     pool.do(wait, 2)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to