Example #1
0
/* Notify the listener that the client has finished sending a message, and
 * transfer all details for handling the response to it. Blocking. */
static bool enqueue_EXPECT_message_to_listener(bus *b, boxed_msg *box) {
    /* Notify listener that it should expect a response to a
     * successfully sent message. */
    BUS_LOG_SNPRINTF(b, 3, LOG_SENDER, b->udata, 128,
        "telling listener to EXPECT sent response, with box %p, seq_id %lld",
        (void *)box, (long long)box->out_seq_id);
    
    if (box->result.status == BUS_SEND_UNDEFINED) {
        box->result.status = BUS_SEND_REQUEST_COMPLETE;
    }

    struct listener *l = Bus_GetListenerForSocket(b, box->fd);

    for (int retries = 0; retries < SEND_NOTIFY_LISTENER_RETRIES; retries++) {
        #ifndef TEST
        uint16_t backpressure = 0;
        #endif
        /* If this succeeds, then this thread cannot touch the box anymore. */
        if (Listener_ExpectResponse(l, box, &backpressure)) {
            Bus_BackpressureDelay(b, backpressure,
                LISTENER_EXPECT_BACKPRESSURE_SHIFT);
            return true;
        } else {
            BUS_LOG_SNPRINTF(b, 5, LOG_SENDER, b->udata, 64,
                "enqueue_request_sent: failed delivery %d", retries);
            syscall_poll(NULL, 0, SEND_NOTIFY_LISTENER_RETRY_DELAY);
        }
    }

    /* Timeout, will be treated as a TX error */
    return false;
}
Example #2
0
bool BusPoll_OnCompletion(struct bus *b, int fd) {
    /* POLL in a pipe */
    #ifndef TEST
    struct pollfd fds[1];
    #endif
    fds[0].fd = fd;
    fds[0].events = POLLIN;

    for (;;) {
        BUS_LOG(b, 5, LOG_SENDING_REQUEST, "Polling on completion...tick...", b->udata);
        #ifdef TEST
        errno = poll_errno;
        #endif
        BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64,
            "poll_on_completion, polling %d", fd);
        int res = syscall_poll(fds, 1, -1);
        BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64,
            "poll_on_completion for %d, res %d (errno %d)", fd, res, errno);
        if (res == -1) {
            if (Util_IsResumableIOError(errno)) {
                BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64,
                    "poll_on_completion, resumable IO error %d", errno);
                errno = 0;
                continue;
            } else {
                BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64,
                    "poll_on_completion, non-resumable IO error %d", errno);
                return false;
            }
        } else if (res == 1) {
            uint16_t msec = 0;
            #ifndef TEST
            uint8_t read_buf[sizeof(uint8_t) + sizeof(uint16_t)];
            #endif

            if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
                BUS_LOG(b, 1, LOG_SENDING_REQUEST, "failed (broken alert pipe)", b->udata);
                return false;
            }

            BUS_LOG(b, 3, LOG_SENDING_REQUEST, "Reading alert pipe...", b->udata);
            #ifdef TEST
            errno = read_errno;
            #endif
            ssize_t sz = syscall_read(fd, read_buf, sizeof(read_buf));

            if (sz == sizeof(read_buf)) {
                /* Payload: little-endian uint16_t, msec of backpressure. */
                assert(read_buf[0] == LISTENER_MSG_TAG);

                msec = (read_buf[1] << 0) + (read_buf[2] << 8);
                Bus_BackpressureDelay(b, msec, LISTENER_BACKPRESSURE_SHIFT);
                BUS_LOG(b, 4, LOG_SENDING_REQUEST, "sent!", b->udata);
                return true;
            } else if (sz == -1) {
                if (Util_IsResumableIOError(errno)) {
                    BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64,
                        "poll_on_completion read, resumable IO error %d", errno);
                    errno = 0;
                    continue;
                } else {
                    BUS_LOG_SNPRINTF(b, 2, LOG_SENDING_REQUEST, b->udata, 64,
                        "poll_on_completion read, non-resumable IO error %d", errno);
                    errno = 0;
                    return false;
                }
            } else {
                BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64,
                    "poll_on_completion bad read size %zd", sz);
                return false;
            }
        } else {
            /* This should never happen, but I have seen it occur on OSX.
             * If we log it, reset errno, and continue, it does not appear
             * to fall into busywaiting by always returning 0. */
            BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64,
                "poll_on_completion, blocking forever returned %d, errno %d", res, errno);
            errno = 0;
        }
    }
}