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