// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
leaq 0x4dc(%rdi), %r14
leaq 0x8(%rdi), %r15
leaq 0x3b0(%rdi), %r12
movl 0x4dc(%rbx), %r13d
movl 0x4e0(%rbx), %eax
movzbl 0x2c(%rbx), %ebp
cmpl $0x3, %ebp
sete %cl
testl %eax, %eax
sete %dl
orb %cl, %dl
jne 0x201fb
cmpl $0x1, %r13d
je 0x201ea
movl %eax, (%rsp)
movq %r15, %rdi
movq %rsp, %rsi
callq 0x20042
jmp 0x201fb
movl %eax, 0x4(%rsp)
movq %r15, %rdi
leaq 0x4(%rsp), %rsi
callq 0x20006
testb $0x2, 0x4f4(%rbx)
je 0x2021a
movq %r12, %rdi
leaq 0x25822(%rip), %rsi     # 0x45a30
callq 0x20f92
andb $-0x3, 0x4f4(%rbx)
cmpb $0x1, 0x5b8(%rbx)
jne 0x20270
xorl $0x1, %r13d
orl 0x4e0(%rbx), %r13d
setne %al
movb $0x0, 0x5b8(%rbx)
cmpl $0x3, %ebp
je 0x20313
testb %al, %al
jne 0x202fc
cmpq $0x0, 0x5f8(%rbx)
je 0x203d7
movq %rbx, %rdi
movq %r14, %rsi
callq 0x203f6
cmpl $0x2, %eax
je 0x201b4
jmp 0x202f3
cmpl $0x1, %ebp
jne 0x202c8
cmpl $0x0, 0x4e0(%rbx)
jne 0x202ac
movq %rbx, %rdi
movq %r14, %rsi
callq 0x203f6
cmpl $0x2, %eax
jne 0x2029b
movq %rbx, %rdi
callq 0x1f01a
jmp 0x201b4
testl %eax, %eax
je 0x2037b
cmpl $0x1, %eax
jne 0x203bd
movl $0x3, 0x1c4(%rbx)
pushq $0x1
popq %rdx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x1ed2e
jmp 0x203bd
cmpl $0x3, %ebp
jne 0x20341
cmpl $-0x1, 0x504(%rbx)
jne 0x203bd
testb $-0x80, 0x10c(%rbx)
jne 0x203bd
andb $-0x3, 0x500(%rbx)
jmp 0x203b5
cmpl $0x1, %eax
jne 0x203d7
movl $0x6, 0x1c4(%rbx)
movq %rbx, %rdi
callq 0x1f0c8
jmp 0x203bd
testb %al, %al
je 0x2038f
movl 0x10c(%rbx), %eax
testb $0x10, %al
je 0x203b5
testb $0x2, %al
jne 0x203bd
cmpb $0x2, 0x2d(%rbx)
jne 0x203bd
movq %rbx, %rdi
callq 0x1e684
jmp 0x203bd
testb $0x1, 0x10c(%rbx)
je 0x20385
cmpb $0x2, 0x2d(%rbx)
jne 0x20385
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x28(%rax)
testb %al, %al
je 0x20385
movb $0x1, 0x5b8(%rbx)
movq %rbx, %rdi
callq 0x21c8c
cmpb $0x2, 0x2c(%rbx)
je 0x203d7
movb $0x0, 0x5b8(%rbx)
jmp 0x203d7
movq %rbx, %rdi
callq 0x1f01a
jmp 0x203bd
movq %rbx, %rdi
callq 0x227e6
jmp 0x203bd
cmpq $0x0, 0x5f8(%rbx)
je 0x203bd
movq %rbx, %rdi
movq %r14, %rsi
callq 0x203f6
testb $0x10, 0x10c(%rbx)
jne 0x203d7
leal -0x1(%rax), %ecx
cmpl $0x2, %ecx
jae 0x203e6
movq %rbx, %rdi
callq 0x1e30a
movq 0x148(%rbx), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xcdd2
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testl %eax, %eax
jne 0x203bd
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
jmp 0x203bd
nop