|  | @@ -21,6 +21,7 @@ import itertools
 | 
	
		
			
				|  |  |  import collections
 | 
	
		
			
				|  |  |  import time
 | 
	
		
			
				|  |  |  import signal
 | 
	
		
			
				|  |  | +import warnings
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from multiprocessing import Process, cpu_count, TimeoutError
 | 
	
		
			
				|  |  |  from multiprocessing import util
 | 
	
	
		
			
				|  | @@ -267,7 +268,7 @@ class TaskHandler(PoolThread):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class TimeoutHandler(PoolThread):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def __init__(self, processes, cache, t_soft, t_hard, putlock):
 | 
	
		
			
				|  |  | +    def __init__(self, processes, cache, t_soft, t_hard):
 | 
	
		
			
				|  |  |          self.processes = processes
 | 
	
		
			
				|  |  |          self.cache = cache
 | 
	
		
			
				|  |  |          self.t_soft = t_soft
 | 
	
	
		
			
				|  | @@ -278,7 +279,6 @@ class TimeoutHandler(PoolThread):
 | 
	
		
			
				|  |  |      def body(self):
 | 
	
		
			
				|  |  |          processes = self.processes
 | 
	
		
			
				|  |  |          cache = self.cache
 | 
	
		
			
				|  |  | -        putlock = self.putlock
 | 
	
		
			
				|  |  |          t_hard, t_soft = self.t_hard, self.t_soft
 | 
	
		
			
				|  |  |          dirty = set()
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -492,9 +492,10 @@ class Pool(object):
 | 
	
		
			
				|  |  |          self._initializer = initializer
 | 
	
		
			
				|  |  |          self._initargs = initargs
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if self.soft_timeout and SIG_SOFT_TIMEOUT is None:
 | 
	
		
			
				|  |  | -            raise NotImplementedError("Soft timeouts not supported: "
 | 
	
		
			
				|  |  | -                    "Your platform does not have the SIGUSR1 signal.")
 | 
	
		
			
				|  |  | +        if soft_timeout and SIG_SOFT_TIMEOUT is None:
 | 
	
		
			
				|  |  | +            warnings.warn(UserWarning("Soft timeouts are not supported: "
 | 
	
		
			
				|  |  | +                    "on this platform: It does not have the SIGUSR1 signal."))
 | 
	
		
			
				|  |  | +            soft_timeout = None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if processes is None:
 | 
	
		
			
				|  |  |              try:
 | 
	
	
		
			
				|  | @@ -521,13 +522,10 @@ class Pool(object):
 | 
	
		
			
				|  |  |          self._task_handler.start()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # Thread killing timedout jobs.
 | 
	
		
			
				|  |  | +        self._timeout_handler = None
 | 
	
		
			
				|  |  | +        self._timeout_handler_mutex = threading.Lock()
 | 
	
		
			
				|  |  |          if self.timeout is not None or self.soft_timeout is not None:
 | 
	
		
			
				|  |  | -            self._timeout_handler = self.TimeoutHandler(
 | 
	
		
			
				|  |  | -                    self._pool, self._cache,
 | 
	
		
			
				|  |  | -                    self.soft_timeout, self.timeout, self._putlock)
 | 
	
		
			
				|  |  | -            self._timeout_handler.start()
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            self._timeout_handler = None
 | 
	
		
			
				|  |  | +            self._start_timeout_handler()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # Thread processing results in the outqueue.
 | 
	
		
			
				|  |  |          self._result_handler = self.ResultHandler(self._outqueue,
 | 
	
	
		
			
				|  | @@ -665,6 +663,19 @@ class Pool(object):
 | 
	
		
			
				|  |  |              return False, None
 | 
	
		
			
				|  |  |          self._poll_result = _poll_result
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    def _start_timeout_handler(self):
 | 
	
		
			
				|  |  | +        # ensure more than one thread does not start the timeout handler
 | 
	
		
			
				|  |  | +        # thread at once.
 | 
	
		
			
				|  |  | +        self._timeout_handler_mutex.acquire()
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            if self._timeout_handler is None:
 | 
	
		
			
				|  |  | +                self._timeout_handler = self.TimeoutHandler(
 | 
	
		
			
				|  |  | +                        self._pool, self._cache,
 | 
	
		
			
				|  |  | +                        self.soft_timeout, self.timeout)
 | 
	
		
			
				|  |  | +                self._timeout_handler.start()
 | 
	
		
			
				|  |  | +        finally:
 | 
	
		
			
				|  |  | +            self._timeout_handler_mutex.release()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      def apply(self, func, args=(), kwds={}):
 | 
	
		
			
				|  |  |          '''
 | 
	
		
			
				|  |  |          Equivalent of `apply()` builtin
 | 
	
	
		
			
				|  | @@ -736,6 +747,10 @@ class Pool(object):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          '''
 | 
	
		
			
				|  |  |          assert self._state == RUN
 | 
	
		
			
				|  |  | +        if soft_timeout and SIG_SOFT_TIMEOUT is None:
 | 
	
		
			
				|  |  | +            warnings.warn(UserWarning("Soft timeouts are not supported: "
 | 
	
		
			
				|  |  | +                    "on this platform: It does not have the SIGUSR1 signal."))
 | 
	
		
			
				|  |  | +            soft_timeout = None
 | 
	
		
			
				|  |  |          result = ApplyResult(self._cache, callback,
 | 
	
		
			
				|  |  |                               accept_callback, timeout_callback,
 | 
	
		
			
				|  |  |                               error_callback, soft_timeout, timeout)
 | 
	
	
		
			
				|  | @@ -744,6 +759,9 @@ class Pool(object):
 | 
	
		
			
				|  |  |              self._putlock.acquire()
 | 
	
		
			
				|  |  |              if self._state != RUN:
 | 
	
		
			
				|  |  |                  return
 | 
	
		
			
				|  |  | +        if timeout or soft_timeout:
 | 
	
		
			
				|  |  | +            # start the timeout handler thread when required.
 | 
	
		
			
				|  |  | +            self._start_timeout_handler()
 | 
	
		
			
				|  |  |          self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
 | 
	
		
			
				|  |  |          return result
 | 
	
		
			
				|  |  |  
 |