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