// File: /workspace/github_cpp_makefile_star2_O1/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
subq $0x18, %rsp
movq %rdi, %rbx
leaq 0x4dc(%rdi), %rax
movq %rax, (%rsp)
leaq 0x3d0(%rdi), %r15
leaq 0xc(%rsp), %r14
movl 0x4dc(%rbx), %r13d
movl 0x4e0(%rbx), %r12d
movzbl 0x2c(%rbx), %ebp
cmpl $0x3, %ebp
sete %al
testl %r12d, %r12d
sete %cl
orb %al, %cl
jne 0x245cf
movl $0x3, %edi
leaq 0x1151c(%rip), %rsi     # 0x35a98
callq 0x2e63a
cmpl $0x1, %r13d
jne 0x24599
movq 0x8(%rbx), %rdi
callq 0x2e73d
leaq 0x11545(%rip), %rdi     # 0x35adc
jmp 0x245a9
movq 0x8(%rbx), %rdi
callq 0x2e73d
leaq 0x115da(%rip), %rdi     # 0x35b83
callq 0x2e73d
movl $0xc, %esi
movq %r14, %rdi
leaq 0x1221f(%rip), %rdx     # 0x367dc
movl %r12d, %ecx
xorl %eax, %eax
callq 0x89e0
movq %r14, %rdi
callq 0x2e759
testb $0x2, 0x4f4(%rbx)
je 0x245f4
movl 0x3fc(%rbx), %edx
leaq 0x2244b(%rip), %rdi     # 0x46a30
movq %r15, %rsi
callq 0x25df4
andb $-0x3, 0x4f4(%rbx)
cmpb $0x1, 0x5b8(%rbx)
jne 0x24679
movb $0x0, 0x5b8(%rbx)
cmpl $0x3, %ebp
jne 0x246b6
cmpl $0x1, %r13d
jne 0x2470e
jne 0x2470e
cmpl $0x0, 0x4e0(%rbx)
jne 0x2470e
cmpq $0x0, 0x5f8(%rbx)
je 0x2485a
movq %rbx, %rdi
movq (%rsp), %rsi
callq 0x24886
movl $0x1, %r12d
testb $0x10, 0x10c(%rbx)
jne 0x2486c
leal -0x1(%rax), %ecx
cmpl $0x2, %ecx
jb 0x2471c
testl %eax, %eax
jne 0x2485a
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
jmp 0x2485a
cmpl $0x3, %ebp
je 0x24729
cmpl $0x1, %ebp
jne 0x24757
cmpl $0x0, 0x4e0(%rbx)
je 0x247c7
movl $0x3, 0x1c4(%rbx)
movq %rbx, %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x23018
jmp 0x24824
cmpl $0x1, %r13d
jne 0x24848
jne 0x24848
cmpl $0x0, 0x4e0(%rbx)
jne 0x24848
cmpq $0x0, 0x5f8(%rbx)
je 0x24866
movq %rbx, %rdi
movq (%rsp), %rsi
callq 0x24886
movl %eax, %r12d
movb $0x1, %al
cmpl $0x2, %r12d
je 0x24835
cmpl $0x1, %r12d
jne 0x24704
xorl %eax, %eax
xorl %ecx, %ecx
xorl %r12d, %r12d
jmp 0x24837
movl 0x10c(%rbx), %eax
testb $0x10, %al
jne 0x247a8
movq %rbx, %rdi
callq 0x224b2
jmp 0x2485a
cmpl $-0x1, 0x504(%rbx)
jne 0x24824
testb $-0x80, 0x10c(%rbx)
jne 0x24824
andb $-0x3, 0x500(%rbx)
movq %rbx, %rdi
callq 0x224b2
jmp 0x24824
testb $0x1, 0x10c(%rbx)
je 0x2479e
cmpb $0x2, 0x2d(%rbx)
jne 0x2479e
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x28(%rax)
testb %al, %al
je 0x2479e
movb $0x1, 0x5b8(%rbx)
movq %rbx, %rdi
callq 0x263c8
movl $0x1, %r12d
cmpb $0x2, 0x2c(%rbx)
je 0x2486c
movb $0x0, 0x5b8(%rbx)
jmp 0x2486c
movq %rbx, %rdi
callq 0x2710c
jmp 0x24824
testb $0x2, %al
jne 0x2485a
cmpb $0x2, 0x2d(%rbx)
jne 0x2485a
movq %rbx, %rdi
callq 0x22856
jmp 0x2485a
movq %rbx, %rdi
movq (%rsp), %rsi
callq 0x24886
xorl %r12d, %r12d
movb $0x1, %bpl
testl %eax, %eax
je 0x24817
cmpl $0x2, %eax
je 0x24805
cmpl $0x1, %eax
jne 0x2481f
movl $0x3, 0x1c4(%rbx)
xorl %r12d, %r12d
movq %rbx, %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x23018
jmp 0x2481f
movq %rbx, %rdi
callq 0x233ac
movl $0x2, %r12d
xorl %ebp, %ebp
jmp 0x2481f
movq %rbx, %rdi
callq 0x233ac
testb %bpl, %bpl
je 0x2486c
movq 0x148(%rbx), %rdi
callq 0xd8da
xorl %r12d, %r12d
jmp 0x2486c
movb $0x1, %cl
orb %cl, %al
testb %cl, %cl
movl $0x1, %ecx
cmovel %ecx, %r12d
testb %al, %al
jne 0x2486c
movl $0x6, 0x1c4(%rbx)
movq %rbx, %rdi
callq 0x2347a
movq 0x148(%rbx), %rdi
callq 0xd8da
movl $0x1, %r12d
cmpl $0x1, %r12d
ja 0x2454e
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop