// File: cybozu[P]yrmcds/cybozu/tcp.cpp
// Function: cybozu::tcp_socket::_sendv(int, cybozu::tcp_socket::iovec const*, int, std::unique_lock<std::mutex>&)
bool tcp_socket::_sendv(int fd, const iovec* iov, const int iovcnt, lock_guard& g) {
    std::size_t total = 0;
    for( int i = 0; i < iovcnt; ++i ) {
        total += iov[i].len;
    }

    while( ! can_send(total) ) {
        on_buffer_full();
        m_cond_write.wait(g);
    }
    if( m_shutdown ) return false;

    ::iovec v[MAX_IOVCNT];
    int v_size = 0;
    for( int i = 0; i < iovcnt; ++i ) {
        if( iov[i].len == 0 )
            continue;
        v[v_size].iov_base = const_cast<char*>(iov[i].p);
        v[v_size].iov_len = iov[i].len;
        ++v_size;
    }
    int ind = 0;

    if( m_pending.empty() ) {
        while( ind < v_size ) {
            ssize_t n = ::writev(fd, &(v[ind]), v_size - ind);
            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::_sendv>: ("
                                    << ecnd.value() << ") "
                                    << ecnd.message();
                return false;
            }
            while( n > 0 ) {
                if( static_cast<std::size_t>(n) < v[ind].iov_len ) {
                    v[ind].iov_base = ((char*)v[ind].iov_base) + n;
                    v[ind].iov_len = v[ind].iov_len - n;
                    break;
                }
                n -= v[ind].iov_len;
                ++ind;
            }
        }
        if( ind == v_size ) return true;
    }

    // recalculate total length
    total = 0;
    for( int i = ind; i < v_size; ++i ) {
        total += v[i].iov_len;
    }

    // put data in the pending request queue.
    if( capacity() < total ) {
        // here, m_pending.empty() and m_tmpbuf.empty() holds true.
        logger::debug() << "<tcp_socket::_sendv> buffering "
                        << total << " bytes data.";
        m_tmpbuf.resize(total);
        char* p = m_tmpbuf.data();
        for( int i = ind; i < v_size; ++i ) {
            std::memcpy(p, v[i].iov_base, v[i].iov_len);
            p += v[i].iov_len;
        }
        return true;
    }

    while( ind < v_size ) {
        char* t_p;
        std::size_t t_len;
        if(m_pending.empty() || std::get<1>(m_pending.back()) == SENDBUF_SIZE) {
            t_p = m_free_buffers.back();
            t_len = 0;
            m_free_buffers.pop_back();
            m_pending.emplace_back(t_p, t_len, 0);
        } else {
            std::tie(t_p, t_len, std::ignore) = m_pending.back();
        }
        std::size_t room = SENDBUF_SIZE - t_len;
        while( room > 0 ) {
            std::size_t to_write = std::min(room, v[ind].iov_len);
            std::memcpy(t_p + t_len, v[ind].iov_base, to_write);
            room -= to_write;
            t_len += to_write;
            std::get<1>(m_pending.back()) = t_len;
            if( to_write == v[ind].iov_len ) {
                ++ind;
                if( ind == v_size ) break;
                continue;
            }
            v[ind].iov_base = ((char*)v[ind].iov_base) + to_write;
            v[ind].iov_len -= to_write;
        }
    }
    return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2b0, %rsp            # imm = 0x2B0
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq %r8, -0x30(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x258(%rbp)
movq $0x0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x561e5
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x561b7
jmp 0x561e7
movq -0x258(%rbp), %rdi
movq -0x38(%rbp), %rsi
callq 0x57da0
xorb $-0x1, %al
testb $0x1, %al
jne 0x561ff
jmp 0x56225
movq -0x258(%rbp), %rdi
movq (%rdi), %rax
callq *0x38(%rax)
movq -0x258(%rbp), %rdi
addq $0xd0, %rdi
movq -0x30(%rbp), %rsi
callq 0x8190
jmp 0x561e7
movq -0x258(%rbp), %rax
testb $0x1, 0xa0(%rax)
je 0x5623e
movb $0x0, -0x1(%rbp)
jmp 0x56a31
movl $0x0, -0x184(%rbp)
movl $0x0, -0x188(%rbp)
movl -0x188(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x562fb
movq -0x20(%rbp), %rax
movslq -0x188(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpq $0x0, 0x8(%rax)
jne 0x5627c
jmp 0x562e7
movq -0x20(%rbp), %rax
movslq -0x188(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rcx
movslq -0x184(%rbp), %rdx
leaq -0x180(%rbp), %rax
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, (%rax)
movq -0x20(%rbp), %rax
movslq -0x188(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rcx
movslq -0x184(%rbp), %rdx
leaq -0x180(%rbp), %rax
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, 0x8(%rax)
movl -0x184(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x184(%rbp)
movl -0x188(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x188(%rbp)
jmp 0x56252
movq -0x258(%rbp), %rdi
movl $0x0, -0x18c(%rbp)
addq $0x70, %rdi
callq 0x3cd90
testb $0x1, %al
jne 0x5631e
jmp 0x565e0
jmp 0x56320
movl -0x18c(%rbp), %eax
cmpl -0x184(%rbp), %eax
jge 0x565c7
movl -0x14(%rbp), %edi
movslq -0x18c(%rbp), %rax
leaq -0x180(%rbp), %rsi
shlq $0x4, %rax
addq %rax, %rsi
movl -0x184(%rbp), %edx
subl -0x18c(%rbp), %edx
callq 0x8330
movq %rax, -0x198(%rbp)
cmpq $-0x1, -0x198(%rbp)
jne 0x564e0
callq 0x8050
cmpl $0xb, (%rax)
je 0x56384
callq 0x8050
cmpl $0xb, (%rax)
jne 0x56389
jmp 0x565c7
callq 0x8050
cmpl $0x4, (%rax)
jne 0x56395
jmp 0x56320
callq 0x83a0
movq %rax, -0x260(%rbp)
callq 0x8050
movq -0x260(%rbp), %rdi
movl (%rax), %esi
movq (%rdi), %rax
callq *0x28(%rax)
movl %eax, -0x1a8(%rbp)
movq %rdx, -0x1a0(%rbp)
leaq -0x1a8(%rbp), %rdi
callq 0xe060
cmpl $0x20, %eax
je 0x564d7
leaq -0x1b8(%rbp), %rdi
movq %rdi, -0x270(%rbp)
callq 0xa600
movq -0x270(%rbp), %rdi
leaq 0x2675b(%rip), %rsi     # 0x7cb53
callq 0x1b730
movq %rax, -0x268(%rbp)
jmp 0x56406
leaq -0x1a8(%rbp), %rdi
callq 0xe060
movq -0x268(%rbp), %rdi
movl %eax, -0x1c8(%rbp)
leaq -0x1c8(%rbp), %rsi
callq 0xdff0
movq %rax, -0x278(%rbp)
jmp 0x56434
movq -0x278(%rbp), %rdi
leaq 0x23cb0(%rip), %rsi     # 0x7a0f2
callq 0xa6e0
movq %rax, -0x280(%rbp)
jmp 0x56450
leaq -0x1e8(%rbp), %rdi
leaq -0x1a8(%rbp), %rsi
callq 0xdfa0
jmp 0x56465
movq -0x280(%rbp), %rdi
leaq -0x1e8(%rbp), %rsi
callq 0xa690
jmp 0x5647a
leaq -0x1e8(%rbp), %rdi
callq 0x83f0
leaq -0x1b8(%rbp), %rdi
callq 0xa770
jmp 0x564d7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1c0(%rbp)
movl %eax, -0x1c4(%rbp)
jmp 0x564c6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1c0(%rbp)
movl %eax, -0x1c4(%rbp)
leaq -0x1e8(%rbp), %rdi
callq 0x83f0
leaq -0x1b8(%rbp), %rdi
callq 0xa770
jmp 0x56a3f
movb $0x0, -0x1(%rbp)
jmp 0x56a31
jmp 0x564e2
cmpq $0x0, -0x198(%rbp)
jle 0x565c2
movq -0x198(%rbp), %rax
movslq -0x18c(%rbp), %rdx
leaq -0x180(%rbp), %rcx
shlq $0x4, %rdx
addq %rdx, %rcx
cmpq 0x8(%rcx), %rax
jae 0x56584
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rcx
addq -0x198(%rbp), %rcx
movslq -0x18c(%rbp), %rdx
leaq -0x180(%rbp), %rax
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, (%rax)
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rcx
subq -0x198(%rbp), %rcx
movslq -0x18c(%rbp), %rdx
leaq -0x180(%rbp), %rax
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, 0x8(%rax)
jmp 0x565c2
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rcx
movq -0x198(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x198(%rbp)
movl -0x18c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18c(%rbp)
jmp 0x564e2
jmp 0x56320
movl -0x18c(%rbp), %eax
cmpl -0x184(%rbp), %eax
jne 0x565de
movb $0x1, -0x1(%rbp)
jmp 0x56a31
jmp 0x565e0
movq $0x0, -0x38(%rbp)
movl -0x18c(%rbp), %eax
movl %eax, -0x1ec(%rbp)
movl -0x1ec(%rbp), %eax
cmpl -0x184(%rbp), %eax
jge 0x56634
movslq -0x1ec(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movl -0x1ec(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ec(%rbp)
jmp 0x565f4
movq -0x258(%rbp), %rdi
callq 0x57e60
cmpq -0x38(%rbp), %rax
jae 0x567a6
leaq -0x200(%rbp), %rdi
movq %rdi, -0x290(%rbp)
callq 0xded0
movq -0x290(%rbp), %rdi
leaq 0x26500(%rip), %rsi     # 0x7cb6b
callq 0x581c0
movq %rax, -0x288(%rbp)
jmp 0x56679
movq -0x288(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x24e10
movq %rax, -0x298(%rbp)
jmp 0x56692
movq -0x298(%rbp), %rdi
leaq 0x264a6(%rip), %rsi     # 0x7cb46
callq 0x57f20
jmp 0x566a7
leaq -0x200(%rbp), %rdi
callq 0xa770
movq -0x258(%rbp), %rdi
addq $0x88, %rdi
movq -0x38(%rbp), %rsi
callq 0x57f60
movq -0x258(%rbp), %rdi
addq $0x88, %rdi
callq 0x34be0
movq %rax, -0x208(%rbp)
movl -0x18c(%rbp), %eax
movl %eax, -0x20c(%rbp)
movl -0x20c(%rbp), %eax
cmpl -0x184(%rbp), %eax
jge 0x5679d
movq -0x208(%rbp), %rdi
movslq -0x20c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rsi
movslq -0x20c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rdx
callq 0x8540
movslq -0x20c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
addq -0x208(%rbp), %rax
movq %rax, -0x208(%rbp)
movl -0x20c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20c(%rbp)
jmp 0x566f0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1c0(%rbp)
movl %eax, -0x1c4(%rbp)
leaq -0x200(%rbp), %rdi
callq 0xa770
jmp 0x56a3f
movb $0x1, -0x1(%rbp)
jmp 0x56a31
jmp 0x567a8
movl -0x18c(%rbp), %eax
cmpl -0x184(%rbp), %eax
jge 0x56a2d
movq -0x258(%rbp), %rdi
addq $0x70, %rdi
callq 0x3cd90
testb $0x1, %al
jne 0x567ef
movq -0x258(%rbp), %rdi
addq $0x70, %rdi
callq 0x57ff0
movq %rax, %rdi
callq 0x580a0
cmpq $0x100000, (%rax)       # imm = 0x100000
jne 0x56855
movq -0x258(%rbp), %rdi
addq $0x58, %rdi
callq 0x580c0
movq -0x258(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0x218(%rbp)
movq $0x0, -0x220(%rbp)
addq $0x58, %rdi
callq 0x58100
movq -0x258(%rbp), %rdi
addq $0x70, %rdi
movl $0x0, -0x224(%rbp)
leaq -0x218(%rbp), %rsi
leaq -0x220(%rbp), %rdx
leaq -0x224(%rbp), %rcx
callq 0x58130
jmp 0x568a0
movq -0x258(%rbp), %rdi
addq $0x70, %rdi
callq 0x57ff0
movq %rax, -0x2a0(%rbp)
leaq -0x240(%rbp), %rdi
leaq -0x218(%rbp), %rsi
leaq -0x220(%rbp), %rdx
leaq 0x263d5(%rip), %rcx     # 0x7cc5d
callq 0x58030
movq -0x2a0(%rbp), %rsi
leaq -0x240(%rbp), %rdi
callq 0x58070
movl $0x100000, %eax         # imm = 0x100000
subq -0x220(%rbp), %rax
movq %rax, -0x248(%rbp)
cmpq $0x0, -0x248(%rbp)
jbe 0x56a28
movslq -0x18c(%rbp), %rax
leaq -0x180(%rbp), %rsi
shlq $0x4, %rax
addq %rax, %rsi
addq $0x8, %rsi
leaq -0x248(%rbp), %rdi
callq 0xd660
movq (%rax), %rax
movq %rax, -0x250(%rbp)
movq -0x218(%rbp), %rdi
addq -0x220(%rbp), %rdi
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rsi
movq -0x250(%rbp), %rdx
callq 0x8540
movq -0x258(%rbp), %rdi
movq -0x250(%rbp), %rcx
movq -0x248(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x248(%rbp)
movq -0x250(%rbp), %rax
addq -0x220(%rbp), %rax
movq %rax, -0x220(%rbp)
movq -0x220(%rbp), %rax
movq %rax, -0x2a8(%rbp)
addq $0x70, %rdi
callq 0x57ff0
movq %rax, %rdi
callq 0x580a0
movq -0x2a8(%rbp), %rcx
movq %rcx, (%rax)
movq -0x250(%rbp), %rax
movslq -0x18c(%rbp), %rdx
leaq -0x180(%rbp), %rcx
shlq $0x4, %rdx
addq %rdx, %rcx
cmpq 0x8(%rcx), %rax
jne 0x569c5
movl -0x18c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18c(%rbp)
movl -0x18c(%rbp), %eax
cmpl -0x184(%rbp), %eax
jne 0x569c0
jmp 0x56a28
jmp 0x568b3
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rcx
addq -0x250(%rbp), %rcx
movslq -0x18c(%rbp), %rdx
leaq -0x180(%rbp), %rax
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, (%rax)
movq -0x250(%rbp), %rdx
movslq -0x18c(%rbp), %rcx
leaq -0x180(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rcx
subq %rdx, %rcx
movq %rcx, 0x8(%rax)
jmp 0x568b3
jmp 0x567a8
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x2b0, %rsp            # imm = 0x2B0
popq %rbp
retq
movq -0x1c0(%rbp), %rdi
callq 0x8bc0
nopl (%rax,%rax)