|  | 
| 39 | 39 | from test.support import socket_helper | 
| 40 | 40 | from test.support import threading_helper | 
| 41 | 41 | from test.support import warnings_helper | 
| 42 |  | - | 
|  | 42 | +from test.support.script_helper import run_python_until_end | 
| 43 | 43 | 
 | 
| 44 | 44 | # Skip tests if _multiprocessing wasn't built. | 
| 45 | 45 | _multiprocessing = import_helper.import_module('_multiprocessing') | 
| @@ -7142,3 +7142,67 @@ class SemLock(_multiprocessing.SemLock): | 
| 7142 | 7142 |         name = f'test_semlock_subclass-{os.getpid()}' | 
| 7143 | 7143 |         s = SemLock(1, 0, 10, name, False) | 
| 7144 | 7144 |         _multiprocessing.sem_unlink(name) | 
|  | 7145 | + | 
|  | 7146 | + | 
|  | 7147 | +@unittest.skipIf(sys.platform != "linux", "Linux only") | 
|  | 7148 | +class ForkInThreads(unittest.TestCase): | 
|  | 7149 | + | 
|  | 7150 | +    def test_fork(self): | 
|  | 7151 | +        code = """ | 
|  | 7152 | +        import os, sys, threading, time | 
|  | 7153 | +
 | 
|  | 7154 | +        t = threading.Thread(target=time.sleep, args=(1,), daemon=True) | 
|  | 7155 | +        t.start() | 
|  | 7156 | +
 | 
|  | 7157 | +        assert threading.active_count() == 2 | 
|  | 7158 | +
 | 
|  | 7159 | +        pid = os.fork() | 
|  | 7160 | +        if pid < 0: | 
|  | 7161 | +            print("Fork failed") | 
|  | 7162 | +        elif pid == 0: | 
|  | 7163 | +            print("In child") | 
|  | 7164 | +            sys.exit(0) | 
|  | 7165 | +        print("In parent") | 
|  | 7166 | +        """ | 
|  | 7167 | + | 
|  | 7168 | +        res, _ = run_python_until_end("-c", code, PYTHONWARNINGS='always') | 
|  | 7169 | +        self.assertIn(b'In child', res.out) | 
|  | 7170 | +        self.assertIn(b'In parent', res.out) | 
|  | 7171 | +        self.assertIn(b'DeprecationWarning', res.err) | 
|  | 7172 | +        self.assertIn(b'is multi-threaded, use of fork() may lead to deadlocks in the child', res.err) | 
|  | 7173 | + | 
|  | 7174 | +        res, _ = run_python_until_end("-c", code, PYTHONWARNINGS='error') | 
|  | 7175 | +        self.assertIn(b'In child', res.out) | 
|  | 7176 | +        self.assertIn(b'In parent', res.out) | 
|  | 7177 | +        self.assertIn(b'DeprecationWarning', res.err) | 
|  | 7178 | +        self.assertIn(b'is multi-threaded, use of fork() may lead to deadlocks in the child', res.err) | 
|  | 7179 | + | 
|  | 7180 | +    def test_forkpty(self): | 
|  | 7181 | +        code = """ | 
|  | 7182 | +        import os, sys, threading, time | 
|  | 7183 | +
 | 
|  | 7184 | +        t = threading.Thread(target=time.sleep, args=(1,), daemon=True) | 
|  | 7185 | +        t.start() | 
|  | 7186 | +
 | 
|  | 7187 | +        assert threading.active_count() == 2 | 
|  | 7188 | +
 | 
|  | 7189 | +        pid, _ = os.forkpty() | 
|  | 7190 | +        if pid < 0: | 
|  | 7191 | +            print(f"forkpty failed") | 
|  | 7192 | +        elif pid == 0: | 
|  | 7193 | +            print(f"In child") | 
|  | 7194 | +            sys.exit(0) | 
|  | 7195 | +        print(f"In parent") | 
|  | 7196 | +        """ | 
|  | 7197 | + | 
|  | 7198 | +        res, _ = run_python_until_end("-c", code, PYTHONWARNINGS='always') | 
|  | 7199 | +        print(res) | 
|  | 7200 | +        self.assertIn(b'In parent', res.out) | 
|  | 7201 | +        self.assertIn(b'DeprecationWarning', res.err) | 
|  | 7202 | +        self.assertIn(b'is multi-threaded, use of forkpty() may lead to deadlocks in the child', res.err) | 
|  | 7203 | + | 
|  | 7204 | +        res, _ = run_python_until_end("-c", code, PYTHONWARNINGS='error') | 
|  | 7205 | +        print(res) | 
|  | 7206 | +        self.assertIn(b'In parent', res.out) | 
|  | 7207 | +        self.assertIn(b'DeprecationWarning', res.err) | 
|  | 7208 | +        self.assertIn(b'is multi-threaded, use of forkpty() may lead to deadlocks in the child', res.err) | 
0 commit comments