// File: /workspace/github_cpp_makefile_star2_O2/cybozu[P]yrmcds/cybozu/tcp.cpp
// Function: cybozu::tcp_socket::_send(int, char const*, unsigned long, std::unique_lock<std::mutex>&)
bool tcp_socket::_send(int fd, const char* p, std::size_t len, lock_guard& g) {
    while( ! can_send(len) ) {
        on_buffer_full();
        m_cond_write.wait(g);
    }
    if( m_shutdown ) return false;

    if( m_pending.empty() ) {
        while( len > 0 ) {
            ssize_t n = ::send(fd, p, len, 0);
            if( n == -1 ) {
                if( errno == EAGAIN || errno == EWOULDBLOCK ) break;
                if( errno == EINTR ) continue;
                auto ecnd = std::system_category().default_error_condition(errno);
                if( ecnd.value() != EPIPE )
                    logger::error() << "<tcp_socket::_send>: ("
                                    << ecnd.value() << ") "
                                    << ecnd.message();
                return false;
            }
            p += n;
            len -= n;
        }
        if( len == 0 ) return true;
    }

    // put data in the pending request queue.
    if( capacity() < len ) {
        // here, m_pending.empty() and m_tmpbuf.empty() holds true.
        logger::debug() << "<tcp_socket::_send> buffering "
                        << len << " bytes data.";
        m_tmpbuf.resize(len);
        std::memcpy(m_tmpbuf.data(), p, len);
        return true;
    }

    if( ! m_pending.empty() ) {
        auto& t = m_pending.back();
        char* t_p;
        std::size_t t_len;
        std::tie(t_p, t_len, std::ignore) = t;
        std::size_t room = SENDBUF_SIZE - t_len;
        if( room > 0 ) {
            std::size_t to_write = std::min(room, len);
            std::memcpy(t_p + t_len, p, to_write);
            p += to_write;
            len -= to_write;
            std::get<1>(t) = t_len + to_write;
            if( len == 0 ) return true;
        }
    }

    while( len > 0 ) {
        char* t_p = m_free_buffers.back();
        m_free_buffers.pop_back();
        std::size_t to_write = std::min(len, SENDBUF_SIZE);
        std::memcpy(t_p, p, to_write);
        p += to_write;
        len -= to_write;
        m_pending.emplace_back(t_p, to_write, 0);
    }
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %r8, %r12
movq %rcx, %r15
movq %rdx, %rbx
movl %esi, %ebp
movq %rdi, %r14
movq %rcx, 0x8(%rsp)
leaq 0xd0(%rdi), %r13
movq %r14, %rdi
movq %r15, %rsi
callq 0x1cfaa
testb %al, %al
jne 0x1c087
movq (%r14), %rax
movq %r14, %rdi
callq *0x38(%rax)
movq %r13, %rdi
movq %r12, %rsi
callq 0x7120
jmp 0x1c062
cmpb $0x0, 0xa0(%r14)
je 0x1c098
xorl %eax, %eax
jmp 0x1c11c
movq 0x70(%r14), %rax
cmpq 0x78(%r14), %rax
je 0x1c1ee
movq %r14, %rdi
callq 0x1cffc
cmpq %r15, %rax
jae 0x1c12b
leaq 0x28(%rsp), %r15
movq %r15, %rdi
callq 0x9360
leaq 0xc64b(%rip), %rsi      # 0x28712
movq %r15, %rdi
callq 0x1d01e
leaq 0x8(%rsp), %rsi
movq %rax, %rdi
callq 0xf538
leaq 0xc64e(%rip), %rsi      # 0x28731
movq %rax, %rdi
callq 0x1d036
leaq 0x28(%rsp), %rdi
callq 0x86e4
leaq 0x88(%r14), %rdi
movq 0x8(%rsp), %rsi
callq 0x1d04e
movq 0x88(%r14), %rdi
movq 0x8(%rsp), %rdx
movq %rbx, %rsi
callq 0x7420
movb $0x1, %al
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x78(%r14), %r13
cmpq %r13, 0x70(%r14)
je 0x1c178
movq -0x10(%r13), %rbp
cmpq $0x100000, %rbp         # imm = 0x100000
je 0x1c178
movl $0x100000, %r12d        # imm = 0x100000
subq %rbp, %r12
cmpq %r12, %r15
cmovbq %r15, %r12
movq -0x8(%r13), %rdi
addq %rbp, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x7420
addq %r12, %rbp
subq %r12, %r15
movq %r15, 0x8(%rsp)
movq %rbp, -0x10(%r13)
je 0x1c11a
addq %r12, %rbx
leaq 0x70(%r14), %r12
leaq 0x18(%rsp), %rbp
leaq 0x14(%rsp), %r13
testq %r15, %r15
je 0x1c11a
movq 0x60(%r14), %rax
movq -0x8(%rax), %rdi
addq $-0x8, %rax
movq %rdi, 0x28(%rsp)
movq %rax, 0x60(%r14)
movl $0x100000, %eax         # imm = 0x100000
cmpq %rax, %r15
movl $0x100000, %edx         # imm = 0x100000
cmovbq %r15, %rdx
movq %rdx, 0x18(%rsp)
movq %rbx, %rsi
callq 0x7420
movq 0x18(%rsp), %rax
addq %rax, %rbx
subq %rax, %r15
movq %r15, 0x8(%rsp)
andl $0x0, 0x14(%rsp)
movq %r12, %rdi
leaq 0x28(%rsp), %rsi
movq %rbp, %rdx
movq %r13, %rcx
callq 0x1d07a
jmp 0x1c186
addq %rax, %rbx
subq %rax, %r15
testq %r15, %r15
je 0x1c11a
movl %ebp, %edi
movq %rbx, %rsi
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x7260
cmpq $-0x1, %rax
jne 0x1c1e8
callq 0x7030
movl (%rax), %r12d
cmpl $0x4, %r12d
je 0x1c1ee
cmpl $0xb, %r12d
jne 0x1c22a
movq %r15, 0x8(%rsp)
jmp 0x1c0a6
movq %r15, 0x8(%rsp)
callq 0x72f0
movq (%rax), %rcx
movq %rax, %rdi
movl %r12d, %esi
callq *0x28(%rcx)
cmpl $0x20, %eax
je 0x1c091
movl %eax, %ebx
movq %rdx, %r14
leaq 0x18(%rsp), %r15
movq %r15, %rdi
callq 0x865e
leaq 0xc499(%rip), %rsi      # 0x286fb
movq %r15, %rdi
callq 0x1cfe4
leaq 0x14(%rsp), %rsi
movl %ebx, (%rsi)
movq %rax, %rdi
callq 0x93b8
leaq 0x9e52(%rip), %rsi      # 0x260d2
movq %rax, %rdi
callq 0x86b2
movq %rax, %r15
movq (%r14), %rax
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq *0x20(%rax)
leaq 0x28(%rsp), %rsi
movq %r15, %rdi
callq 0x869a
leaq 0x28(%rsp), %rdi
callq 0x71d0
leaq 0x18(%rsp), %rdi
callq 0x86e4
jmp 0x1c091
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x71d0
jmp 0x1c2d7
jmp 0x1c2d4
jmp 0x1c2d4
movq %rax, %rbx
leaq 0x18(%rsp), %rdi
jmp 0x1c2e6
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x86e4
movq %rbx, %rdi
callq 0x7990
nop