// File: 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
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movq %r8, -0x30(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0x57da0
xorb $-0x1, %al
testb $0x1, %al
jne 0x55ca1
jmp 0x55cc7
movq -0xf8(%rbp), %rdi
movq (%rdi), %rax
callq *0x38(%rax)
movq -0xf8(%rbp), %rdi
addq $0xd0, %rdi
movq -0x30(%rbp), %rsi
callq 0x8190
jmp 0x55c89
movq -0xf8(%rbp), %rax
testb $0x1, 0xa0(%rax)
je 0x55ce0
movb $0x0, -0x1(%rbp)
jmp 0x56169
movq -0xf8(%rbp), %rdi
addq $0x70, %rdi
callq 0x3cd90
testb $0x1, %al
jne 0x55cf9
jmp 0x55e9f
jmp 0x55cfb
cmpq $0x0, -0x28(%rbp)
jbe 0x55e8d
movl -0x14(%rbp), %edi
movq -0x20(%rbp), %rsi
movq -0x28(%rbp), %rdx
xorl %ecx, %ecx
callq 0x8310
movq %rax, -0x38(%rbp)
cmpq $-0x1, -0x38(%rbp)
jne 0x55e6d
callq 0x8050
cmpl $0xb, (%rax)
je 0x55d3b
callq 0x8050
cmpl $0xb, (%rax)
jne 0x55d40
jmp 0x55e8d
callq 0x8050
cmpl $0x4, (%rax)
jne 0x55d4c
jmp 0x55cfb
callq 0x83a0
movq %rax, -0x100(%rbp)
callq 0x8050
movq -0x100(%rbp), %rdi
movl (%rax), %esi
movq (%rdi), %rax
callq *0x28(%rax)
movl %eax, -0x48(%rbp)
movq %rdx, -0x40(%rbp)
leaq -0x48(%rbp), %rdi
callq 0xe060
cmpl $0x20, %eax
je 0x55e64
leaq -0x58(%rbp), %rdi
movq %rdi, -0x110(%rbp)
callq 0xa600
movq -0x110(%rbp), %rdi
leaq 0x26d6d(%rip), %rsi     # 0x7cb10
callq 0x57e20
movq %rax, -0x108(%rbp)
jmp 0x55db1
leaq -0x48(%rbp), %rdi
callq 0xe060
movq -0x108(%rbp), %rdi
movl %eax, -0x68(%rbp)
leaq -0x68(%rbp), %rsi
callq 0xdff0
movq %rax, -0x118(%rbp)
jmp 0x55dd6
movq -0x118(%rbp), %rdi
leaq 0x2430e(%rip), %rsi     # 0x7a0f2
callq 0xa6e0
movq %rax, -0x120(%rbp)
jmp 0x55df2
leaq -0x88(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0xdfa0
jmp 0x55e04
movq -0x120(%rbp), %rdi
leaq -0x88(%rbp), %rsi
callq 0xa690
jmp 0x55e19
leaq -0x88(%rbp), %rdi
callq 0x83f0
leaq -0x58(%rbp), %rdi
callq 0xa770
jmp 0x55e64
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
jmp 0x55e56
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x83f0
leaq -0x58(%rbp), %rdi
callq 0xa770
jmp 0x56177
movb $0x0, -0x1(%rbp)
jmp 0x56169
movq -0x38(%rbp), %rax
addq -0x20(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x38(%rbp), %rcx
movq -0x28(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x28(%rbp)
jmp 0x55cfb
cmpq $0x0, -0x28(%rbp)
jne 0x55e9d
movb $0x1, -0x1(%rbp)
jmp 0x56169
jmp 0x55e9f
movq -0xf8(%rbp), %rdi
callq 0x57e60
cmpq -0x28(%rbp), %rax
jae 0x55f7e
leaq -0x98(%rbp), %rdi
movq %rdi, -0x130(%rbp)
callq 0xded0
movq -0x130(%rbp), %rdi
leaq 0x26c51(%rip), %rsi     # 0x7cb27
callq 0x57ee0
movq %rax, -0x128(%rbp)
jmp 0x55ee4
movq -0x128(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x24e10
movq %rax, -0x138(%rbp)
jmp 0x55efd
movq -0x138(%rbp), %rdi
leaq 0x26c3b(%rip), %rsi     # 0x7cb46
callq 0x57f20
jmp 0x55f12
leaq -0x98(%rbp), %rdi
callq 0xa770
movq -0xf8(%rbp), %rdi
addq $0x88, %rdi
movq -0x28(%rbp), %rsi
callq 0x57f60
movq -0xf8(%rbp), %rdi
addq $0x88, %rdi
callq 0x34be0
movq %rax, %rdi
movq -0x20(%rbp), %rsi
movq -0x28(%rbp), %rdx
callq 0x8540
movb $0x1, -0x1(%rbp)
jmp 0x56169
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x98(%rbp), %rdi
callq 0xa770
jmp 0x56177
movq -0xf8(%rbp), %rdi
addq $0x70, %rdi
callq 0x3cd90
testb $0x1, %al
jne 0x560a8
movq -0xf8(%rbp), %rdi
addq $0x70, %rdi
callq 0x57ff0
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
movq %rax, -0x140(%rbp)
leaq -0xc8(%rbp), %rdi
leaq -0xa8(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
leaq 0x26c86(%rip), %rcx     # 0x7cc5d
callq 0x58030
movq -0x140(%rbp), %rsi
leaq -0xc8(%rbp), %rdi
callq 0x58070
movl $0x100000, %eax         # imm = 0x100000
subq -0xb0(%rbp), %rax
movq %rax, -0xd0(%rbp)
cmpq $0x0, -0xd0(%rbp)
jbe 0x560a6
leaq -0xd0(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0xd660
movq (%rax), %rax
movq %rax, -0xd8(%rbp)
movq -0xa8(%rbp), %rdi
addq -0xb0(%rbp), %rdi
movq -0x20(%rbp), %rsi
movq -0xd8(%rbp), %rdx
callq 0x8540
movq -0xd8(%rbp), %rax
addq -0x20(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0xd8(%rbp), %rcx
movq -0x28(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x28(%rbp)
movq -0xb0(%rbp), %rax
addq -0xd8(%rbp), %rax
movq %rax, -0x148(%rbp)
movq -0xa0(%rbp), %rdi
callq 0x580a0
movq -0x148(%rbp), %rcx
movq %rcx, (%rax)
cmpq $0x0, -0x28(%rbp)
jne 0x560a4
movb $0x1, -0x1(%rbp)
jmp 0x56169
jmp 0x560a6
jmp 0x560a8
jmp 0x560aa
cmpq $0x0, -0x28(%rbp)
jbe 0x56165
movq -0xf8(%rbp), %rdi
addq $0x58, %rdi
callq 0x580c0
movq -0xf8(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0xe0(%rbp)
addq $0x58, %rdi
callq 0x58100
leaq -0x28(%rbp), %rdi
leaq 0x26b4e(%rip), %rsi     # 0x7cc38
callq 0xd660
movq (%rax), %rax
movq %rax, -0xe8(%rbp)
movq -0xe0(%rbp), %rdi
movq -0x20(%rbp), %rsi
movq -0xe8(%rbp), %rdx
callq 0x8540
movq -0xf8(%rbp), %rdi
movq -0xe8(%rbp), %rax
addq -0x20(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0xe8(%rbp), %rcx
movq -0x28(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x28(%rbp)
addq $0x70, %rdi
movl $0x0, -0xec(%rbp)
leaq -0xe0(%rbp), %rsi
leaq -0xe8(%rbp), %rdx
leaq -0xec(%rbp), %rcx
callq 0x58130
jmp 0x560aa
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
movq -0x60(%rbp), %rdi
callq 0x8bc0