// File: davmac314[P]dinit/src/service.cc
// Function: service_record::do_stop(bool)
void service_record::do_stop(bool with_restart) noexcept
{
    // Called when we should definitely stop. We may need to restart afterwards, but we
    // won't know that for sure until the execution transition.
    // Note: to inhibit automatic restart, including restart due to dependent still requiring this
    //       service, caller must first set desired_state to STOPPED

    if (is_start_pinned()) return;

    in_auto_restart = false;
    in_user_restart = false;

    // Will we restart? desired state of STOPPED inhibits auto-restart
    bool do_auto_restart = false;
    if (auto_restart == auto_restart_mode::ALWAYS) {
        do_auto_restart = true;
    }
    else if (auto_restart == auto_restart_mode::ON_FAILURE) {
        if (get_type() == service_type_t::PROCESS || get_type() == service_type_t::BGPROCESS) {
            auto exit_status = get_exit_status();
            if (exit_status.was_signalled()) {
                if (!value(exit_status.get_signal()).is_in(SIGHUP, SIGINT, SIGUSR1, SIGUSR2, SIGTERM)) {
                    do_auto_restart = true;
                }
            }
            else {
                if (exit_status.get_exit_status() != 0) {
                    do_auto_restart = true;
                }
            }
        }
    }
    bool for_restart = with_restart || (do_auto_restart && desired_state == service_state_t::STARTED);
    bool restart_deps = with_restart;

    if (!with_restart && for_restart) {
        // auto restart - check for restarting too often
        for_restart = check_restart();
        in_auto_restart = for_restart;
    }

    // If we won't restart, release explicit activation:
    if (!for_restart) {
        if (start_explicit) {
            start_explicit = false;
            release(false);
        }
    }

    bool all_deps_stopped = stop_dependents(for_restart, restart_deps);

    if (service_state != service_state_t::STARTED) {
        if (service_state == service_state_t::STARTING) {
            // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
            // we need to delegate to can_interrupt_start() (which can be overridden).
            if (!waiting_for_deps && !waiting_for_console) {
                if (!can_interrupt_start()) {
                    // Well this is awkward: we're going to have to continue starting. We can stop once
                    // we've reached the started state.
                    return;
                }

                if (!interrupt_start()) {
                    // Now wait for service startup to actually end; we don't need to handle it here.
                    notify_listeners(service_event_t::STARTCANCELLED);
                    return;
                }
            }
            else if (waiting_for_console) {
                services->unqueue_console(this);
                waiting_for_console = false;
            }

            // We must have had desired_state == STARTED.
            notify_listeners(service_event_t::STARTCANCELLED);

            // Reaching this point, we are starting interruptibly - so we
            // stop now (by falling through to below).
        }
        else {
            // If we're starting we need to wait for that to complete.
            // If we're already stopping/stopped there's nothing to do.
            return;
        }
    }

    service_state = service_state_t::STOPPING;
    waiting_for_deps = !all_deps_stopped;
    if (all_deps_stopped) {
        services->add_transition_queue(this);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movb %sil, %al
movq %rdi, -0x8(%rbp)
andb $0x1, %al
movb %al, -0x9(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x48(%rbp)
callq 0x4e360
testb $0x1, %al
jne 0x4c467
jmp 0x4c46c
jmp 0x4c78b
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %ecx
andl $0xfffdffff, %ecx       # imm = 0xFFFDFFFF
orl $0x0, %ecx
movl %ecx, 0x10c(%rax)
movl 0x10c(%rax), %ecx
andl $0xfffbffff, %ecx       # imm = 0xFFFBFFFF
orl $0x0, %ecx
movl %ecx, 0x10c(%rax)
movb $0x0, -0xa(%rbp)
cmpl $0x1, 0x108(%rax)
jne 0x4c4b0
movb $0x1, -0xa(%rbp)
jmp 0x4c59e
movq -0x48(%rbp), %rax
cmpl $0x2, 0x108(%rax)
jne 0x4c59c
movq -0x48(%rbp), %rdi
callq 0x2d5a0
cmpl $0x1, %eax
je 0x4c4e1
movq -0x48(%rbp), %rdi
callq 0x2d5a0
cmpl $0x2, %eax
jne 0x4c59a
movq -0x48(%rbp), %rdi
movq (%rdi), %rax
movq 0x50(%rax), %rax
callq *%rax
movq %rax, -0x50(%rbp)
jmp 0x4c4f4
movq -0x50(%rbp), %rax
movq %rax, -0x14(%rbp)
leaq -0x14(%rbp), %rdi
callq 0x4e4b0
testb $0x1, %al
jne 0x4c50b
jmp 0x4c584
leaq -0x14(%rbp), %rdi
callq 0x4e500
movl %eax, -0x24(%rbp)
leaq -0x24(%rbp), %rdi
callq 0x4e4d0
movq %rax, -0x58(%rbp)
jmp 0x4c526
movq -0x58(%rbp), %rax
movq %rax, -0x20(%rbp)
movl $0x1, -0x28(%rbp)
movl $0x2, -0x2c(%rbp)
movl $0xa, -0x30(%rbp)
movl $0xc, -0x34(%rbp)
movl $0xf, -0x38(%rbp)
leaq -0x20(%rbp), %rdi
leaq -0x28(%rbp), %rsi
leaq -0x2c(%rbp), %rdx
leaq -0x30(%rbp), %rcx
leaq -0x34(%rbp), %r8
leaq -0x38(%rbp), %r9
callq 0x4e520
movb %al, -0x59(%rbp)
jmp 0x4c573
movb -0x59(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x4c57e
jmp 0x4c582
movb $0x1, -0xa(%rbp)
jmp 0x4c598
leaq -0x14(%rbp), %rdi
callq 0x4e590
cmpl $0x0, %eax
je 0x4c596
movb $0x1, -0xa(%rbp)
jmp 0x4c598
jmp 0x4c59a
jmp 0x4c59c
jmp 0x4c59e
movb $0x1, %al
testb $0x1, -0x9(%rbp)
movb %al, -0x5a(%rbp)
jne 0x4c5c8
xorl %eax, %eax
testb $0x1, -0xa(%rbp)
movb %al, -0x5b(%rbp)
je 0x4c5c2
movq -0x48(%rbp), %rax
cmpb $0x2, 0x2d(%rax)
sete %al
movb %al, -0x5b(%rbp)
movb -0x5b(%rbp), %al
movb %al, -0x5a(%rbp)
movb -0x5a(%rbp), %al
andb $0x1, %al
movb %al, -0x39(%rbp)
movb -0x9(%rbp), %al
andb $0x1, %al
movb %al, -0x3a(%rbp)
testb $0x1, -0x9(%rbp)
jne 0x4c61a
testb $0x1, -0x39(%rbp)
je 0x4c61a
movq -0x48(%rbp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
movb %al, %cl
movq -0x48(%rbp), %rax
andb $0x1, %cl
movb %cl, -0x39(%rbp)
movb -0x39(%rbp), %cl
andb $0x1, %cl
movzbl %cl, %edx
movl 0x10c(%rax), %ecx
shll $0x11, %edx
andl $0xfffdffff, %ecx       # imm = 0xFFFDFFFF
orl %edx, %ecx
movl %ecx, 0x10c(%rax)
testb $0x1, -0x39(%rbp)
jne 0x4c658
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x8, %eax
andl $0x1, %eax
testl $0x1, %eax
je 0x4c656
movq -0x48(%rbp), %rdi
movl 0x10c(%rdi), %eax
andl $0xfffffeff, %eax       # imm = 0xFFFFFEFF
orl $0x0, %eax
movl %eax, 0x10c(%rdi)
xorl %esi, %esi
callq 0x4c070
jmp 0x4c658
movq -0x48(%rbp), %rdi
movb -0x39(%rbp), %cl
movb -0x3a(%rbp), %al
andb $0x1, %cl
andb $0x1, %al
movzbl %cl, %esi
movzbl %al, %edx
callq 0x4d940
movb %al, %cl
movq -0x48(%rbp), %rax
andb $0x1, %cl
movb %cl, -0x3b(%rbp)
cmpb $0x2, 0x2c(%rax)
je 0x4c74d
movq -0x48(%rbp), %rax
cmpb $0x1, 0x2c(%rax)
jne 0x4c749
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x4, %eax
andl $0x1, %eax
testl $0x1, %eax
jne 0x4c6fa
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x5, %eax
andl $0x1, %eax
testl $0x1, %eax
jne 0x4c6fa
movq -0x48(%rbp), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
testb $0x1, %al
jne 0x4c6d7
jmp 0x4c78b
movq -0x48(%rbp), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
testb $0x1, %al
jne 0x4c6f8
movq -0x48(%rbp), %rdi
movl $0x3, %esi
callq 0x4e2a0
jmp 0x4c78b
jmp 0x4c739
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %eax
shrl $0x5, %eax
andl $0x1, %eax
testl $0x1, %eax
je 0x4c737
movq -0x48(%rbp), %rsi
movq 0x148(%rsi), %rdi
callq 0x4e460
movq -0x48(%rbp), %rax
movl 0x10c(%rax), %ecx
andl $-0x21, %ecx
orl $0x0, %ecx
movl %ecx, 0x10c(%rax)
jmp 0x4c739
movq -0x48(%rbp), %rdi
movl $0x3, %esi
callq 0x4e2a0
jmp 0x4c74b
jmp 0x4c78b
jmp 0x4c74d
movq -0x48(%rbp), %rax
movb $0x3, 0x2c(%rax)
movb -0x3b(%rbp), %cl
xorb $-0x1, %cl
andb $0x1, %cl
movzbl %cl, %edx
movl 0x10c(%rax), %ecx
shll $0x4, %edx
andl $-0x11, %ecx
orl %edx, %ecx
movl %ecx, 0x10c(%rax)
testb $0x1, -0x3b(%rbp)
je 0x4c78b
movq -0x48(%rbp), %rsi
movq 0x148(%rsi), %rdi
callq 0x4e3b0
addq $0x60, %rsp
popq %rbp
retq
movq %rax, %rdi
callq 0xfa30
nopl (%rax)