| #!/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 |
| } |