Exemple #1
0
static void datacopier_writable(libxl__egc *egc, libxl__ev_fd *ev,
                                int fd, short events, short revents) {
    libxl__datacopier_state *dc = CONTAINER_OF(ev, *dc, towrite);
    STATE_AO_GC(dc->ao);

    if (datacopier_pollhup_handled(egc, dc, fd, revents, 1))
        return;

    if (revents & ~POLLOUT) {
        LOG(ERROR, "unexpected poll event 0x%x on fd %d (should be POLLOUT)"
            " writing %s during copy of %s",
            revents, fd, dc->writewhat, dc->copywhat);
        datacopier_callback(egc, dc, ERROR_FAIL, -1, EIO);
        return;
    }
    assert(revents & POLLOUT);
    for (;;) {
        libxl__datacopier_buf *buf = LIBXL_TAILQ_FIRST(&dc->bufs);
        if (!buf)
            break;
        if (!buf->used) {
            LIBXL_TAILQ_REMOVE(&dc->bufs, buf, entry);
            free(buf);
            continue;
        }
        int r = write(ev->fd, buf->buf, buf->used);
        if (r < 0) {
            if (errno == EINTR) continue;
            if (errno == EWOULDBLOCK) break;
            assert(errno);
            LOGE(ERROR, "error writing to %s during copy of %s",
                 dc->writewhat, dc->copywhat);
            datacopier_callback(egc, dc, ERROR_FAIL, 1, errno);
            return;
        }
        assert(r > 0);
        assert(r <= buf->used);
        buf->used -= r;
        dc->used -= r;
        assert(dc->used >= 0);
        memmove(buf->buf, buf->buf+r, buf->used);
    }
    datacopier_check_state(egc, dc);
}
Exemple #2
0
static void datacopier_readable(libxl__egc *egc, libxl__ev_fd *ev,
                                int fd, short events, short revents) {
    libxl__datacopier_state *dc = CONTAINER_OF(ev, *dc, toread);
    STATE_AO_GC(dc->ao);

    if (datacopier_pollhup_handled(egc, dc, fd, revents, 0))
        return;

    if (revents & ~(POLLIN|POLLHUP)) {
        LOG(ERROR, "unexpected poll event 0x%x on fd %d (expected POLLIN "
            "and/or POLLHUP) reading %s during copy of %s",
            revents, fd, dc->readwhat, dc->copywhat);
        datacopier_callback(egc, dc, ERROR_FAIL, -1, EIO);
        return;
    }
    assert(revents & (POLLIN|POLLHUP));
    for (;;) {
        libxl__datacopier_buf *buf = NULL;
        int r;

        if (dc->readbuf) {
            r = read(ev->fd, dc->readbuf + dc->used, dc->bytes_to_read);
        } else {
            while (dc->used >= dc->maxsz) {
                libxl__datacopier_buf *rm = LIBXL_TAILQ_FIRST(&dc->bufs);
                dc->used -= rm->used;
                assert(dc->used >= 0);
                LIBXL_TAILQ_REMOVE(&dc->bufs, rm, entry);
                free(rm);
            }

            buf = LIBXL_TAILQ_LAST(&dc->bufs, libxl__datacopier_bufs);
            if (!buf || buf->used >= sizeof(buf->buf)) {
                buf = libxl__malloc(NOGC, sizeof(*buf));
                buf->used = 0;
                LIBXL_TAILQ_INSERT_TAIL(&dc->bufs, buf, entry);
            }
            r = read(ev->fd, buf->buf + buf->used,
                     min_t(size_t, sizeof(buf->buf) - buf->used,
                           (dc->bytes_to_read == -1) ? SIZE_MAX : dc->bytes_to_read));
        }
        if (r < 0) {
            if (errno == EINTR) continue;
            assert(errno);
            if (errno == EWOULDBLOCK) {
                if (revents & POLLHUP) {
                    LOG(ERROR,
                        "poll reported HUP but fd read gave EWOULDBLOCK"
                        " on %s during copy of %s",
                        dc->readwhat, dc->copywhat);
                    datacopier_callback(egc, dc, ERROR_FAIL, -1, 0);
                    return;
                }
                break;
            }
            LOGE(ERROR, "error reading %s during copy of %s",
                 dc->readwhat, dc->copywhat);
            datacopier_callback(egc, dc, ERROR_FAIL, 0, errno);
            return;
        }
        if (r == 0) {
            if (dc->callback_pollhup) {
                /* It might be that this "eof" is actually a HUP.  If
                 * the caller cares about the difference,
                 * double-check using poll(2). */
                struct pollfd hupchk;
                hupchk.fd = ev->fd;
                hupchk.events = POLLIN;
                hupchk.revents = 0;
                r = poll(&hupchk, 1, 0);
                if (r < 0)
                    LIBXL__EVENT_DISASTER(egc,
     "unexpected failure polling fd for datacopier eof hup check",
                                  errno, 0);
                if (datacopier_pollhup_handled(egc, dc, fd, hupchk.revents, 0))
                    return;
            }
            libxl__ev_fd_deregister(gc, &dc->toread);
            break;
        }
        if (dc->log) {
            int wrote = fwrite(buf->buf + buf->used, 1, r, dc->log);
            if (wrote != r) {
                assert(ferror(dc->log));
                assert(errno);
                LOGE(ERROR, "error logging %s", dc->copywhat);
                datacopier_callback(egc, dc, ERROR_FAIL, 0, errno);
                return;
            }
        }
        if (!dc->readbuf) {
            buf->used += r;
            assert(buf->used <= sizeof(buf->buf));
        }
        dc->used += r;
        if (dc->bytes_to_read > 0)
            dc->bytes_to_read -= r;
        if (dc->bytes_to_read == 0)
            break;
    }
    datacopier_check_state(egc, dc);
}
Exemple #3
0
static void datacopier_readable(libxl__egc *egc, libxl__ev_fd *ev,
                                int fd, short events, short revents) {
    libxl__datacopier_state *dc = CONTAINER_OF(ev, *dc, toread);
    STATE_AO_GC(dc->ao);

    if (datacopier_pollhup_handled(egc, dc, revents, 0))
        return;

    if (revents & ~POLLIN) {
        LOG(ERROR, "unexpected poll event 0x%x (should be POLLIN)"
            " on %s during copy of %s", revents, dc->readwhat, dc->copywhat);
        datacopier_callback(egc, dc, -1, 0);
        return;
    }
    assert(revents & POLLIN);
    for (;;) {
        while (dc->used >= dc->maxsz) {
            libxl__datacopier_buf *rm = LIBXL_TAILQ_FIRST(&dc->bufs);
            dc->used -= rm->used;
            assert(dc->used >= 0);
            LIBXL_TAILQ_REMOVE(&dc->bufs, rm, entry);
            free(rm);
        }

        libxl__datacopier_buf *buf =
            LIBXL_TAILQ_LAST(&dc->bufs, libxl__datacopier_bufs);
        if (!buf || buf->used >= sizeof(buf->buf)) {
            buf = malloc(sizeof(*buf));
            if (!buf) libxl__alloc_failed(CTX, __func__, 1, sizeof(*buf));
            buf->used = 0;
            LIBXL_TAILQ_INSERT_TAIL(&dc->bufs, buf, entry);
        }
        int r = read(ev->fd,
                     buf->buf + buf->used,
                     sizeof(buf->buf) - buf->used);
        if (r < 0) {
            if (errno == EINTR) continue;
            if (errno == EWOULDBLOCK) break;
            LOGE(ERROR, "error reading %s during copy of %s",
                 dc->readwhat, dc->copywhat);
            datacopier_callback(egc, dc, 0, errno);
            return;
        }
        if (r == 0) {
            libxl__ev_fd_deregister(gc, &dc->toread);
            break;
        }
        if (dc->log) {
            int wrote = fwrite(buf->buf + buf->used, 1, r, dc->log);
            if (wrote != r) {
                assert(ferror(dc->log));
                assert(errno);
                LOGE(ERROR, "error logging %s", dc->copywhat);
                datacopier_callback(egc, dc, 0, errno);
                return;
            }
        }
        buf->used += r;
        dc->used += r;
        assert(buf->used <= sizeof(buf->buf));
    }
    datacopier_check_state(egc, dc);
}