New GitHub issue #102512 from marmarek:<br>

<hr>

<pre>
<!--
 If you're new to Python and you're not sure whether what you're experiencing is a bug, the CPython issue tracker is not
  the right place to seek help. Consider the following options instead:

  - reading the Python tutorial: https://docs.python.org/3/tutorial/
  - posting in the "Users" category on discuss.python.org: https://discuss.python.org/c/users/7
  - emailing the Python-list mailing list: https://mail.python.org/mailman/listinfo/python-list
  - searching our issue tracker (https://github.com/python/cpython/issues) to see if
 your problem has already been reported
-->

# Bug report

`threading._shutdown()` relies on `_main_thread` having `_tstate_lock` not `None` (there is assert for that). When fork is called from a DummyThread (in my case, that's a thread created by (Py)Qt), it gets promoted to main thread, but remains very simplistic DummyThread. Especially, nobody initializes its `_tstate_lock`. `threading._after_fork()` handles the case of current thread not being in `_active` dict at all (by creating new MainThread object), but it doesn't handle the case of having DummyThread there already. This results in AssertionError in thread shutdown method - which for example confuses `multiprocessing.Process` (it gets exit code 1, even if the process function was successful).

Reproducer:
```
#!/usr/bin/python3

import threading
import multiprocessing
import _thread

class Bar(multiprocessing.Process):
    def run(self):
 print("process")

def run_thread(lock):
    # the call to current_thread() is crucial for reproducer - it allocates
    # DummyThread()
    print(f"thread: {threading.current_thread()}")
 p = Bar()
    p.start()
    p.join()
    print(f"proc exit code: {p.exitcode}")
    lock.release()


def main():
    lock = _thread.allocate_lock()
    lock.acquire()
    t = _thread.start_new_thread(run_thread, (lock,))
    # t.join
 lock.acquire()
    print(f"thread exit")

main()
```

It should print:
```
thread: <_DummyThread(Dummy-1, started daemon 135243893053120)>
process
proc exit code: 0
thread exit
```
but it prints:
```
thread: <_DummyThread(Dummy-1, started daemon 135243893053120)>
process
proc exit code: 1
thread exit
```
(see exit code difference)

`multiprocessing.Process` (or rather `multiprocessing.popen_fork.Popen._launch()` to be specific) swallows the exception, but adding some debug prints there I get:
```
Traceback (most recent call last):
  File "/usr/lib64/python3.11/multiprocessing/popen_fork.py", line 71, in _launch
    code = process_obj._bootstrap(parent_sentinel=child_r)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/multiprocessing/process.py", line 332, in _bootstrap
    threading._shutdown()
  File "/usr/lib64/python3.11/threading.py", line 1553, in _shutdown
    assert tlock is not None
           ^^^^^^^^^^^^^^^^^
```

# Your environment

<!-- Include as many relevant details as possible about the environment you experienced the bug in -->

- CPython versions tested on: 3.11.2
- Operating system and architecture: Fedora 37, x86_64


</pre>

<hr>

<a href="https://github.com/python/cpython/issues/102512">View on GitHub</a>
<p>Labels: type-bug</p>
<p>Assignee: </p>