| 117 | |
| 118 | @contextlib.contextmanager |
| 119 | def start_threads(threads, unlock=None): |
| 120 | try: |
| 121 | import faulthandler |
| 122 | except ImportError: |
| 123 | # It isn't supported on subinterpreters yet. |
| 124 | faulthandler = None |
| 125 | threads = list(threads) |
| 126 | started = [] |
| 127 | try: |
| 128 | try: |
| 129 | for t in threads: |
| 130 | t.start() |
| 131 | started.append(t) |
| 132 | except: |
| 133 | if support.verbose: |
| 134 | print("Can't start %d threads, only %d threads started" % |
| 135 | (len(threads), len(started))) |
| 136 | raise |
| 137 | yield |
| 138 | finally: |
| 139 | try: |
| 140 | if unlock: |
| 141 | unlock() |
| 142 | endtime = time.monotonic() |
| 143 | for timeout in range(1, 16): |
| 144 | endtime += 60 |
| 145 | for t in started: |
| 146 | t.join(max(endtime - time.monotonic(), 0.01)) |
| 147 | started = [t for t in started if t.is_alive()] |
| 148 | if not started: |
| 149 | break |
| 150 | if support.verbose: |
| 151 | print('Unable to join %d threads during a period of ' |
| 152 | '%d minutes' % (len(started), timeout)) |
| 153 | finally: |
| 154 | started = [t for t in started if t.is_alive()] |
| 155 | if started: |
| 156 | if faulthandler is not None: |
| 157 | faulthandler.dump_traceback(sys.stdout) |
| 158 | raise AssertionError('Unable to join %d threads' % len(started)) |
| 159 | |
| 160 | |
| 161 | class catch_threading_exception: |