int sfdetach(int s, int64_t deadline) {
    int err = 0;
    struct sf *conn = msockdata(s, sf_type);
    if(dill_slow(!conn)) return -1;
    /* If connection is broken don't even try to do termination handshake. */
    if(conn->res == SF_RESET) {err = ECONNRESET; goto dealloc;}
    /* Ask oworker to exit. */
    struct msg msg = {NULL, 0};
    int rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    if(dill_slow(rc < 0 && errno == EPIPE)) {err = ECONNRESET; goto dealloc;}
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;}
    /* Given that there's no way for oworker to receive this message,
       the function only exits when it closes the channel. */
    rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    dill_assert(rc < 0);
    if(dill_slow(errno != EPIPE)) {err = errno; goto dealloc;}
    if(dill_slow(conn->ores == SF_RESET)) {err = ECONNRESET; goto dealloc;}
    dill_assert(conn->ores == SF_DONE);
    /* Now that oworker have exited send the termination sequence. */
    rc = bsend(conn->u, &sf_termsequence, sizeof(sf_termsequence), -1);
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;}
    rc = bflush(conn->u, deadline);
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;} 
    /* Read and drop any pending inbound messages. By doing this we'll ensure
       that reading on the underlying socket will continue from the first byte
       following the sf termination sequence. */
    if(conn->res == SF_ACTIVE) {
        while(1) {
            struct msg msg;
            rc = chrecv(conn->ichan, &msg, sizeof(msg), deadline);
            if(rc < 0) break;
            free(msg.buf);
        }
        if(dill_slow(errno != EPIPE)) {err = errno; goto dealloc;}
        if(dill_slow(conn->ires == SF_RESET)) {err = ECONNRESET; goto dealloc;}
        dill_assert(conn->ires == SF_DONE);
    }
