コード例 #1
0
ファイル: chan.c プロジェクト: jimjag/libdill
coroutine void cancel(int ch) {
    int val;
    int rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == ECANCELED);
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == -1 && errno == ECANCELED);
}
コード例 #2
0
ファイル: step6.c プロジェクト: jimjag/libdill
coroutine void statistics(int ch) {
    int active = 0;
    int succeeded = 0;
    int failed = 0;
    
    while(1) {
        int op;
        int rc = chrecv(ch, &op, sizeof(op), -1);
        if(rc < 0 && errno == ECANCELED) return;
        assert(rc == 0);

        switch(op) {
        case CONN_ESTABLISHED:
            ++active;
            break;
        case CONN_SUCCEEDED:
            --active;
            ++succeeded;
            break;
        case CONN_FAILED:
            --active;
            ++failed;
            break;
        }

        printf("active: %-5d  succeeded: %-5d  failed: %-5d\n",
            active, succeeded, failed);
    }
}
コード例 #3
0
ファイル: chan.c プロジェクト: jimjag/libdill
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);
}
コード例 #4
0
ファイル: choose.c プロジェクト: raedwulf/libdill
coroutine void receiver2(int ch, int expected) {
    int rc = yield();
    errno_assert(rc == 0);
    int val;
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == expected);
}
コード例 #5
0
ファイル: sleep.c プロジェクト: raedwulf/libdill
int main() {
    /* Test 'msleep'. */
    int64_t deadline = now() + 100;
    int rc = msleep(deadline);
    errno_assert(rc == 0);
    int64_t diff = now () - deadline;
    time_assert(diff, 0);

    /* msleep-sort */
    int ch = chmake(sizeof(int));
    errno_assert(ch >= 0);
    int hndls[4];
    hndls[0] = go(delay(30, ch));
    errno_assert(hndls[0] >= 0);
    hndls[1] = go(delay(40, ch));
    errno_assert(hndls[1] >= 0);
    hndls[2] = go(delay(10, ch));
    errno_assert(hndls[2] >= 0);
    hndls[3] = go(delay(20, ch));
    errno_assert(hndls[3] >= 0);
    int val;
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 10);
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 20);
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 30);
    rc = chrecv(ch, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    assert(val == 40);
    rc = hclose(hndls[0]);
    errno_assert(rc == 0);
    rc = hclose(hndls[1]);
    errno_assert(rc == 0);
    rc = hclose(hndls[2]);
    errno_assert(rc == 0);
    rc = hclose(hndls[3]);
    errno_assert(rc == 0);
    rc = hclose(ch);
    errno_assert(rc == 0);

    return 0;
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: nagle.c プロジェクト: raedwulf/dillsocks
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;
}
コード例 #8
0
static int sf_recv(int s, void *buf, size_t *len, int64_t deadline) {
    if(dill_slow(!len)) {errno = EINVAL; return -1;}
    struct sf *conn = msockdata(s, sf_type);
    if(dill_slow(!conn)) return -1;
    if(dill_slow(conn->res != SF_ACTIVE)) {errno = ECONNRESET; return -1;}
    /* Get message from the worker. */
    struct msg msg;
    int rc = chrecv(conn->ichan, &msg, sizeof(msg), deadline);
    /* Worker signals disconnection by closing the pipe. */
    if(dill_slow(rc < 0 && errno == EPIPE)) {
        if(conn->res != SF_RESET)
            conn->res = conn->ires;
        errno = ECONNRESET;
        return -1;
    }
    if(dill_slow(rc < 0)) return -1;
    /* Fill in user's buffer. */
    size_t tocopy = *len < msg.len ? *len : msg.len;
    memcpy(buf, msg.buf, tocopy);
    *len = msg.len;
    free(msg.buf);
    return 0;
}
コード例 #9
0
static coroutine void sf_oworker(struct sf *conn) {
    struct msg msg = {NULL, 0};
    while(1) {
        int rc = chrecv(conn->ochan, &msg, sizeof(msg), -1);
        if(dill_slow(rc < 0 && errno == ECANCELED)) break;
        dill_assert(rc == 0);
        /* User requests that the coroutine stops. */
        if(!msg.buf) {conn->ores = SF_DONE; break;}
        uint64_t hdr;
        dill_putll((uint8_t*)&hdr, msg.len);
        rc = bsend(conn->u, &hdr, sizeof(hdr), -1);
        CHECKRC(ores)
        rc = bsend(conn->u, msg.buf, msg.len, -1);
        CHECKRC(ores)
        free(msg.buf);
        msg.buf = NULL;
        msg.len = 0;
        rc = bflush(conn->u, -1);
        CHECKRC(ores)
    }
    free(msg.buf);
    int rc = chdone(conn->ochan);
    dill_assert(rc == 0);
}
コード例 #10
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;
}
コード例 #11
0
ファイル: chan.c プロジェクト: jimjag/libdill
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;
}
コード例 #12
0
ファイル: choose.c プロジェクト: raedwulf/libdill
int main() {
    int rc;
    int val;

    /* Non-blocking receiver case. */
    int ch1 = chmake(sizeof(int));
    errno_assert(ch1 >= 0);
    int hndl1 = go(sender1(ch1, 555));
    errno_assert(hndl1 >= 0);
    struct chclause cls1[] = {{CHRECV, ch1, &val, sizeof(val)}};
    rc = choose(cls1, 1, -1);
    choose_assert(0, 0);
    assert(val == 555);
    hclose(ch1);
    rc = hclose(hndl1);
    errno_assert(rc == 0);

    /* Blocking receiver case. */
    int ch2 = chmake(sizeof(int));
    errno_assert(ch2 >= 0);
    int hndl2 = go(sender2(ch2, 666));
    errno_assert(hndl2 >= 0);
    struct chclause cls2[] = {{CHRECV, ch2, &val, sizeof(val)}};
    rc = choose(cls2, 1, -1);
    choose_assert(0, 0);
    assert(val == 666);
    hclose(ch2);
    rc = hclose(hndl2);
    errno_assert(rc == 0);

    /* Non-blocking sender case. */
    int ch3 = chmake(sizeof(int));
    errno_assert(ch3 >= 0);
    int hndl3 = go(receiver1(ch3, 777));
    errno_assert(hndl3 >= 0);
    val = 777;
    struct chclause cls3[] = {{CHSEND, ch3, &val, sizeof(val)}};
    rc = choose(cls3, 1, -1);
    choose_assert(0, 0);
    hclose(ch3);
    rc = hclose(hndl3);
    errno_assert(rc == 0);

    /* Blocking sender case. */
    int ch4 = chmake(sizeof(int));
    errno_assert(ch4 >= 0);
    int hndl4 = go(receiver2(ch4, 888));
    errno_assert(hndl4 >= 0);
    val = 888;
    struct chclause cls4[] = {{CHSEND, ch4, &val, sizeof(val)}};
    rc = choose(cls4, 1, -1);
    choose_assert(0, 0);
    hclose(ch4);
    rc = hclose(hndl4);
    errno_assert(rc == 0);

    /* Check with two channels. */
    int hndl5[2];
    int ch5 = chmake(sizeof(int));
    errno_assert(ch5 >= 0);
    int ch6 = chmake(sizeof(int));
    errno_assert(ch6 >= 0);
    hndl5[0] = go(sender1(ch6, 555));
    errno_assert(hndl5 >= 0);
    struct chclause cls5[] = {
        {CHRECV, ch5, &val, sizeof(val)},
        {CHRECV, ch6, &val, sizeof(val)}
    };
    rc = choose(cls5, 2, -1);
    choose_assert(1, 0);
    assert(val == 555);
    hndl5[1] = go(sender2(ch5, 666));
    errno_assert(hndl5 >= 0);
    rc = choose(cls5, 2, -1);
    choose_assert(0, 0);
    assert(val == 666);
    hclose(ch5);
    hclose(ch6);
    rc = hclose(hndl5[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl5[1]);
    errno_assert(rc == 0);

    /* Test whether selection of in channels is random. */
    int ch7 = chmake(sizeof(int));
    errno_assert(ch7 >= 0);
    int ch8 = chmake(sizeof(int));
    errno_assert(ch8 >= 0);
    int hndl6[2];
    hndl6[0] = go(feeder(ch7, 111));
    errno_assert(hndl6[0] >= 0);
    hndl6[1] = go(feeder(ch8, 222));
    errno_assert(hndl6[1] >= 0);
    int i;
    int first = 0;
    int second = 0;
    int third = 0;
    for(i = 0; i != 100; ++i) {
        struct chclause cls6[] = {
            {CHRECV, ch7, &val, sizeof(val)},
            {CHRECV, ch8, &val, sizeof(val)}
        };
        rc = choose(cls6, 2, -1);
        errno_assert(rc == 0 || rc == 1);
        if(rc == 0) {
            assert(val == 111);
            ++first;
        }
        if(rc == 1) {
            assert(val == 222);
            ++second;
        }
        int rc = yield();
        errno_assert(rc == 0);
    }
    assert(first > 1 && second > 1);
    hclose(hndl6[0]);
    hclose(hndl6[1]);
    hclose(ch7);
    hclose(ch8);

    /* Test 'otherwise' clause. */
    int ch9 = chmake(sizeof(int));
    errno_assert(ch9 >= 0);
    struct chclause cls7[] = {{CHRECV, ch9, &val, sizeof(val)}};
    rc = choose(cls7, 1, 0);
    choose_assert(-1, ETIMEDOUT);
    hclose(ch9);
    rc = choose(NULL, 0, 0);
    choose_assert(-1, ETIMEDOUT);

    /* Test two simultaneous senders vs. choose statement. */
    int ch10 = chmake(sizeof(int));
    errno_assert(ch10 >= 0);
    int hndl7[2];
    hndl7[0] = go(sender1(ch10, 888));
    errno_assert(hndl7[0] >= 0);
    hndl7[1] = go(sender1(ch10, 999));
    errno_assert(hndl7[1] >= 0);
    val = 0;
    struct chclause cls8[] = {{CHRECV, ch10, &val, sizeof(val)}};
    rc = choose(cls8, 1, -1);
    choose_assert(0, 0);
    assert(val == 888);
    val = 0;
    rc = choose(cls8, 1, -1);
    choose_assert(0, 0);
    assert(val == 999);
    hclose(ch10);
    rc = hclose(hndl7[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl7[1]);
    errno_assert(rc == 0);

    /* Test two simultaneous receivers vs. choose statement. */
    int ch11 = chmake(sizeof(int));
    errno_assert(ch11 >= 0);
    int hndl8[2];
    hndl8[0] = go(receiver1(ch11, 333));
    errno_assert(hndl8[0] >= 0);
    hndl8[1] = go(receiver1(ch11, 444));
    errno_assert(hndl8[1] >= 0);
    val = 333;
    struct chclause cls9[] = {{CHSEND, ch11, &val, sizeof(val)}};
    rc = choose(cls9, 1, -1);
    choose_assert(0, 0);
    val = 444;
    rc = choose(cls9, 1, -1);
    choose_assert(0, 0);
    hclose(ch11);
    rc = hclose(hndl8[0]);
    errno_assert(rc == 0);
    rc = hclose(hndl8[1]);
    errno_assert(rc == 0);

    /* Choose vs. choose. */
    int ch12 = chmake(sizeof(int));
    errno_assert(ch12 >= 0);
    int hndl9 = go(choosesender(ch12, 111));
    errno_assert(hndl9 >= 0);
    struct chclause cls10[] = {{CHRECV, ch12, &val, sizeof(val)}};
    rc = choose(cls10, 1, -1);
    choose_assert(0, 0);
    assert(val == 111);
    hclose(ch12);
    rc = hclose(hndl9);
    errno_assert(rc == 0);

    /* Test transferring a large object. */
    int ch17 = chmake(sizeof(struct large));
    errno_assert(ch17 >= 0);
    int hndl10 = go(sender4(ch17));
    errno_assert(hndl9 >= 0);
    struct large lrg;
    struct chclause cls14[] = {{CHRECV, ch17, &lrg, sizeof(lrg)}};
    rc = choose(cls14, 1, -1);
    choose_assert(0, 0);
    hclose(ch17);

    /* Test that 'in' on done-with channel fires. */
    int ch18 = chmake(sizeof(int));
    errno_assert(ch18 >= 0);
    rc = hdone(ch18);
    errno_assert(rc == 0);
    struct chclause cls15[] = {{CHRECV, ch18, &val, sizeof(val)}};
    rc = choose(cls15, 1, -1);
    choose_assert(0, EPIPE);
    hclose(ch18);

    /* Test expiration of 'deadline' clause. */
    int ch21 = chmake(sizeof(int));
    errno_assert(ch21 >= 0);
    int64_t start = now();
    struct chclause cls17[] = {{CHRECV, ch21, &val, sizeof(val)}};
    rc = choose(cls17, 1, start + 50);
    choose_assert(-1, ETIMEDOUT);
    int64_t diff = now() - start;
    time_assert(diff, 50);
    hclose(ch21);

    /* Test unexpired 'deadline' clause. */
    int ch22 = chmake(sizeof(int));
    errno_assert(ch22 >= 0);
    start = now();
    int hndl11 = go(sender3(ch22, 4444, start + 50));
    errno_assert(hndl11 >= 0);
    struct chclause cls18[] = {{CHRECV, ch22, &val, sizeof(val)}};
    rc = choose(cls17, 1, start + 1000);
    choose_assert(0, 0);
    assert(val == 4444);
    diff = now() - start;
    time_assert(diff, 50);
    hclose(ch22);
    rc = hclose(hndl11);
    errno_assert(rc == 0);

    /* Test that first channel in the array is prioritized. */
    int ch23 = chmake(sizeof(int));
    errno_assert(ch23 >= 0);
    int ch24 = chmake(sizeof(int));
    errno_assert(ch24 >= 0);
    int hndl12 = go(sender1(ch23, 0));
    errno_assert(hndl12 >= 0);
    int hndl13 = go(sender1(ch24, 0));
    errno_assert(hndl13 >= 0);
    struct chclause cls19[] = {
        {CHRECV, ch24, &val, sizeof(val)},
        {CHRECV, ch23, &val, sizeof(val)}
    };
    rc = choose(cls19, 2, -1);
    choose_assert(0, 0);
    rc = chrecv(ch23, &val, sizeof(val), -1);
    errno_assert(rc == 0);
    rc = hclose(hndl13);
    errno_assert(rc == 0);
    rc = hclose(hndl12);
    errno_assert(rc == 0);
    rc = hclose(ch24);
    errno_assert(rc == 0);
    rc = hclose(ch23);
    errno_assert(rc == 0);

    /* Try adding the same channel to choose twice. Doing so is pointless,
       but it shouldn't crash the application. */
    int ch25 = chmake(sizeof(int));
    errno_assert(ch25 >= 0);
    struct chclause cls20[] = {
        {CHRECV, ch25, &val, sizeof(val)},
        {CHRECV, ch25, &val, sizeof(val)}
    };
    rc = choose(cls20, 2, now() + 50);
    choose_assert(-1, ETIMEDOUT);
    rc = hclose(ch25);
    errno_assert(rc == 0);

    return 0;
}
コード例 #13
0
ファイル: nagle.c プロジェクト: raedwulf/dillsocks
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);
    }
}