Kaydet (Commit) c57a84f4 authored tarafından Alexandre Vassalotti's avatar Alexandre Vassalotti

Merged revisions 73694,73708,73738 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r73694 | jesse.noller | 2009-06-29 14:24:26 -0400 (Mon, 29 Jun 2009) | 1 line

  Issue 5740: multiprocessing.connection.* authkey fixes
........
  r73708 | jesse.noller | 2009-06-30 13:11:52 -0400 (Tue, 30 Jun 2009) | 1 line

  Resolves issues 5155, 5313, 5331 - bad file descriptor error with processes in processes
........
  r73738 | r.david.murray | 2009-06-30 22:49:10 -0400 (Tue, 30 Jun 2009) | 2 lines

  Make punctuation prettier and break up run-on sentence.
........
üst 260484d1
...@@ -1715,7 +1715,7 @@ authentication* using the :mod:`hmac` module. ...@@ -1715,7 +1715,7 @@ authentication* using the :mod:`hmac` module.
generally be omitted since it can usually be inferred from the format of generally be omitted since it can usually be inferred from the format of
*address*. (See :ref:`multiprocessing-address-formats`) *address*. (See :ref:`multiprocessing-address-formats`)
If *authentication* is ``True`` or *authkey* is a string then digest If *authenticate* is ``True`` or *authkey* is a string then digest
authentication is used. The key used for authentication will be either authentication is used. The key used for authentication will be either
*authkey* or ``current_process().authkey)`` if *authkey* is ``None``. *authkey* or ``current_process().authkey)`` if *authkey* is ``None``.
If authentication fails then :exc:`AuthenticationError` is raised. See If authentication fails then :exc:`AuthenticationError` is raised. See
...@@ -1757,7 +1757,7 @@ authentication* using the :mod:`hmac` module. ...@@ -1757,7 +1757,7 @@ authentication* using the :mod:`hmac` module.
If *authkey* is ``None`` and *authenticate* is ``True`` then If *authkey* is ``None`` and *authenticate* is ``True`` then
``current_process().authkey`` is used as the authentication key. If ``current_process().authkey`` is used as the authentication key. If
*authkey* is ``None`` and *authentication* is ``False`` then no *authkey* is ``None`` and *authenticate* is ``False`` then no
authentication is done. If authentication fails then authentication is done. If authentication fails then
:exc:`AuthenticationError` is raised. See :ref:`multiprocessing-auth-keys`. :exc:`AuthenticationError` is raised. See :ref:`multiprocessing-auth-keys`.
...@@ -2099,6 +2099,38 @@ Explicitly pass resources to child processes ...@@ -2099,6 +2099,38 @@ Explicitly pass resources to child processes
for i in range(10): for i in range(10):
Process(target=f, args=(lock,)).start() Process(target=f, args=(lock,)).start()
Beware replacing sys.stdin with a "file like object"
:mod:`multiprocessing` originally unconditionally called::
os.close(sys.stdin.fileno())
in the :meth:`multiprocessing.Process._bootstrap` method --- this resulted
in issues with processes-in-processes. This has been changed to::
sys.stdin.close()
sys.stdin = open(os.devnull)
Which solves the fundamental issue of processes colliding with each other
resulting in a bad file descriptor error, but introduces a potential danger
to applications which replace :func:`sys.stdin` with a "file-like object"
with output buffering. This danger is that if multiple processes call
:func:`close()` on this file-like object, it could result in the same
data being flushed to the object multiple times, resulting in corruption.
If you write a file-like object and implement your own caching, you can
make it fork-safe by storing the pid whenever you append to the cache,
and discarding the cache when the pid changes. For example::
@property
def cache(self):
pid = os.getpid()
if pid != self._pid:
self._pid = pid
self._cache = []
return self._cache
For more information, see :issue:`5155`, :issue:`5313` and :issue:`5331`
Windows Windows
~~~~~~~ ~~~~~~~
......
...@@ -221,7 +221,8 @@ class Process(object): ...@@ -221,7 +221,8 @@ class Process(object):
self._counter = itertools.count(1) self._counter = itertools.count(1)
if sys.stdin is not None: if sys.stdin is not None:
try: try:
os.close(sys.stdin.fileno()) sys.stdin.close()
sys.stdin = open(os.devnull)
except (OSError, ValueError): except (OSError, ValueError):
pass pass
_current_process = self _current_process = self
......
...@@ -8,6 +8,7 @@ import unittest ...@@ -8,6 +8,7 @@ import unittest
import threading import threading
import queue as pyqueue import queue as pyqueue
import time import time
import io
import sys import sys
import os import os
import gc import gc
...@@ -1868,7 +1869,74 @@ class TestInitializers(unittest.TestCase): ...@@ -1868,7 +1869,74 @@ class TestInitializers(unittest.TestCase):
p.join() p.join()
self.assertEqual(self.ns.test, 1) self.assertEqual(self.ns.test, 1)
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers] #
# Issue 5155, 5313, 5331: Test process in processes
# Verifies os.close(sys.stdin.fileno) vs. sys.stdin.close() behavior
#
def _ThisSubProcess(q):
try:
item = q.get(block=False)
except pyqueue.Empty:
pass
def _TestProcess(q):
queue = multiprocessing.Queue()
subProc = multiprocessing.Process(target=_ThisSubProcess, args=(queue,))
subProc.start()
subProc.join()
def _afunc(x):
return x*x
def pool_in_process():
pool = multiprocessing.Pool(processes=4)
x = pool.map(_afunc, [1, 2, 3, 4, 5, 6, 7])
class _file_like(object):
def __init__(self, delegate):
self._delegate = delegate
self._pid = None
@property
def cache(self):
pid = os.getpid()
# There are no race conditions since fork keeps only the running thread
if pid != self._pid:
self._pid = pid
self._cache = []
return self._cache
def write(self, data):
self.cache.append(data)
def flush(self):
self._delegate.write(''.join(self.cache))
self._cache = []
class TestStdinBadfiledescriptor(unittest.TestCase):
def test_queue_in_process(self):
queue = multiprocessing.Queue()
proc = multiprocessing.Process(target=_TestProcess, args=(queue,))
proc.start()
proc.join()
def test_pool_in_process(self):
p = multiprocessing.Process(target=pool_in_process)
p.start()
p.join()
def test_flushing(self):
sio = io.StringIO()
flike = _file_like(sio)
flike.write('foo')
proc = multiprocessing.Process(target=lambda: flike.flush())
flike.flush()
assert sio.getvalue() == 'foo'
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
TestStdinBadfiledescriptor]
# #
# #
......
...@@ -46,6 +46,7 @@ Des Barry ...@@ -46,6 +46,7 @@ Des Barry
Ulf Bartelt Ulf Bartelt
Nick Bastin Nick Bastin
Jeff Bauer Jeff Bauer
Mike Bayer
Michael R Bax Michael R Bax
Anthony Baxter Anthony Baxter
Samuel L. Bayer Samuel L. Bayer
...@@ -185,6 +186,7 @@ Cesar Douady ...@@ -185,6 +186,7 @@ Cesar Douady
Dean Draayer Dean Draayer
John DuBois John DuBois
Paul Dubois Paul Dubois
Graham Dumpleton
Quinn Dunkan Quinn Dunkan
Robin Dunn Robin Dunn
Luke Dunstan Luke Dunstan
...@@ -558,6 +560,7 @@ Steven Pemberton ...@@ -558,6 +560,7 @@ Steven Pemberton
Santiago Peresón Santiago Peresón
Mark Perrego Mark Perrego
Trevor Perrin Trevor Perrin
Gabriel de Perthuis
Tim Peters Tim Peters
Benjamin Peterson Benjamin Peterson
Chris Petrilli Chris Petrilli
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment