Skip to content

SocketPoll

Description

Wait until any item is ready. Backed by poll() on POSIX and WSAPoll() on Windows. Signatures match closely enough that a single shim works; the WSAPoll failed-connect bug from older Windows builds was fixed in Windows 10 2004 (2020).

Parameters

Name Direction Description
items in,out Array of items. Caller fills fd + events_requested; events_ready is the output.
count in Number of items in items.
timeout_ms in -1 = block forever, 0 = poll once, >0 = milliseconds.

Success

returns number of items with non-zero events_ready.

Failure

returns -1; logs the failing syscall. EINTR is transparently retried.

Usage example (Cross-references)

Usage examples (Cross-references)
    #endif
    
    i32 SocketPoll(SocketPollItem *items, u32 count, i32 timeout_ms) {
        if (!items && count > 0) {
            LOG_FATAL("SocketPoll: items is NULL but count > 0");
    i32 SocketPoll(SocketPollItem *items, u32 count, i32 timeout_ms) {
        if (!items && count > 0) {
            LOG_FATAL("SocketPoll: items is NULL but count > 0");
        }
            if (!pfds) {
                HeapAllocatorDeinit(&halloc);
                LOG_ERROR("SocketPoll: heap allocation for pollfd array failed");
                return -1;
            }
            items[1] = (SocketPollItem) {.fd = b->fd, .events_requested = SOCKET_POLL_READ};
    
            i32 ready = SocketPoll(items, 2, 1000);
            if (ready < 0) {
                return;
                // log noise when it does).
                SocketPollItem listen_item = {.fd = listener.fd, .events_requested = SOCKET_POLL_READ};
                i32            ready       = SocketPoll(&listen_item, 1, 1000);
                if (ready <= 0) {
                    continue;
    
        // Positive timeout: blocks until the byte arrives, so no race.
        i32 n = SocketPoll(&item, 1, 1000);
    
        bool ok = sent && n == 1 && (item.events_ready & SOCKET_POLL_READ) != 0 &&
        item.events_requested = SOCKET_POLL_WRITE; // not READ
    
        i32 n = SocketPoll(&item, 1, 0);
    
        // Whatever poll returns, READ must never be set since it wasn't asked.
        item.events_requested = SOCKET_POLL_WRITE;
    
        i32 n = SocketPoll(&item, 1, 1000);
    
        bool ok = n == 1 && (item.events_ready & SOCKET_POLL_WRITE) != 0 && (item.events_ready & SOCKET_POLL_READ) == 0;
        item.events_requested = SOCKET_POLL_READ; // not WRITE
    
        i32 n = SocketPoll(&item, 1, 1000);
    
        // Readable, READ requested -> READ set; WRITE must stay clear.
    
        // No data sent. READ on an idle socket with immediate timeout -> 0.
        i32 n = SocketPoll(&item, 1, 0);
    
        bool ok = n == 0 && item.events_ready == 0;
        // is deterministic. Do NOT collapse this back into one poll.
        SocketPollItem warm0 = {.fd = p0.server.fd, .events_requested = SOCKET_POLL_READ};
        (void)SocketPoll(&warm0, 1, 1000);
        SocketPollItem warm2 = {.fd = p2.server.fd, .events_requested = SOCKET_POLL_READ};
        (void)SocketPoll(&warm2, 1, 1000);
        (void)SocketPoll(&warm0, 1, 1000);
        SocketPollItem warm2 = {.fd = p2.server.fd, .events_requested = SOCKET_POLL_READ};
        (void)SocketPoll(&warm2, 1, 1000);
    
        SocketPollItem items[3]   = {0};
        items[2].events_requested = SOCKET_POLL_READ;
    
        i32 n = SocketPoll(items, 3, 1000);
    
        bool ok = sent && n == 2 && (items[0].events_ready & SOCKET_POLL_READ) != 0 &&
        items[2].events_requested = SOCKET_POLL_READ;
    
        i32 n = SocketPoll(items, 3, 1000);
    
        bool ok = sent && n == 1 && (items[0].events_ready & SOCKET_POLL_READ) == 0 &&
        item.events_requested = SOCKET_POLL_READ;
    
        i32 n = SocketPoll(&item, 1, 1000);
    
        bool ok = n == 1 && (item.events_ready & SOCKET_POLL_READ) != 0 && (item.events_ready & SOCKET_POLL_WRITE) == 0;
    bool test_sk1_zero_count_returns_zero(void) {
        // NULL items is legal exactly when count == 0.
        i32 n = SocketPoll(NULL, 0, 0);
        return n == 0;
    }
            }
    
            i32 n = SocketPoll(items, N, 0);
            ok    = n == 0;
            for (u32 i = 0; i < N; ++i)
            }
    
            i32 n = SocketPoll(items, N, 1000);
            ok    = ok && n == 1 && (items[N - 1].events_ready & SOCKET_POLL_READ) != 0;
            for (u32 i = 0; i + 1 < N; ++i)
    // pass count==1 so the > 0 guard must hold and abort).
    bool test_sk1_null_items_nonzero_count_aborts(void) {
        SocketPoll(NULL, 1, 0);
        return true; // unreachable; LOG_FATAL longjmps out
    }
        idle.fd               = server.fd;
        idle.events_requested = SOCKET_POLL_READ;
        i32 nidle             = SocketPoll(&idle, 1, 0);
        ok                    = ok && nidle == 0 && (idle.events_ready & SOCKET_POLL_READ) == 0;
        ready.fd               = server.fd;
        ready.events_requested = SOCKET_POLL_READ;
        i32 nready             = SocketPoll(&ready, 1, 1000);
        ok                     = ok && nready == 1 && (ready.events_ready & SOCKET_POLL_READ) != 0;
Last updated on