// File: davmac314[P]dinit/src/proc-service.cc
// Function: bgproc_service::handle_exit_status()
void bgproc_service::handle_exit_status() noexcept
{
    // For bgproc services, receiving exit status can mean one of two things:
    // 1. We were launching the process, and it finished (possibly after forking). If it did fork
    //    we want to obtain the process id of the process that we should now monitor, the actual
    //    daemon. Or,
    // 2. The above has already happened, and we are monitoring the daemon process, which has now
    //    terminated for some reason.

    begin:
    bool did_exit = exit_status.did_exit();
    bool was_signalled = exit_status.was_signalled();
    auto current_state = get_state();

    if (!exit_status.did_exit_clean() && current_state != service_state_t::STOPPING) {
        if (did_exit) {
            log(loglevel_t::ERROR, "Service ", get_name(), " process terminated with exit code ",
                    exit_status.get_exit_status());
        }
        else if (was_signalled) {
            log(loglevel_t::ERROR, "Service ", get_name(), " terminated due to signal ",
                    exit_status.get_signal());
        }
    }

    if (waiting_stopstart_timer) {
        process_timer.stop_timer(event_loop);
        waiting_stopstart_timer = false;
    }

    if (doing_smooth_recovery) {
        doing_smooth_recovery = false;

        // We're either started, or stopping (i.e. we were requested to stop during smooth recovery).

        if (current_state == service_state_t::STOPPING) {
            // Stop was issued during smooth recovery
            if ((did_exit && exit_status.get_exit_status() != 0) || was_signalled) {
                if (!waiting_for_deps) {
                    stopped();
                }
                else if (get_target_state() == service_state_t::STARTED && !pinned_stopped) {
                    initiate_start();
                }
            }
            else {
                // We need to re-read the PID, since it has now changed.
                if (pid_file.length() != 0) {
                    auto pid_result = read_pid_file(&exit_status);

                    if (waiting_for_deps) {
                        // don't do anything else until dependents have stopped
                        return;
                    }

                    switch (pid_result) {
                    case pid_result_t::FAILED:
                    case pid_result_t::TERMINATED:
                        // Failed startup: no auto-restart.
                        stopped();
                        break;
                    case pid_result_t::OK:
                        // We now need to bring down the daemon process
                        bring_down();
                        break;
                    }
                }
            }
            services->process_queues();
            return;
        }
        else /* if (service_state == service_state_t::STARTED) */ {
            bool need_stop = false;
            if ((did_exit && exit_status.get_exit_status() != 0) || was_signalled) {
                need_stop = true;
            }
            else {
                // We need to re-read the PID, since it has now changed.
                if (pid_file.length() != 0) {
                    auto pid_result = read_pid_file(&exit_status);

                    switch (pid_result) {
                    case pid_result_t::FAILED:
                        // Failed startup: no auto-restart.
                        need_stop = true;
                        break;
                    case pid_result_t::TERMINATED:
                        goto begin;
                    case pid_result_t::OK:
                        break;
                    }
                }
            }

            if (need_stop) {
                // Failed startup: no auto-restart.
                stop_reason = stopped_reason_t::TERMINATED;
                unrecoverable_stop();
                services->process_queues();
            }

            return;
        }
    }

    if (current_state == service_state_t::STARTING) {
        if (exit_status.did_exit_clean()) {
            auto pid_result = read_pid_file(&exit_status);
            switch (pid_result) {
                case pid_result_t::FAILED:
                    // Failed startup: no auto-restart.
                    stop_reason = stopped_reason_t::FAILED;
                    failed_to_start();
                    break;
                case pid_result_t::TERMINATED:
                    // started, but immediately terminated
                    started();
                    goto begin;
                case pid_result_t::OK:
                    started();
                    break;
            }
        }
        else {
            stop_reason = stopped_reason_t::FAILED;
            failed_to_start();
        }
    }
    else if (current_state == service_state_t::STOPPING) {
        // We won't log a non-zero exit status or termination due to signal here -
        // we assume that the process died because we signalled it.
        if (stop_pid == -1 && !waiting_for_execstat) {
            stop_issued = false;
            stopped();
        }
    }
    else {
        // we must be STARTED
        if (smooth_recovery && get_target_state() == service_state_t::STARTED && check_restart()) {
            doing_smooth_recovery = true;
            do_smooth_recovery();
            if (get_state() != service_state_t::STARTED) {
                doing_smooth_recovery = false;
            }
            return;
        }
        handle_unexpected_termination();
    }
    services->process_queues();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4ed70
movq -0x30(%rbp), %rdi
andb $0x1, %al
movb %al, -0x9(%rbp)
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e4b0
movq -0x30(%rbp), %rdi
andb $0x1, %al
movb %al, -0xa(%rbp)
callq 0x2f0d0
movq -0x30(%rbp), %rdi
movb %al, -0xb(%rbp)
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e260
testb $0x1, %al
jne 0x5066e
cmpb $0x3, -0xb(%rbp)
je 0x5066e
testb $0x1, -0x9(%rbp)
je 0x50624
movq -0x30(%rbp), %rdi
callq 0x2d420
movq -0x30(%rbp), %rdi
movq %rax, -0x38(%rbp)
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e590
movq -0x38(%rbp), %rdx
movl %eax, -0x10(%rbp)
movl $0x3, %edi
leaq 0x283fd(%rip), %rsi     # 0x78a0f
leaq 0x2843a(%rip), %rcx     # 0x78a53
leaq -0x10(%rbp), %r8
callq 0x50350
jmp 0x5066c
testb $0x1, -0xa(%rbp)
je 0x5066a
movq -0x30(%rbp), %rdi
callq 0x2d420
movq -0x30(%rbp), %rdi
movq %rax, -0x40(%rbp)
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e500
movq -0x40(%rbp), %rdx
movl %eax, -0x14(%rbp)
movl $0x3, %edi
leaq 0x283b5(%rip), %rsi     # 0x78a0f
leaq 0x28499(%rip), %rcx     # 0x78afa
leaq -0x14(%rbp), %r8
callq 0x50390
jmp 0x5066c
jmp 0x5066e
movq -0x30(%rbp), %rax
movb 0x4f4(%rax), %al
shrb %al
andb $0x1, %al
testb $0x1, %al
je 0x506ad
movq -0x30(%rbp), %rdi
addq $0x3b0, %rdi            # imm = 0x3B0
leaq 0x584ce(%rip), %rsi     # 0xa8b60
callq 0x529f0
movq -0x30(%rbp), %rax
movb 0x4f4(%rax), %cl
andb $-0x3, %cl
orb $0x0, %cl
movb %cl, 0x4f4(%rax)
movq -0x30(%rbp), %rax
testb $0x1, 0x5b8(%rax)
je 0x5088c
movq -0x30(%rbp), %rax
movb $0x0, 0x5b8(%rax)
cmpb $0x3, -0xb(%rbp)
jne 0x507d6
testb $0x1, -0x9(%rbp)
je 0x506ee
movq -0x30(%rbp), %rdi
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e590
cmpl $0x0, %eax
jne 0x506f4
testb $0x1, -0xa(%rbp)
je 0x50746
movq -0x30(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x4, %eax
andl $0x1, %eax
testl $0x1, %eax
jne 0x50716
movq -0x30(%rbp), %rdi
callq 0x4bb20
jmp 0x50744
movq -0x30(%rbp), %rdi
callq 0x52d20
cmpb $0x2, %al
jne 0x50742
movq -0x30(%rbp), %rax
movl 0x10c(%rax), %eax
shrl %eax
andl $0x1, %eax
testl $0x1, %eax
jne 0x50742
movq -0x30(%rbp), %rdi
callq 0x4c1e0
jmp 0x50744
jmp 0x507c1
movq -0x30(%rbp), %rdi
addq $0x5f0, %rdi            # imm = 0x5F0
callq 0xab20
cmpq $0x0, %rax
je 0x507bf
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x4dc, %rsi            # imm = 0x4DC
callq 0x50a00
movl %eax, %ecx
movq -0x30(%rbp), %rax
movl %ecx, -0x18(%rbp)
movl 0x10c(%rax), %eax
shrl $0x4, %eax
andl $0x1, %eax
testl $0x1, %eax
je 0x50790
jmp 0x509f1
movl -0x18(%rbp), %eax
movl %eax, -0x44(%rbp)
testl %eax, %eax
je 0x507b3
jmp 0x5079c
movl -0x44(%rbp), %eax
decl %eax
subl $0x1, %eax
ja 0x507bd
jmp 0x507a8
movq -0x30(%rbp), %rdi
callq 0x4bb20
jmp 0x507bd
movq -0x30(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0x507bf
jmp 0x507c1
movq -0x30(%rbp), %rax
movq 0x148(%rax), %rdi
callq 0x173c0
jmp 0x509f1
movb $0x0, -0x19(%rbp)
testb $0x1, -0x9(%rbp)
je 0x507f5
movq -0x30(%rbp), %rdi
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e590
cmpl $0x0, %eax
jne 0x507fb
testb $0x1, -0xa(%rbp)
je 0x50801
movb $0x1, -0x19(%rbp)
jmp 0x5085e
movq -0x30(%rbp), %rdi
addq $0x5f0, %rdi            # imm = 0x5F0
callq 0xab20
cmpq $0x0, %rax
je 0x5085c
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x4dc, %rsi            # imm = 0x4DC
callq 0x50a00
movl %eax, -0x20(%rbp)
movl -0x20(%rbp), %eax
movl %eax, -0x48(%rbp)
testl %eax, %eax
je 0x50858
jmp 0x50839
movl -0x48(%rbp), %eax
subl $0x1, %eax
je 0x5084d
jmp 0x50843
movl -0x48(%rbp), %eax
subl $0x2, %eax
je 0x50853
jmp 0x5085a
movb $0x1, -0x19(%rbp)
jmp 0x5085a
jmp 0x50584
jmp 0x5085a
jmp 0x5085c
jmp 0x5085e
testb $0x1, -0x19(%rbp)
je 0x50887
movq -0x30(%rbp), %rdi
movl $0x6, 0x1c4(%rdi)
callq 0x4d730
movq -0x30(%rbp), %rax
movq 0x148(%rax), %rdi
callq 0x173c0
jmp 0x509f1
cmpb $0x1, -0xb(%rbp)
jne 0x50936
movq -0x30(%rbp), %rdi
addq $0x4dc, %rdi            # imm = 0x4DC
callq 0x4e260
testb $0x1, %al
jne 0x508ac
jmp 0x50917
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x4dc, %rsi            # imm = 0x4DC
callq 0x50a00
movl %eax, -0x24(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0x4c(%rbp)
testl %eax, %eax
je 0x5090c
jmp 0x508ce
movl -0x4c(%rbp), %eax
subl $0x1, %eax
je 0x508e2
jmp 0x508d8
movl -0x4c(%rbp), %eax
subl $0x2, %eax
je 0x508fe
jmp 0x50915
movq -0x30(%rbp), %rdi
movl $0x3, 0x1c4(%rdi)
xorl %esi, %esi
movl $0x1, %edx
callq 0x4cf90
jmp 0x50915
movq -0x30(%rbp), %rdi
callq 0x4d570
jmp 0x50584
movq -0x30(%rbp), %rdi
callq 0x4d570
jmp 0x50931
movq -0x30(%rbp), %rdi
movl $0x3, 0x1c4(%rdi)
xorl %esi, %esi
movl $0x1, %edx
callq 0x4cf90
jmp 0x509e1
cmpb $0x3, -0xb(%rbp)
jne 0x5097b
movq -0x30(%rbp), %rax
cmpl $-0x1, 0x504(%rax)
jne 0x50979
movq -0x30(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x7, %eax
andl $0x1, %eax
testl $0x1, %eax
jne 0x50979
movq -0x30(%rbp), %rdi
movb 0x500(%rdi), %al
andb $-0x3, %al
orb $0x0, %al
movb %al, 0x500(%rdi)
callq 0x4bb20
jmp 0x509df
movq -0x30(%rbp), %rax
movl 0x10c(%rax), %eax
andl $0x1, %eax
testl $0x1, %eax
je 0x509d6
movq -0x30(%rbp), %rdi
callq 0x52d20
cmpb $0x2, %al
jne 0x509d6
movq -0x30(%rbp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
testb $0x1, %al
jne 0x509ac
jmp 0x509d6
movq -0x30(%rbp), %rdi
movb $0x1, 0x5b8(%rdi)
callq 0x54cf0
movq -0x30(%rbp), %rdi
callq 0x2f0d0
cmpb $0x2, %al
je 0x509d4
movq -0x30(%rbp), %rax
movb $0x0, 0x5b8(%rax)
jmp 0x509f1
movq -0x30(%rbp), %rdi
callq 0x56080
jmp 0x509e1
movq -0x30(%rbp), %rax
movq 0x148(%rax), %rdi
callq 0x173c0
addq $0x50, %rsp
popq %rbp
retq
nopw (%rax,%rax)