blob: b9bc74a2ebac7cc210c6a52aaa9fa6ee39edcf95 [file] [log] [blame]
#!/bin/bash
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# For routines we want to use in ebuild-helpers/ but don't want to
# expose to the general ebuild environment.
source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
#
# API functions for doing parallel processing
#
makeopts_jobs() {
# Copied from eutils.eclass:makeopts_jobs()
local jobs=$(echo " ${MAKEOPTS} " | \
sed -r -n 's:.*[[:space:]](-j|--jobs[=[:space:]])[[:space:]]*([0-9]+).*:\2:p')
echo ${jobs:-1}
}
__multijob_init() {
# Setup a pipe for children to write their pids to when they finish.
# We have to allocate two fd's because POSIX has undefined behavior
# when you open a FIFO for simultaneous read/write. #487056
local pipe=$(mktemp -t multijob.XXXXXX)
rm -f "${pipe}"
mkfifo -m 600 "${pipe}"
__redirect_alloc_fd mj_write_fd "${pipe}"
__redirect_alloc_fd mj_read_fd "${pipe}"
rm -f "${pipe}"
# See how many children we can fork based on the user's settings.
mj_max_jobs=$(makeopts_jobs "$@")
mj_num_jobs=0
}
__multijob_child_init() {
trap 'echo ${BASHPID:-$(__bashpid)} $? >&'${mj_write_fd} EXIT
trap 'exit 1' INT TERM
}
__multijob_finish_one() {
local pid ret
read -r -u ${mj_read_fd} pid ret
: $(( --mj_num_jobs ))
return ${ret}
}
__multijob_finish() {
local ret=0
while [[ ${mj_num_jobs} -gt 0 ]] ; do
__multijob_finish_one
: $(( ret |= $? ))
done
# Let bash clean up its internal child tracking state.
wait
return ${ret}
}
__multijob_post_fork() {
: $(( ++mj_num_jobs ))
if [[ ${mj_num_jobs} -ge ${mj_max_jobs} ]] ; then
__multijob_finish_one
fi
return $?
}
# @FUNCTION: __redirect_alloc_fd
# @USAGE: <var> <file> [redirection]
# @DESCRIPTION:
# Find a free fd and redirect the specified file via it. Store the new
# fd in the specified variable. Useful for the cases where we don't care
# about the exact fd #.
__redirect_alloc_fd() {
local var=$1 file=$2 redir=${3:-"<>"}
if [[ $(( (BASH_VERSINFO[0] << 8) + BASH_VERSINFO[1] )) -ge $(( (4 << 8) + 1 )) ]] ; then
# Newer bash provides this functionality.
eval "exec {${var}}${redir}'${file}'"
else
# Need to provide the functionality ourselves.
local fd=10
local fddir=/dev/fd
# Prefer /proc/self/fd if available (/dev/fd
# doesn't work on solaris, see bug #474536).
[[ -d /proc/self/fd ]] && fddir=/proc/self/fd
while :; do
# Make sure the fd isn't open. It could be a char device,
# or a symlink (possibly broken) to something else.
if [[ ! -e ${fddir}/${fd} ]] && [[ ! -L ${fddir}/${fd} ]] ; then
eval "exec ${fd}${redir}'${file}'" && break
fi
[[ ${fd} -gt 1024 ]] && die 'could not locate a free temp fd !?'
: $(( ++fd ))
done
: $(( ${var} = fd ))
fi
}