]> granicus.if.org Git - python/commitdiff
Issue #7242: On Solaris 9 and earlier calling os.fork() from within a
authorGregory P. Smith <greg@mad-scientist.com>
Mon, 1 Mar 2010 01:22:39 +0000 (01:22 +0000)
committerGregory P. Smith <greg@mad-scientist.com>
Mon, 1 Mar 2010 01:22:39 +0000 (01:22 +0000)
thread could raise an incorrect RuntimeError about not holding the import
lock.  The import lock is now reinitialized after fork.

Lib/test/test_thread.py
Misc/NEWS
Modules/posixmodule.c
Python/import.c

index 134ac3b7ca7c17ab02596967a00b2eaf31dbec15..4e707e5a13f162833ae9daa99bee0cdf27e36711 100644 (file)
@@ -4,6 +4,7 @@ import random
 from test import test_support
 import thread
 import time
+import sys
 import weakref
 
 from test import lock_tests
@@ -196,8 +197,47 @@ class LockTests(lock_tests.LockTests):
     locktype = thread.allocate_lock
 
 
+class TestForkInThread(unittest.TestCase):
+    def setUp(self):
+        self.read_fd, self.write_fd = os.pipe()
+
+    def test_forkinthread(self):
+        if sys.platform.startswith('win'):
+            from test.test_support import TestSkipped
+            raise TestSkipped("This test is only appropriate for "
+                              "POSIX-like systems.")
+        def thread1():
+            try:
+                pid = os.fork() # fork in a thread
+            except RuntimeError:
+                sys.exit(0) # exit the child
+
+            if pid == 0: # child
+                os.close(self.read_fd)
+                os.write(self.write_fd, "OK")
+                sys.exit(0)
+            else: # parent
+                os.close(self.write_fd)
+
+        thread.start_new_thread(thread1, ())
+        self.assertEqual(os.read(self.read_fd, 2), "OK",
+                         "Unable to fork() in thread")
+
+    def tearDown(self):
+        try:
+            os.close(self.read_fd)
+        except OSError:
+            pass
+
+        try:
+            os.close(self.write_fd)
+        except OSError:
+            pass
+
+
 def test_main():
-    test_support.run_unittest(ThreadRunningTests, BarrierTest, LockTests)
+    test_support.run_unittest(ThreadRunningTests, BarrierTest, LockTests,
+                              TestForkInThread)
 
 if __name__ == "__main__":
     test_main()
index 2e765a93c96ecc6da0c626a1eb06cad2795bb339..184c028f66f91e6793584b84375133639a4840de 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -87,6 +87,10 @@ Extension Modules
 - Stop providing crtassem.h symbols when compiling with Visual Studio 2010, as
   msvcr100.dll is not a platform assembly anymore.
 
+- Issue #7242: On Solaris 9 and earlier calling os.fork() from within a
+  thread could raise an incorrect RuntimeError about not holding the import
+  lock.  The import lock is now reinitialized after fork.
+
 Tests
 -----
 
index 46053febdb69920b8928084546a367f861bb4245..45128d32b8e4927c5b006dbdc83051340ef52804 100644 (file)
@@ -3605,14 +3605,18 @@ static PyObject *
 posix_fork1(PyObject *self, PyObject *noargs)
 {
        pid_t pid;
-       int result;
+       int result = 0;
        _PyImport_AcquireLock();
        pid = fork1();
-       result = _PyImport_ReleaseLock();
+       if (pid == 0) {
+               /* child: this clobbers and resets the import lock. */
+               PyOS_AfterFork();
+       } else {
+               /* parent: release the import lock. */
+               result = _PyImport_ReleaseLock();
+       }
        if (pid == -1)
                return posix_error();
-       if (pid == 0)
-               PyOS_AfterFork();
        if (result < 0) {
                /* Don't clobber the OSError if the fork failed. */
                PyErr_SetString(PyExc_RuntimeError,
@@ -3634,14 +3638,18 @@ static PyObject *
 posix_fork(PyObject *self, PyObject *noargs)
 {
        pid_t pid;
-       int result;
+       int result = 0;
        _PyImport_AcquireLock();
        pid = fork();
-       result = _PyImport_ReleaseLock();
+       if (pid == 0) {
+               /* child: this clobbers and resets the import lock. */
+               PyOS_AfterFork();
+       } else {
+               /* parent: release the import lock. */
+               result = _PyImport_ReleaseLock();
+       }
        if (pid == -1)
                return posix_error();
-       if (pid == 0)
-               PyOS_AfterFork();
        if (result < 0) {
                /* Don't clobber the OSError if the fork failed. */
                PyErr_SetString(PyExc_RuntimeError,
@@ -3759,11 +3767,12 @@ posix_forkpty(PyObject *self, PyObject *noargs)
 
        _PyImport_AcquireLock();
        pid = forkpty(&master_fd, NULL, NULL, NULL);
+       if (pid == 0)
+               PyOS_AfterFork();
+
        result = _PyImport_ReleaseLock();
        if (pid == -1)
                return posix_error();
-       if (pid == 0)
-               PyOS_AfterFork();
        if (result < 0) {
                /* Don't clobber the OSError if the fork failed. */
                PyErr_SetString(PyExc_RuntimeError,
index c25c4f0345e4f40fafa2db6bd61214c6ba0470a9..eb50bc56f1ba54364e1c6d30530f4b63ae71a0c9 100644 (file)
@@ -301,14 +301,18 @@ _PyImport_ReleaseLock(void)
        return 1;
 }
 
-/* This function used to be called from PyOS_AfterFork to ensure that newly
-   created child processes do not share locks with the parent, but for some
-   reason only on AIX systems. Instead of re-initializing the lock, we now
-   acquire the import lock around fork() calls. */
+/* This function is called from PyOS_AfterFork to ensure that newly
+   created child processes do not share locks with the parent.
+   We now acquire the import lock around fork() calls but on some platforms
+   (Solaris 9 and earlier? see isue7242) that still left us with problems. */
 
 void
 _PyImport_ReInitLock(void)
 {
+       if (import_lock != NULL)
+               import_lock = PyThread_allocate_lock();
+       import_lock_thread = -1;
+       import_lock_level = 0;
 }
 
 #endif