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); }
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); } }
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); }
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); }
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; }
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 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 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; }
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); }
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; }
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; }
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; }
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); } }