// File: /workspace/github_cpp_makefile_star2_O3/davmac314[P]dinit/src/control.cc
// Function: control_conn_t::process_start_stop(cp_cmd)
bool control_conn_t::process_start_stop(cp_cmd pktType)
{
    using std::string;
    
    constexpr int pkt_size = 2 + sizeof(handle_t);
    
    if (rbuf.get_length() < pkt_size) {
        chklen = pkt_size;
        return true;
    }
    
    // 1 byte: packet type
    // 1 byte: flags
    //    bit 0: 0 = no pin, 1 = pin
    //    bit 1: 0 = force stop, 1 = not forced ("gentle")
    //    bit 2: 0 = don't restart, 1 = restart after stopping
    //      --- (reserved)
    //    bit 7: 0 = no pre-ack, 1 = issue pre-ack
    // 4 bytes: service handle
    
    bool do_pin = ((rbuf[1] & 1) == 1);
    handle_t handle;
    rbuf.extract((char *) &handle, 2, sizeof(handle));
    
    service_record *service = find_service_for_key(handle);
    if (service == nullptr) {
        // Service handle is bad
        char badreqRep[] = { (char)cp_rply::BADREQ };
        if (!queue_packet(badreqRep, 1)) return false;
        bad_conn_close = true;
        return true;
    }
    else {
        char ack_buf[1] = { (char)cp_rply::PREACK };
        if (rbuf[1] & 128) {
            // Issue PREACK before doing anything that might change service state (and cause a
            // service event info packet to be issued as a result). This allows the client to
            // determine whether the info packets were queued before or after the command was
            // processed.
            if (!queue_packet(ack_buf, 1)) return false;
        }

        ack_buf[0] = (char)cp_rply::ACK;
        
        switch (pktType) {
        case cp_cmd::STARTSERVICE:
            // start service, mark as required
            if (services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STOPPED
                    || service->get_state() == service_state_t::STOPPING)
                    && service->is_stop_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTOPPED;
                break;
            }
            if (do_pin) service->pin_start();
            service->start();
            services->process_queues();
            if (service->get_state() == service_state_t::STARTED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        case cp_cmd::STOPSERVICE:
        {
            // force service to stop
            bool do_restart = ((rbuf[1] & 4) == 4);
            bool gentle = ((rbuf[1] & 2) == 2);
            if (do_restart && services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STARTED
                    || service->get_state() == service_state_t::STARTING)
                    && service->is_start_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTARTED;
                break;
            }
            if (gentle) {
                // Check dependents; return appropriate response if any will be affected
                bool has_dependents;
                if (!check_dependents(service, has_dependents)) {
                    return false;
                }
                if (has_dependents) {
                    // Reply packet has already been sent
                    goto clear_out;
                }
            }
            service_state_t wanted_state;
            if (do_restart) {
                if (! service->restart()) {
                    ack_buf[0] = (char)cp_rply::NAK;
                    break;
                }
                wanted_state = service_state_t::STARTED;
            }
            else {
                if (do_pin) service->pin_stop();
                service->stop(true);
                service->forced_stop();
                wanted_state = service_state_t::STOPPED;
            }
            services->process_queues();
            if (service->get_state() == wanted_state) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        }
        case cp_cmd::WAKESERVICE:
        {
            // re-attach a service to its (started) dependents, causing it to start.
            if (services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STOPPED
                    || service->get_state() == service_state_t::STOPPING)
                    && service->is_stop_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTOPPED;
                break;
            }
            bool found_dpt = false;
            for (auto dpt : service->get_dependents()) {
                if (dpt->is_only_ordering()) continue;
                auto from = dpt->get_from();
                auto from_state = from->get_state();
                if (from_state == service_state_t::STARTED || from_state == service_state_t::STARTING) {
                    found_dpt = true;
                    if (!dpt->holding_acq) {
                        dpt->get_from()->start_dep(*dpt);
                    }
                }
            }
            if (!found_dpt) {
                ack_buf[0] = (char)cp_rply::NAK;
            }

            if (do_pin) service->pin_start();
            services->process_queues();
            if (service->get_state() == service_state_t::STARTED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        }
        case cp_cmd::RELEASESERVICE:
            // remove required mark, stop if not required by dependents
            if (do_pin) service->pin_stop();
            service->stop(false);
            services->process_queues();
            if (service->get_state() == service_state_t::STOPPED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        default:
            // avoid warning for unhandled switch/case values
            return false;
        }
        
        if (!queue_packet(ack_buf, 1)) return false;
    }
    
    clear_out:
    // Clear the packet from the buffer
    rbuf.consume(pkt_size);
    chklen = 0;
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
cmpl $0x5, 0x484(%rdi)
ja 0x28695
movl $0x6, 0x7c(%rbx)
movb $0x1, %al
jmp 0x289fa
movl %esi, %ebp
leaq 0x80(%rbx), %r14
movl 0x480(%rbx), %r15d
leal 0x1(%r15), %eax
leal -0x3ff(%r15), %ecx
movl $0x400, %r12d           # imm = 0x400
cmpl %r12d, %eax
cmovbl %eax, %ecx
leal 0x2(%r15), %eax
addl $0xfffffc02, %r15d      # imm = 0xFFFFFC02
cmpl %r12d, %eax
cmovbl %eax, %r15d
movb 0x80(%rbx,%rcx), %al
movb %al, 0x1(%rsp)
leal -0x3fd(%r15), %eax
movl %r15d, %esi
cmpl $0xfffffbfe, %eax       # imm = 0xFFFFFBFE
ja 0x2871c
subl %r15d, %r12d
addq %r14, %rsi
leaq 0x4(%rsp), %r13
movq %r13, %rdi
movq %r12, %rdx
callq 0x84d0
leaq (%rsp,%r12), %rdi
addq $0x4, %rdi
addl $0xfffffc04, %r15d      # imm = 0xFFFFFC04
movq %r14, %rsi
movq %r15, %rdx
callq 0x84d0
jmp 0x28722
addq %rsi, %r14
movq %r14, %r13
movl (%r13), %esi
movq %rbx, %rdi
callq 0x2b906
testq %rax, %rax
je 0x287e1
movq %rax, %r14
movb $0x4f, (%rsp)
movl 0x480(%rbx), %eax
leal 0x1(%rax), %ecx
addl $0xfffffc01, %eax       # imm = 0xFFFFFC01
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
cmpb $0x0, 0x80(%rbx,%rax)
jns 0x28777
movq %rsp, %rsi
movq %rbx, %rdi
movl $0x1, %edx
callq 0x28036
testb %al, %al
je 0x289f8
movb $0x32, (%rsp)
movzbl %bpl, %eax
addl $-0x3, %eax
cmpl $0x3, %eax
ja 0x289f8
leaq 0xdc96(%rip), %rcx      # 0x36428
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x28935
movzbl 0x2c(%r14), %eax
cmpl $0x3, %eax
je 0x287b7
testl %eax, %eax
jne 0x287c5
testb $0x2, 0x10c(%r14)
jne 0x2896f
testb $0x1, 0x1(%rsp)
je 0x287d4
movq %r14, %rdi
callq 0x23a6a
movq %r14, %rdi
callq 0x22b92
jmp 0x288a1
leaq 0x3(%rsp), %rsi
movb $0x34, (%rsi)
movq %rbx, %rdi
movl $0x1, %edx
callq 0x28036
testb %al, %al
je 0x289fa
movb $0x1, 0x78(%rbx)
jmp 0x289fa
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x28935
movzbl 0x2c(%r14), %eax
cmpl $0x3, %eax
je 0x28823
testl %eax, %eax
jne 0x28831
testb $0x2, 0x10c(%r14)
jne 0x2896f
movq %r14, %r15
addq $0x130, %r15            # imm = 0x130
movq 0x130(%r14), %r12
cmpq %r15, %r12
je 0x2888e
xorl %ebp, %ebp
movq 0x10(%r12), %r13
movl 0x14(%r13), %eax
andl $-0x2, %eax
cmpl $0x4, %eax
je 0x2887f
movq (%r13), %rax
movb 0x2c(%rax), %al
decb %al
cmpb $0x1, %al
ja 0x2887f
movb $0x1, %bpl
cmpb $0x0, 0x11(%r13)
jne 0x2887f
movq 0x8(%r13), %rdi
callq 0x22c46
movb $0x1, 0x11(%r13)
movq (%r12), %r12
cmpq %r15, %r12
jne 0x28849
testb $0x1, %bpl
jne 0x28892
movb $0x33, (%rsp)
testb $0x1, 0x1(%rsp)
je 0x288a1
movq %r14, %rdi
callq 0x23a6a
movq 0x70(%rbx), %rdi
callq 0xd37e
cmpb $0x2, 0x2c(%r14)
je 0x289b0
jmp 0x289b4
testb $0x1, 0x1(%rsp)
je 0x288c9
orb $0x2, 0x10c(%r14)
movq %r14, %rdi
xorl %esi, %esi
callq 0x237c8
movq 0x70(%rbx), %rdi
callq 0xd37e
cmpb $0x0, 0x2c(%r14)
jne 0x289b4
jmp 0x289b0
movl 0x480(%rbx), %eax
leal 0x1(%rax), %ecx
addl $0xfffffc01, %eax       # imm = 0xFFFFFC01
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
movb 0x80(%rbx,%rax), %bpl
testb $0x4, %bpl
je 0x2891b
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x28935
movb 0x2c(%r14), %al
decb %al
cmpb $0x1, %al
ja 0x2893b
testb $0xc, 0x10c(%r14)
je 0x2893b
movb $0x44, (%rsp)
jmp 0x289b4
movb $0x45, (%rsp)
jmp 0x289b4
testb $0x2, %bpl
jne 0x28975
testb $0x4, %bpl
jne 0x28992
testb $0x1, 0x1(%rsp)
je 0x28956
orb $0x2, 0x10c(%r14)
movq %r14, %rdi
movl $0x1, %esi
callq 0x237c8
movq %r14, %rdi
callq 0x2376c
xorl %ebp, %ebp
jmp 0x289a1
movb $0x43, (%rsp)
jmp 0x289b4
leaq 0x2(%rsp), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2aeac
testb %al, %al
je 0x289f8
cmpb $0x0, 0x2(%rsp)
je 0x28941
jmp 0x289c8
movq %r14, %rdi
callq 0x23878
movb $0x2, %bpl
testb %al, %al
je 0x28a09
movq 0x70(%rbx), %rdi
callq 0xd37e
cmpb %bpl, 0x2c(%r14)
jne 0x289b4
movb $0x3d, (%rsp)
movq %rsp, %rsi
movq %rbx, %rdi
movl $0x1, %edx
callq 0x28036
testb %al, %al
je 0x289f8
movl 0x480(%rbx), %eax
leal 0x6(%rax), %ecx
addl $0xfffffc06, %eax       # imm = 0xFFFFFC06
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
movl %eax, 0x480(%rbx)
addl $-0x6, 0x484(%rbx)
movl $0x0, 0x7c(%rbx)
jmp 0x2868e
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movb $0x33, (%rsp)
jmp 0x289b4
nop