Skip to content

Commit

Permalink
hdone() for bundles implemented
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Sustrik <[email protected]>
  • Loading branch information
sustrik committed Feb 4, 2018
1 parent 2694b0b commit 2716640
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 8 deletions.
30 changes: 29 additions & 1 deletion cr.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,13 @@ struct dill_bundle {
struct hvfs vfs;
/* List of coroutines in this bundle. */
struct dill_list crs;
/* If somebody is doing hdone() on this bundle, here's the clause
to trigger when all coroutines are finished. */
struct dill_clause *waiter;
/* If true, the bundle was created by bundle_mem. */
unsigned int mem : 1;
/* If true, hdone() was already called on this bundle. */
unsigned int done : 1;
};

DILL_CT_ASSERT(BUNDLE_SIZE >= sizeof(struct dill_bundle));
Expand All @@ -93,7 +98,9 @@ int bundle_mem(void *mem) {
b->vfs.close = dill_bundle_close;
b->vfs.done = dill_bundle_done;
dill_list_init(&b->crs);
b->waiter = NULL;
b->mem = 1;
b->done = 0;
return hmake(&b->vfs);
}

Expand Down Expand Up @@ -129,7 +136,21 @@ static void dill_bundle_close(struct hvfs *vfs) {
}

static int dill_bundle_done(struct hvfs *vfs, int64_t deadline) {
dill_assert(0);
struct dill_bundle *self = (struct dill_bundle*)vfs;
if(self->done) {errno = EPIPE; return -1;}
self->done = 1;
if(!dill_list_empty(&self->crs)) {
struct dill_clause cl;
self->waiter = &cl;
dill_waitfor(&cl, 0, NULL);
struct dill_tmclause tmcl;
dill_timer(&tmcl, 1, deadline);
int id = dill_wait();
if(dill_slow(id < 0)) return -1;
if(dill_slow(id == 1)) {errno = ETIMEDOUT; return -1;}
dill_assert(id == 0);
}
return 0;
}

/******************************************************************************/
Expand Down Expand Up @@ -337,6 +358,13 @@ void dill_epilogue(void) {
/* Deallocate the coroutine, unless, of course, it is already
in the process of being closed. */
if(!ctx->r->no_blocking1) {
/* If this is the last coroutine in the bundle and there's someone
waiting for hdone() on the bundle unblock them. */
if(dill_list_oneitem(&ctx->r->bundle)) {
struct dill_bundle *b = dill_cont(ctx->r->bundle.next,
struct dill_bundle, crs);
if(b->waiter) dill_trigger(b->waiter, 0);
}
dill_list_erase(&ctx->r->bundle);
dill_cr_close(&ctx->r->vfs);
}
Expand Down
4 changes: 2 additions & 2 deletions libdill.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ DILL_EXPORT int hdone(int h, int64_t deadline);
/******************************************************************************/

#if defined(__i386__)
# define BUNDLE_SIZE 28
# define BUNDLE_SIZE 32
#else
# define BUNDLE_SIZE 56
# define BUNDLE_SIZE 64
#endif

DILL_EXPORT int bundle(void);
Expand Down
7 changes: 6 additions & 1 deletion list.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,16 @@ static inline void dill_list_init(struct dill_list *self) {
self->prev = self;
}

/* True if the list has no items. */
/* True if the list has no items except for the head. */
static inline int dill_list_empty(struct dill_list *self) {
return self->next == self;
}

/* True if the list has only one item in addition to the head. */
static inline int dill_list_oneitem(struct dill_list *self) {
return self->next != self && self->next == self->prev;
}

/* Returns an iterator to one past the item pointed to by 'it'. If 'it' is the
list itself it returns the first item of the list. At the end of
the list, it returns the list itself. */
Expand Down
50 changes: 46 additions & 4 deletions tests/bundle.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ coroutine void worker2(void) {
assert(rc == -1 && errno == ECANCELED);
}

coroutine void worker3(void) {
int rc = msleep(now() + 50);
coroutine void worker3(int delay) {
int rc = msleep(now() + delay);
assert(rc == 0);
}

Expand Down Expand Up @@ -71,9 +71,9 @@ int main(void) {

int hndl5 = bundle();
errno_assert(hndl5 >= 0);
rc = bundle_go(hndl5, worker3());
rc = bundle_go(hndl5, worker3(50));
errno_assert(rc == 0);
rc = bundle_go(hndl5, worker3());
rc = bundle_go(hndl5, worker3(50));
errno_assert(rc == 0);
rc = msleep(now() + 100);
errno_assert(rc == 0);
Expand Down Expand Up @@ -109,5 +109,47 @@ int main(void) {
rc = hclose(hndl8);
errno_assert(rc == 0);

/* Test hdone() on empty bundle. */
int hndl9 = bundle();
errno_assert(hndl9 >= 0);
rc = hdone(hndl9, -1);
errno_assert(rc == 0);
rc = hclose(hndl9);
errno_assert(rc == 0);

/* Test hdone() on bundle with one coroutine. */
int hndl10 = go(worker3(50));
errno_assert(hndl10 >= 0);
rc = hdone(hndl10, -1);
errno_assert(rc == 0);
rc = hclose(hndl10);
errno_assert(rc == 0);

/* Test hdone() on bundle with two coroutines. */
int hndl11 = bundle();
errno_assert(hndl11 >= 0);
rc = bundle_go(hndl11, worker3(50));
errno_assert(rc == 0);
rc = bundle_go(hndl11, worker3(100));
errno_assert(rc == 0);
rc = hdone(hndl11, -1);
errno_assert(rc == 0);
rc = hclose(hndl11);
errno_assert(rc == 0);

/* Test hdone() on bundle with timout. */
int hndl12 = go(worker3(50));
errno_assert(hndl12 >= 0);
rc = hdone(hndl12, now() + 1000);
errno_assert(rc == 0);
rc = hclose(hndl12);
errno_assert(rc == 0);
int hndl13 = go(worker2());
errno_assert(hndl13 >= 0);
rc = hdone(hndl13, now() + 50);
errno_assert(rc == -1 && errno == ETIMEDOUT);
rc = hclose(hndl13);
errno_assert(rc == 0);

return 0;
}

0 comments on commit 2716640

Please sign in to comment.