dealloc:
    /* Deallocate the object. */
    rc = hclose(conn->iworker);
    dill_assert(rc == 0);
    rc = hclose(conn->oworker);
    dill_assert(rc == 0);
    rc = hclose(conn->ichan);
    dill_assert(rc == 0);
    rc = hclose(conn->ochan);
    dill_assert(rc == 0);
    int u = conn->u;
    free(conn);
    if(err == 0) return u;
    rc = hclose(u);
    dill_assert(rc == 0);
    errno = err;
    return -1;
}
static int sf_send(int s, const void *buf, size_t len, int64_t deadline) {
    struct sf *conn = msockdata(s, sf_type);
    if(dill_slow(!conn)) return -1;
    if(dill_slow(conn->res != SF_ACTIVE)) {errno = ECONNRESET; return -1;}
    /* Create a message object. */
    struct msg msg;
    msg.buf = malloc(len);
    if(dill_slow(!msg.buf)) {errno = ENOMEM; return -1;}
    memcpy(msg.buf, buf, len);
    msg.len = len;
    /* Send it to the worker. */
    int rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    if(dill_fast(rc >= 0)) return 0;
    /* Closed pipe means that the connection was terminated. */
    if(errno == EPIPE) {
        dill_assert(conn->ores == SF_RESET);
        conn->res = SF_RESET;
        errno = ECONNRESET;
    }
    /* Clean up. */
    int err = errno;
    free(msg.buf);
    errno = err;
    return -1;
}
Beispiel #3
0
coroutine void sender(int ch, int doyield, int val) {
    if(doyield) {
        int rc = yield();
        errno_assert(rc == 0);
    }
    int rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #4
0
coroutine void receiver2(int ch) {
    int val;
    int rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == EPIPE);
    val = 0;
    rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #5
0
coroutine void sender3(int ch, int doyield) {
    if(doyield) {
        int rc = yield();
        errno_assert(rc == 0);
    }
    int rc = chsend(ch, NULL, 0, -1);
    errno_assert(rc == 0);
}
Beispiel #6
0
coroutine void feeder(int ch, int val) {
    while(1) {
        int rc = chsend(ch, &val, sizeof(val), -1);
        if(rc == -1 && errno == ECANCELED) return;
        errno_assert(rc == 0);
        rc = yield();
        if(rc == -1 && errno == ECANCELED) return;
        errno_assert(rc == 0);
    }
}
Beispiel #7
0
coroutine void dialogue(int s, int ch) {
    int op = CONN_ESTABLISHED;
    int rc = chsend(ch, &op, sizeof(op), -1);
    assert(rc == 0);
    int64_t deadline = now() + 60000;
    rc = msend(s, "What's your name?", 17, deadline);
    if(rc != 0) goto cleanup;
    char inbuf[256];
    ssize_t sz = mrecv(s, inbuf, sizeof(inbuf), deadline);
    if(sz < 0) goto cleanup;
    inbuf[sz] = 0;
    char outbuf[256];
    rc = snprintf(outbuf, sizeof(outbuf), "Hello, %s!", inbuf);
    rc = msend(s, outbuf, rc, deadline);
    if(rc != 0) goto cleanup;
cleanup:
    op = errno == 0 ? CONN_SUCCEEDED : CONN_FAILED;
    rc = chsend(ch, &op, sizeof(op), -1);
    assert(rc == 0 || errno == ECANCELED);
    rc = hclose(s);
    assert(rc == 0);
}
Beispiel #8
0
static int nagle_bsendv(struct bsock_vfs *bvfs,
      const struct iovec *iov, size_t iovlen, int64_t deadline) {
    struct nagle_sock *obj = dsock_cont(bvfs, struct nagle_sock, bvfs);
    /* Send is done in a worker coroutine. */
    struct nagle_vec vec = {iov, iovlen};
    int rc = chsend(obj->sendch, &vec, sizeof(vec), deadline);
    if(dsock_slow(rc < 0)) return -1;
    /* Wait till worker is done. */
    int err;
    rc = chrecv(obj->ackch, &err, sizeof(err), deadline);
    if(dsock_slow(rc < 0)) return -1;
    if(dsock_slow(rc < 0)) {errno = err; return -1;}
    return 0;
}
static coroutine void sf_iworker(struct sf *conn) {
    struct msg msg = {NULL, 0};
    while(1) {
        uint64_t hdr;
        int rc = brecv(conn->u, &hdr, sizeof(hdr), -1);
        CHECKRC(ires)
        if(dill_slow(hdr == sf_termsequence)) {conn->ires = SF_DONE; break;}
        msg.len = (size_t)dill_getll((uint8_t*)&hdr);
        msg.buf = malloc(msg.len);
        dill_assert(msg.buf);
        rc = brecv(conn->u, msg.buf, msg.len, -1);
        CHECKRC(ires)
        rc = chsend(conn->ichan, &msg, sizeof(msg), -1);
        if(dill_slow(rc < 0 && errno == ECANCELED)) break;
        dill_assert(rc == 0);
        msg.buf = NULL;
        msg.len = 0;
    }
    free(msg.buf);
    int rc = chdone(conn->ichan);
    dill_assert(rc == 0);
}
int main(int argc, char *argv[]) {
    if(argc != 2) {
        printf("usage: chrecv <millions-of-messages>\n");
        return 1;
    }
    long count = atol(argv[1]) * 1000000;

    int ch = channel(sizeof(char), count);
    assert(ch >= 0);

    long i;
    char val = 0;
    for(i = 0; i != count; ++i) {
        int rc = chsend(ch, &val, sizeof(char), -1);
        assert(rc == 0);
    }

    int64_t start = now();

    for(i = 0; i != count; ++i) {
        int rc = chrecv(ch, &val, sizeof(char), -1);
        assert(rc == 0);
    }

    int64_t stop = now();
    long duration = (long)(stop - start);
    long ns = duration * 1000000 / count;

    printf("received %ldM messages in %f seconds\n",
        (long)(count / 1000000), ((float)duration) / 1000);
    printf("duration of receiving a single message: %ld ns\n", ns);
    printf("message received per second: %fM\n",
        (float)(1000000000 / ns) / 1000000);

    return 0;
}
Beispiel #11
0
int main() {
    int val;
    int rc;

    /* Receiver waits for sender. */
    int ch1[2];
    rc = chmake(ch1);
    errno_assert(rc == 0);
    assert(ch1[0] >= 0);
    assert(ch1[1] >= 0);
    int hndl1 = go(sender(ch1[0], 1, 333));
    errno_assert(hndl1 >= 0);
    rc = chrecv(ch1[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 333);
    rc = hclose(ch1[1]);
    errno_assert(rc == 0);
    rc = hclose(ch1[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl1);
    errno_assert(rc == 0);

    /* Sender waits for receiver. */
    int ch2[2];
    rc = chmake(ch2);
    errno_assert(rc == 0);
    int hndl2 = go(sender(ch2[0], 0, 444));
    errno_assert(hndl2 >= 0);
    rc = chrecv(ch2[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 444);
    rc = hclose(ch2[1]);
    errno_assert(rc == 0);
    rc = hclose(ch2[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl2);
    errno_assert(rc == 0);

    /* Test two simultaneous senders. */
    int ch3[2];
    rc = chmake(ch3);
    errno_assert(rc == 0);
    int hndl3[2];
    hndl3[0] = go(sender(ch3[0], 0, 888));
    errno_assert(hndl3[0] >= 0);
    hndl3[1] = go(sender(ch3[0], 0, 999));
    errno_assert(hndl3[1] >= 0);
    rc = chrecv(ch3[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 888);
    rc = yield();
    errno_assert(rc == 0);
    rc = chrecv(ch3[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 999);
    rc = hclose(ch3[1]);
    errno_assert(rc == 0);
    rc = hclose(ch3[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl3[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl3[1]);
    errno_assert(rc == 0);

    /* Test two simultaneous receivers. */
    int ch4[2];
    rc = chmake(ch4);
    errno_assert(rc == 0);
    int hndl4[2];
    hndl4[0] = go(receiver(ch4[0], 333));
    errno_assert(hndl4[0] >= 0);
    hndl4[1] = go(receiver(ch4[0], 444));
    errno_assert(hndl4[1] >= 0);
    val = 333;
    rc = chsend(ch4[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    val = 444;
    rc = chsend(ch4[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    rc = hclose(ch4[1]);
    errno_assert(rc == 0);
    rc = hclose(ch4[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl4[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl4[1]);
    errno_assert(rc == 0);

    /* Test simple chdone() scenario. */
    int ch8[2];
    rc = chmake(ch8);
    errno_assert(rc == 0);
    rc = chdone(ch8[0]);
    errno_assert(rc == 0);
    rc = chrecv(ch8[1], &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == EPIPE);
    rc = chrecv(ch8[1], &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == EPIPE);
    rc = chrecv(ch8[1], &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == EPIPE);
    rc = hclose(ch8[1]);
    errno_assert(rc == 0);
    rc = hclose(ch8[0]);
    errno_assert(rc == 0);

    /* Test whether chdone() unblocks all receivers. */
    int ch12[2];
    rc = chmake(ch12);
    errno_assert(rc == 0);
    int hndl6[2];
    hndl6[0] = go(receiver2(ch12[0]));
    errno_assert(hndl6[0] >= 0);
    hndl6[1] = go(receiver2(ch12[0]));
    errno_assert(hndl6[1] >= 0);
    rc = chdone(ch12[1]);
    errno_assert(rc == 0);
    rc = chrecv(ch12[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 0);
    rc = chrecv(ch12[1], &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 0);
    rc = hclose(ch12[1]);
    errno_assert(rc == 0);
    rc = hclose(ch12[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl6[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl6[1]);
    errno_assert(rc == 0);

    /* Test whether chdone() unblocks blocked senders. */
    int ch15[2];
    rc = chmake(ch15);
    errno_assert(rc == 0);
    int hndl8[3];
    hndl8[0] = go(sender2(ch15[0]));
    errno_assert(hndl8[0] >= 0);
    hndl8[1] = go(sender2(ch15[0]));
    errno_assert(hndl8[1] >= 0);
    hndl8[2] = go(sender2(ch15[0]));
    errno_assert(hndl8[2] >= 0);
    rc = msleep(now() + 50);
    errno_assert(rc == 0);
    rc = chdone(ch15[1]);
    errno_assert(rc == 0);
    rc = hclose(ch15[1]);
    errno_assert(rc == 0);
    rc = hclose(ch15[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl8[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl8[1]);
    errno_assert(rc == 0);
    rc = hclose(hndl8[2]);
    errno_assert(rc == 0);

    /* Test whether hclose() unblocks blocked senders and receivers. */
    int ch16[2];
    rc = chmake(ch16);
    errno_assert(rc == 0);
    int hndl9[2];
    hndl9[0] = go(receiver3(ch16[0]));
    errno_assert(hndl9[0] >= 0);
    hndl9[1] = go(receiver3(ch16[0]));
    errno_assert(hndl9[1] >= 0);
    rc = msleep(now() + 50);
    errno_assert(rc == 0);
    rc = hclose(ch16[1]);
    errno_assert(rc == 0);
    rc = hclose(ch16[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl9[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl9[1]);
    errno_assert(rc == 0);

    /* Test cancelation. */
    int ch17[2];
    rc = chmake(ch17);
    errno_assert(rc == 0);
    int hndl10 = go(cancel(ch17[0]));
    errno_assert(hndl10 >= 0);
    rc = hclose(hndl10);
    errno_assert(rc == 0);
    rc = hclose(ch17[1]);
    errno_assert(rc == 0);
    rc = hclose(ch17[0]);
    errno_assert(rc == 0);

    /* Receiver waits for sender (zero-byte message). */
    int ch18[2];
    rc = chmake(ch18);
    errno_assert(rc == 0);
    int hndl11 = go(sender3(ch18[0], 1));
    errno_assert(hndl11 >= 0);
    rc = chrecv(ch18[1], NULL, 0, -1);
    errno_assert(rc == 0);
    rc = hclose(ch18[1]);
    errno_assert(rc == 0);
    rc = hclose(ch18[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl11);
    errno_assert(rc == 0);

    /* Sender waits for receiver (zero-byte message). */
    int ch19[2];
    rc = chmake(ch19);
    errno_assert(rc == 0);
    int hndl12 = go(sender3(ch19[0], 0));
    errno_assert(hndl12 >= 0);
    rc = chrecv(ch19[1], NULL, 0, -1);
    errno_assert(rc == 0);
    rc = hclose(ch19[1]);
    errno_assert(rc == 0);
    rc = hclose(ch19[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl12);
    errno_assert(rc == 0);

    /* Channel with user-supplied storage. */
    struct chstorage mem;
    int ch20[2];
    rc = chmake_mem(&mem, ch20);
    errno_assert(rc == 0);
    rc = chrecv(ch20[0], NULL, 0, now() + 50);
    errno_assert(rc == -1 && errno == ETIMEDOUT);
    rc = hclose(ch20[1]);
    errno_assert(rc == 0);
    rc = hclose(ch20[0]);
    errno_assert(rc == 0);

    return 0;
}
Beispiel #12
0
static coroutine void nagle_sender(int s, size_t batch, int64_t interval,
      uint8_t *buf, int sendch, int ackch) {
    /* Amount of data in the buffer. */
    size_t len = 0;
    /* Last time at least one byte was sent. */
    int64_t last = now();
    while(1) {
        /* Get data to send from the user coroutine. */
        struct nagle_vec vec;
        int rc = chrecv(sendch, &vec, sizeof(vec),
            interval >= 0 && len ? last + interval : -1);
        if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
        /* Timeout expired. Flush the data in the buffer. */
        if(dsock_slow(rc < 0 && errno == ETIMEDOUT)) {
            rc = bsend(s, buf, len, -1);
            if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
            dsock_assert(rc == 0);
            len = 0;
            last = now();
            continue;
        }
        dsock_assert(rc == 0);
        /* If data fit into the buffer, store them there. */
        size_t bytes = iov_size(vec.iov, vec.iovlen);
        if(len + bytes < batch) {
            iov_copyallfrom(buf + len, vec.iov, vec.iovlen);
            len += bytes;
            int err = 0;
            rc = chsend(ackch, &err, sizeof(err), -1);
            if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
            dsock_assert(rc == 0);
            continue;
        }
        if(len > 0) {
            /* Flush the buffer. */
            rc = bsend(s, buf, len, -1);
            if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
            /* Pass the error to the user. */
            if(dsock_slow(rc < 0)) {
                int err = errno;
                rc = chsend(ackch, &err, sizeof(err), -1);
                if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
                dsock_assert(rc == 0);
                return;
            }
            len = 0;
            last = now();
        }
        /* Once again: If data fit into buffer store them there. */
        if(bytes < batch) {
            iov_copyallfrom(buf, vec.iov, vec.iovlen);
            len = bytes;
            int err = 0;
            rc = chsend(ackch, &err, sizeof(err), -1);
            if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
            dsock_assert(rc == 0);
            continue;
        }
        /* This is a big chunk of data, no need to Nagle it.
           We'll send it straight away. */
        rc = bsendv(s, vec.iov, vec.iovlen, -1);
        if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
        dsock_assert(rc == 0);
        last = now();
        int err = 0;
        rc = chsend(ackch, &err, sizeof(err), -1);
        if(dsock_slow(rc < 0 && errno == ECANCELED)) return;
        dsock_assert(rc == 0);
    }
}
Beispiel #13
0
coroutine static void delay(int n, int ch) {
    int rc = msleep(now() + n);
    errno_assert(rc == 0);
    rc = chsend(ch, &n, sizeof(n), -1);
    errno_assert(rc == 0);
}
Beispiel #14
0
coroutine void sender2(int ch) {
    int val = 0;
    int rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == EPIPE);
}
Beispiel #15
0
coroutine void structsender(int ch, struct foo val) {
    int rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #16
0
coroutine void charsender(int ch, char val) {
    int rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #17
0
coroutine void sender1(int ch, int val) {
    int rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #18
0
coroutine void sender3(int ch, int val, int64_t deadline) {
    int rc = msleep(deadline);
    errno_assert(rc == 0);
    rc = chsend(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
}
Beispiel #19
0
coroutine void sender4(int ch) {
    struct large large = {{0}};
    int rc = chsend(ch, &large, sizeof(large), -1);
    errno_assert(rc == 0);
}