|
17 | 17 | import fcntl |
18 | 18 | except ImportError: |
19 | 19 | pass |
| 20 | +try: |
| 21 | + import multiprocessing |
| 22 | +except ImportError: |
| 23 | + multiprocessing = None |
20 | 24 |
|
21 | 25 |
|
22 | 26 | class TestBase(unittest.TestCase): |
@@ -994,28 +998,36 @@ def test_add_and_close(self): |
994 | 998 | self.assertEqual(contents, f.read()) |
995 | 999 | self._box = self._factory(self._path) |
996 | 1000 |
|
| 1001 | + @unittest.skipUnless(hasattr(os, 'fork'), "Test needs fork().") |
| 1002 | + @unittest.skipUnless(multiprocessing, "Test needs multiprocessing.") |
997 | 1003 | def test_lock_conflict(self): |
998 | | - # Fork off a subprocess that will lock the file for 2 seconds, |
999 | | - # unlock it, and then exit. |
1000 | | - if not hasattr(os, 'fork'): |
1001 | | - return |
| 1004 | + # Fork off a child process that will lock the mailbox temporarily, |
| 1005 | + # unlock it and exit. |
| 1006 | + ready = multiprocessing.Event() |
| 1007 | + done = multiprocessing.Event() |
| 1008 | + |
1002 | 1009 | pid = os.fork() |
1003 | 1010 | if pid == 0: |
1004 | | - # In the child, lock the mailbox. |
| 1011 | + # child |
1005 | 1012 | try: |
| 1013 | + # lock the mailbox, and signal the parent it can proceed |
1006 | 1014 | self._box.lock() |
1007 | | - time.sleep(2) |
| 1015 | + ready.set() |
| 1016 | + |
| 1017 | + # wait until the parent is done, and unlock the mailbox |
| 1018 | + done.wait(5) |
1008 | 1019 | self._box.unlock() |
1009 | 1020 | finally: |
1010 | 1021 | os._exit(0) |
1011 | 1022 |
|
1012 | | - # In the parent, sleep a bit to give the child time to acquire |
1013 | | - # the lock. |
1014 | | - time.sleep(0.5) |
| 1023 | + # In the parent, wait until the child signals it locked the mailbox. |
| 1024 | + ready.wait(5) |
1015 | 1025 | try: |
1016 | 1026 | self.assertRaises(mailbox.ExternalClashError, |
1017 | 1027 | self._box.lock) |
1018 | 1028 | finally: |
| 1029 | + # Signal the child it can now release the lock and exit. |
| 1030 | + done.set() |
1019 | 1031 | # Wait for child to exit. Locking should now succeed. |
1020 | 1032 | exited_pid, status = os.waitpid(pid, 0) |
1021 | 1033 |
|
|
0 commit comments