// File: /workspace/github_cpp_makefile_star2_O3/AndreRenaud[P]simple_uart/simple_uart.c
// Function: simple_uart_read_timeout
ssize_t simple_uart_read_timeout(struct simple_uart *sc, void *buffer, size_t max_len, uint64_t timeout_ms)
{
    if (!sc)
        return -EINVAL;
    if (max_len == 0)
        return 0; // Nothing to read, but not an error
    if (!buffer)
        return -EINVAL;

    ssize_t r = 0;
#ifdef _WIN32
    COMMTIMEOUTS commTimeout;
    DWORD bytes_read = 0;

    /* Get the comm timeouts */
    if (GetCommTimeouts(sc->port, &commTimeout)) {
        if (timeout_ms == 0) {
            /* Non-blocking: return immediately with whatever data is there */
            commTimeout.ReadIntervalTimeout = MAXDWORD;
            commTimeout.ReadTotalTimeoutMultiplier = MAXDWORD;
            commTimeout.ReadTotalTimeoutConstant = 1;
        } else {
            /* Blocking with timeout */
            commTimeout.ReadIntervalTimeout = 0;
            commTimeout.ReadTotalTimeoutMultiplier = 0;
            commTimeout.ReadTotalTimeoutConstant = (DWORD)timeout_ms;
        }
        SetCommTimeouts(sc->port, &commTimeout);
    }
    if (max_len > ULONG_MAX)
        max_len = ULONG_MAX; // avoid overflow at typecast
    if (!ReadFile(sc->port, buffer, (DWORD)max_len, &bytes_read, NULL))
        return win32_errno();
    r = (ssize_t)bytes_read;
#else
    fd_set readfds, exceptfds;
    struct timeval t;

    FD_ZERO(&readfds);
    FD_SET(sc->fd, &readfds);
    FD_ZERO(&exceptfds);
    FD_SET(sc->fd, &exceptfds);
    t.tv_sec = timeout_ms / 1000;
    t.tv_usec = (timeout_ms % 1000) * 1000;

    r = select(sc->fd + 1, &readfds, NULL, &exceptfds, &t);
    if (r < 0)
        return -errno;
    if (r == 0)
        return -ETIMEDOUT; // Timeout occurred
    r = read(sc->fd, buffer, max_len);
    if (r < 0)
        r = -errno;
#endif
    if (r > 0 && sc->logfile) {
        fwrite(buffer, (size_t)r, 1, sc->logfile);
        fflush(sc->logfile);
    }
    return r;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq $-0x16, %r12
testq %rdi, %rdi
je 0x58e5
movq %rdx, %r15
testq %rdx, %rdx
je 0x58cc
movq %rsi, %r14
testq %rsi, %rsi
je 0x58e5
movq %rcx, %r9
movq %rdi, %rbx
xorps %xmm0, %xmm0
leaq 0x90(%rsp), %rsi
movaps %xmm0, (%rsi)
movaps %xmm0, 0x10(%rsi)
movaps %xmm0, 0x20(%rsi)
movaps %xmm0, 0x30(%rsi)
movaps %xmm0, 0x40(%rsi)
movaps %xmm0, 0x50(%rsi)
movaps %xmm0, 0x60(%rsi)
movaps %xmm0, 0x70(%rsi)
movl (%rdi), %edi
leal 0x3f(%rdi), %eax
testl %edi, %edi
cmovnsl %edi, %eax
movl %eax, %edx
andl $-0x40, %edx
movl %edi, %ecx
subl %edx, %ecx
movl $0x1, %edx
shlq %cl, %rdx
sarl $0x6, %eax
cltq
orq %rdx, 0x90(%rsp,%rax,8)
leaq 0x10(%rsp), %rcx
movaps %xmm0, (%rcx)
movaps %xmm0, 0x10(%rcx)
movaps %xmm0, 0x20(%rcx)
movaps %xmm0, 0x30(%rcx)
movaps %xmm0, 0x40(%rcx)
movaps %xmm0, 0x50(%rcx)
movaps %xmm0, 0x60(%rcx)
movaps %xmm0, 0x70(%rcx)
orq %rdx, 0x10(%rsp,%rax,8)
movq %r9, %rax
shrq $0x3, %rax
movabsq $0x20c49ba5e353f7cf, %rdx # imm = 0x20C49BA5E353F7CF
mulq %rdx
shrq $0x4, %rdx
movq %rsp, %r8
movq %rdx, (%r8)
imulq $0x3e8, %rdx, %rax      # imm = 0x3E8
subq %rax, %r9
imulq $0x3e8, %r9, %rax       # imm = 0x3E8
movq %rax, 0x8(%r8)
incl %edi
xorl %edx, %edx
callq 0x2290
testl %eax, %eax
js 0x58d1
je 0x58de
movl (%rbx), %edi
movq %r14, %rsi
movq %r15, %rdx
callq 0x21f0
movq %rax, %r12
testq %rax, %rax
jns 0x58a3
callq 0x2060
movslq (%rax), %r12
negq %r12
testq %r12, %r12
jle 0x58e5
movq 0x8(%rbx), %rcx
testq %rcx, %rcx
je 0x58e5
movl $0x1, %edx
movq %r14, %rdi
movq %r12, %rsi
callq 0x2390
movq 0x8(%rbx), %rdi
callq 0x22a0
jmp 0x58e5
xorl %r12d, %r12d
jmp 0x58e5
callq 0x2060
movslq (%rax), %r12
negq %r12
jmp 0x58e5
movq $-0x6e, %r12
movq %r12, %rax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r14
popq %r15
retq