17db96d56Sopenharmony_ci"""This test case provides support for checking forking and wait behavior.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciTo test different wait behavior, override the wait_impl method.
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ciWe want fork1() semantics -- only the forking thread survives in the
67db96d56Sopenharmony_cichild after a fork().
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ciOn some systems (e.g. Solaris without posix threads) we find that all
97db96d56Sopenharmony_ciactive threads survive in the child after a fork(); this is an error.
107db96d56Sopenharmony_ci"""
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciimport os, sys, time, unittest
137db96d56Sopenharmony_ciimport threading
147db96d56Sopenharmony_cifrom test import support
157db96d56Sopenharmony_cifrom test.support import threading_helper
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ciLONGSLEEP = 2
197db96d56Sopenharmony_ciSHORTSLEEP = 0.5
207db96d56Sopenharmony_ciNUM_THREADS = 4
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ciclass ForkWait(unittest.TestCase):
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci    def setUp(self):
257db96d56Sopenharmony_ci        self._threading_key = threading_helper.threading_setup()
267db96d56Sopenharmony_ci        self.alive = {}
277db96d56Sopenharmony_ci        self.stop = 0
287db96d56Sopenharmony_ci        self.threads = []
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci    def tearDown(self):
317db96d56Sopenharmony_ci        # Stop threads
327db96d56Sopenharmony_ci        self.stop = 1
337db96d56Sopenharmony_ci        for thread in self.threads:
347db96d56Sopenharmony_ci            thread.join()
357db96d56Sopenharmony_ci        thread = None
367db96d56Sopenharmony_ci        self.threads.clear()
377db96d56Sopenharmony_ci        threading_helper.threading_cleanup(*self._threading_key)
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci    def f(self, id):
407db96d56Sopenharmony_ci        while not self.stop:
417db96d56Sopenharmony_ci            self.alive[id] = os.getpid()
427db96d56Sopenharmony_ci            try:
437db96d56Sopenharmony_ci                time.sleep(SHORTSLEEP)
447db96d56Sopenharmony_ci            except OSError:
457db96d56Sopenharmony_ci                pass
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci    def wait_impl(self, cpid, *, exitcode):
487db96d56Sopenharmony_ci        support.wait_process(cpid, exitcode=exitcode)
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_ci    def test_wait(self):
517db96d56Sopenharmony_ci        for i in range(NUM_THREADS):
527db96d56Sopenharmony_ci            thread = threading.Thread(target=self.f, args=(i,))
537db96d56Sopenharmony_ci            thread.start()
547db96d56Sopenharmony_ci            self.threads.append(thread)
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ci        # busy-loop to wait for threads
577db96d56Sopenharmony_ci        deadline = time.monotonic() + support.SHORT_TIMEOUT
587db96d56Sopenharmony_ci        while len(self.alive) < NUM_THREADS:
597db96d56Sopenharmony_ci            time.sleep(0.1)
607db96d56Sopenharmony_ci            if deadline < time.monotonic():
617db96d56Sopenharmony_ci                break
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci        a = sorted(self.alive.keys())
647db96d56Sopenharmony_ci        self.assertEqual(a, list(range(NUM_THREADS)))
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci        prefork_lives = self.alive.copy()
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci        if sys.platform in ['unixware7']:
697db96d56Sopenharmony_ci            cpid = os.fork1()
707db96d56Sopenharmony_ci        else:
717db96d56Sopenharmony_ci            cpid = os.fork()
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci        if cpid == 0:
747db96d56Sopenharmony_ci            # Child
757db96d56Sopenharmony_ci            time.sleep(LONGSLEEP)
767db96d56Sopenharmony_ci            n = 0
777db96d56Sopenharmony_ci            for key in self.alive:
787db96d56Sopenharmony_ci                if self.alive[key] != prefork_lives[key]:
797db96d56Sopenharmony_ci                    n += 1
807db96d56Sopenharmony_ci            os._exit(n)
817db96d56Sopenharmony_ci        else:
827db96d56Sopenharmony_ci            # Parent
837db96d56Sopenharmony_ci            self.wait_impl(cpid, exitcode=0)
84