spack/lib/spack/llnl/util/multiproc.py
Massimiliano Culpo db6ef96e87
Finding compilers executes all queries first and then process them
The function calls to find compilers have been reorganized to:
1. Collect all the queries that are needed to detect compiler's version
2. Execute them on demand
3. Process the results and register compilers
2019-06-07 09:30:15 +02:00

99 lines
2.7 KiB
Python

# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""
This implements a parallel map operation but it can accept more values
than multiprocessing.Pool.apply() can. For example, apply() will fail
to pickle functions if they're passed indirectly as parameters.
"""
import functools
from multiprocessing import Semaphore, Value
__all__ = ['Barrier']
def deferred(func):
"""Package a function call into something that can be invoked
at a later moment.
Args:
func (callable): callable that must be deferred
Returns:
Deferred version of the same function
"""
@functools.wraps(func)
def _impl(*args, **kwargs):
def _deferred_call():
return func(*args, **kwargs)
return _deferred_call
return _impl
def invoke(f):
return f()
def execute(command_list, executor=map):
"""Execute a list of packaged commands and return their result.
Args:
command_list: list of commands to be executed
executor: object that execute each command. Must have the
same semantic as ``map``.
Returns:
List of results
"""
return executor(invoke, command_list)
class Barrier:
"""Simple reusable semaphore barrier.
Python 2.6 doesn't have multiprocessing barriers so we implement this.
See http://greenteapress.com/semaphores/downey08semaphores.pdf, p. 41.
"""
def __init__(self, n, timeout=None):
self.n = n
self.to = timeout
self.count = Value('i', 0)
self.mutex = Semaphore(1)
self.turnstile1 = Semaphore(0)
self.turnstile2 = Semaphore(1)
def wait(self):
if not self.mutex.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.count.value += 1
if self.count.value == self.n:
if not self.turnstile2.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.turnstile1.release()
self.mutex.release()
if not self.turnstile1.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.turnstile1.release()
if not self.mutex.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.count.value -= 1
if self.count.value == 0:
if not self.turnstile1.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.turnstile2.release()
self.mutex.release()
if not self.turnstile2.acquire(timeout=self.to):
raise BarrierTimeoutError()
self.turnstile2.release()
class BarrierTimeoutError(Exception):
pass