백그라운드 프로세스가 셸에서 종료될 때까지 포그라운드 프로세스를 실행합니다.

백그라운드 프로세스가 셸에서 종료될 때까지 포그라운드 프로세스를 실행합니다.

QEMU 가상 머신을 모드로 실행 -daemonize한 다음 QEMU 인스턴스와 상호 작용하도록 설계된 임의의 포그라운드(대화형 가능) 프로세스를 생성합니다. 일반적으로 포그라운드 프로세스가 완료되면 pidfile을 통해 QEMU 인스턴스를 정리합니다.

qemu-system ... -pidfile ./qemu.pid -daemonize

/my/custom/interactive/process

pkill -F ./qemu.pid

그러나 어떤 경우에는 포그라운드 프로세스가 계속 실행되는 동안 QEMU가 독립적으로 종료될 수 있습니다. 하지만 만일을 대비해 차단하고 싶습니다. 따라서 내 사용자 정의 상호 작용 프로세스는 다음과 같이 작동해야 합니다.

tail -f --pid=./qemu.pid /dev/null

어떻게 하면 잘할 수 있나요? 아마도 시간 초과에 대한 일종의 래퍼가 있어서 다음과 같이 실행할 수 있습니다.

trackpid ./qemu.pid /my/custom/interactive/process

답변1

qemu 프로세스를 폴링하여 사라지는지 확인하고, 사라지면 조기에 종료할 수 있습니다. 특히 qemu-system.

그것도 꽤 많이 있습니다. 이 행을 삭제할 수 있지만 #DEBUG, 이 행들이 어떻게 결합되는지 확인하려면 주석 처리를 제거하고 프로그램 출력을 코드와 비교하십시오.

#!/bin/bash

InvokeQemu()
{
    local i pid pidFile=qemu.pid

    # Start the qemu process, and return the PID if possible
    #
    (
        # qemu-system ... -pidFile "$pidFile" -daemonize
        ( sleep 30 & sleep 0.5 && echo $! >"$pidFile" )    # FAKE IT for half a minute
    ) >/dev/null 2>&1 </dev/null

    #echo "InvokeQemu: checking for successful daemonisation" >&2    #DEBUG
    for i in 1 2 3
    do
        # Does the PID file exist yet
        #echo "InvokeQemu: attempt $i" >&2    #DEBUG
        if [[ -s "$pidFile" ]] && pid=$(cat "$pidFile") && [[ -n "$pid" ]]
        then
            printf "%s\n" $pid
            #echo "InvokeQemu: pid=$pid" >&2    #DEBUG
            return 0
        fi

        # Pause a moment or so before trying again
        sleep 2
    done
    return 1
}

MonitorPIDs()
{
    local pid

    for pid in "$@"
    do
        #echo "MonitorPIDs: checking pid $pid" >&2    #DEBUG
        if err=$(kill -0 "$pid" 2>&1) || [[ "$err" == *permitted* || "$err" == *denied* ]]
        then
            # Process still exists
            :
            #echo "MonitorPIDs: pid $pid still alive" >&2    #DEBUG
        else
            #echo "MonitorPIDs: pid $pid has died" >&2    #DEBUG
            echo "$pid"
            return 1
        fi
    done
    #echo "MonitorPIDs: all good" >&2    #DEBUG
    return 0
}

########################################################################
# Go
myPid=$$

# Start the qemu emulator
echo "Starting qemu emulator"
qemuPid=$(InvokeQemu)

if [[ -z "$qemuPid" ]]
then
    echo "Could not start qemu" >&2
    exit 1
fi

# Start the monitor process
#
# Once any of them is no longer running it will fire SIGTERM to its
# remaining PIDs and then exit
echo "Starting monitor process"
(
    while MonitorPIDs $qemuPid $myPid >/dev/null
    do
        #echo "(Monitor): all good" >&2    #DEBUG
        sleep 2
    done
    kill $qemuPid $myPid 2>/dev/null
) &

# Start your interactive foreground process
#
# You will receive SIGTERM within a few seconds of the emulator exiting,
# so you may want to trap that
echo "Starting interactive process"
while read -p "What do you want to do? " x
do
    echo "OK"
    sleep 1
done
exit 0

답변2

마지막으로 다음 코드를 얻었습니다.

qemu-system ... -pidfile ./qemu.pid -daemonize

{
  tail -f --pidfile="$(cat ./qemu.pid)" /dev/null
  kill -INT 0
} &

/my/custom/interactive/process
kill $!

pkill -F ./qemu.pid

중괄호 안의 스크립트는 실제로 백그라운드에서 실행되는 pidfile 모니터입니다. pid가 사라지면 모니터는 현재 프로세스 그룹을 종료합니다. kill -INT 0가장 안정적이고 깨끗한 결과를 제공하기 때문에 사용합니다 .

다른 옵션은 다음과 같습니다:

kill -- 0(TERM 신호를 사용하여 종료하면 대화형 프로세스를 올바르게 종료할 수 없습니다)

kill -INT $$(쉘 프로세스만 종료하며 대화형 프로세스는 올바르게 종료될 수 없습니다)

kill -- -$$sudo(쉘의 pid로 표시되는 프로세스 그룹을 죽이는 것은 프로세스 그룹 리더로 호출하기 때문에 항상 제대로 작동하지 않는 것 같습니다 )

pkill -P $$(하위 프로세스만 종료하는 것이 실제로 작동하지만 내장 셸을 사용하고 Ctrl-C를 사용하여 동작을 처리하는 것을 선호합니다.)

또 다른 요점은 대화형 프로세스가 자체적으로 완료되면 종료 및 정리 스크립트에 대한 추가 추론을 피하기 위해 모니터 프로세스를 종료해야 한다는 것입니다.

관련 정보