// File: /workspace/github_cpp_makefile_star2_O3/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 $0x38, %rsp
movq %r8, %r12
movq %rcx, %rbx
movq %rdx, %r14
movl %esi, %ebp
movq %rdi, %r15
movq %rcx, %rsi
callq 0x21410
testb %al, %al
jne 0x20052
leaq 0xd0(%r15), %r13
movq (%r15), %rax
movq %r15, %rdi
callq *0x38(%rax)
movq %r13, %rdi
movq %r12, %rsi
callq 0x7100
movq %r15, %rdi
movq %rbx, %rsi
callq 0x21410
testb %al, %al
je 0x2002f
cmpb $0x0, 0xa0(%r15)
je 0x20064
xorl %r12d, %r12d
jmp 0x2024a
movq 0x70(%r15), %rax
movq 0x78(%r15), %r13
cmpq %r13, %rax
je 0x200e5
movq 0x60(%r15), %rcx
subq 0x58(%r15), %rcx
shlq $0x11, %rcx
cmpq %r13, %rax
je 0x20133
subq -0x10(%r13), %rcx
addq $0x100000, %rcx         # imm = 0x100000
cmpq %rbx, %rcx
jb 0x2013c
movq -0x10(%r13), %rbp
cmpq $0x100000, %rbp         # imm = 0x100000
je 0x201e0
movl $0x100000, %r12d        # imm = 0x100000
subq %rbp, %r12
cmpq %r12, %rbx
cmovbq %rbx, %r12
movq -0x8(%r13), %rdi
addq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x7400
addq %r12, %rbp
movq %rbp, -0x10(%r13)
subq %r12, %rbx
je 0x20247
addq %r12, %r14
jmp 0x201e5
movb $0x1, %r12b
testq %rbx, %rbx
je 0x2024a
movl %ebp, %edi
movq %r14, %rsi
movq %rbx, %rdx
xorl %ecx, %ecx
callq 0x7240
cmpq $-0x1, %rax
je 0x2010e
addq %rax, %r14
subq %rax, %rbx
jmp 0x200e8
callq 0x7040
movl (%rax), %r13d
cmpl $0x4, %r13d
je 0x200e8
cmpl $0xb, %r13d
jne 0x2025c
movq 0x70(%r15), %rax
movq 0x78(%r15), %r13
jmp 0x20071
cmpq %rbx, %rcx
jae 0x201e0
leaq 0x26945(%rip), %rax     # 0x46a88
movl (%rax), %eax
xorl %esi, %esi
cmpl $0x3, %eax
setge %sil
leaq 0x140f2(%rip), %rdx     # 0x34247
leaq 0x10(%rsp), %r12
movq %r12, %rdi
callq 0x96e6
movb (%r12), %al
cmpb $0x1, %al
jne 0x20184
movq 0x18(%rsp), %rdi
leaq 0x1660c(%rip), %rsi     # 0x36782
movl $0x1e, %edx
callq 0x7570
movb 0x10(%rsp), %al
testb $0x1, %al
je 0x20199
movq 0x18(%rsp), %rdi
movq %rbx, %rsi
callq 0x7330
movb 0x10(%rsp), %al
testb $0x1, %al
je 0x201b3
movq 0x18(%rsp), %rdi
leaq 0x165f8(%rip), %rsi     # 0x367a1
movl $0xc, %edx
callq 0x7570
leaq 0x10(%rsp), %rdi
callq 0x8f4e
leaq 0x88(%r15), %rdi
movq %rbx, %rsi
callq 0x21456
movq 0x88(%r15), %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x7400
jmp 0x20247
testq %rbx, %rbx
je 0x20247
leaq 0x70(%r15), %r12
leaq 0x34(%rsp), %r13
movq 0x60(%r15), %rax
movq -0x8(%rax), %rdi
addq $-0x8, %rax
movq %rdi, 0x10(%rsp)
movq %rax, 0x60(%r15)
movl $0x100000, %eax         # imm = 0x100000
cmpq %rax, %rbx
movl $0x100000, %edx         # imm = 0x100000
cmovbq %rbx, %rdx
movq %rdx, (%rsp)
movq %r14, %rsi
callq 0x7400
movq (%rsp), %rbp
addq %rbp, %r14
movl $0x0, 0x34(%rsp)
movq %r12, %rdi
leaq 0x10(%rsp), %rsi
movq %rsp, %rdx
movq %r13, %rcx
callq 0x21482
subq %rbp, %rbx
jne 0x201ee
movb $0x1, %r12b
movl %r12d, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x72e0
movq (%rax), %rcx
movq %rax, %rdi
movl %r13d, %esi
callq *0x28(%rcx)
cmpl $0x20, %eax
je 0x2005c
movl %eax, %ebx
movq %rdx, %r14
leaq 0x26806(%rip), %rax     # 0x46a88
movl (%rax), %esi
notl %esi
shrl $0x1f, %esi
leaq 0x13f36(%rip), %rdx     # 0x341c6
movq %rsp, %r15
movq %r15, %rdi
callq 0x96e6
movb (%r15), %al
cmpb $0x1, %al
jne 0x202bb
movq 0x8(%rsp), %rdi
leaq 0x164bd(%rip), %rsi     # 0x3676b
movl $0x16, %edx
callq 0x7570
movb (%rsp), %al
testb $0x1, %al
je 0x202ce
movq 0x8(%rsp), %rdi
movl %ebx, %esi
callq 0x7980
movb (%rsp), %al
testb $0x1, %al
je 0x202e8
movq 0x8(%rsp), %rdi
leaq 0x13df4(%rip), %rsi     # 0x340d2
movl $0x2, %edx
callq 0x7570
movq (%r14), %rax
leaq 0x10(%rsp), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq *0x20(%rax)
cmpb $0x1, (%rsp)
jne 0x20312
movq 0x8(%rsp), %rdi
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
callq 0x7570
leaq 0x20(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x2032d
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x7500
movq %rsp, %rdi
callq 0x8f4e
jmp 0x2005c
movq %rax, %rbx
leaq 0x20(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x20361
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x7500
jmp 0x20361
jmp 0x2035e
jmp 0x2035e
movq %rax, %rbx
movq %rsp, %rdi
jmp 0x2036e
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x8f4e
movq %rbx, %rdi
callq 0x79a0
nop