Skip to content

Commit 2716640

Browse files
committed
hdone() for bundles implemented
Signed-off-by: Martin Sustrik <[email protected]>
1 parent 2694b0b commit 2716640

File tree

4 files changed

+83
-8
lines changed

4 files changed

+83
-8
lines changed

cr.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,13 @@ struct dill_bundle {
7676
struct hvfs vfs;
7777
/* List of coroutines in this bundle. */
7878
struct dill_list crs;
79+
/* If somebody is doing hdone() on this bundle, here's the clause
80+
to trigger when all coroutines are finished. */
81+
struct dill_clause *waiter;
7982
/* If true, the bundle was created by bundle_mem. */
8083
unsigned int mem : 1;
84+
/* If true, hdone() was already called on this bundle. */
85+
unsigned int done : 1;
8186
};
8287

8388
DILL_CT_ASSERT(BUNDLE_SIZE >= sizeof(struct dill_bundle));
@@ -93,7 +98,9 @@ int bundle_mem(void *mem) {
9398
b->vfs.close = dill_bundle_close;
9499
b->vfs.done = dill_bundle_done;
95100
dill_list_init(&b->crs);
101+
b->waiter = NULL;
96102
b->mem = 1;
103+
b->done = 0;
97104
return hmake(&b->vfs);
98105
}
99106

@@ -129,7 +136,21 @@ static void dill_bundle_close(struct hvfs *vfs) {
129136
}
130137

131138
static int dill_bundle_done(struct hvfs *vfs, int64_t deadline) {
132-
dill_assert(0);
139+
struct dill_bundle *self = (struct dill_bundle*)vfs;
140+
if(self->done) {errno = EPIPE; return -1;}
141+
self->done = 1;
142+
if(!dill_list_empty(&self->crs)) {
143+
struct dill_clause cl;
144+
self->waiter = &cl;
145+
dill_waitfor(&cl, 0, NULL);
146+
struct dill_tmclause tmcl;
147+
dill_timer(&tmcl, 1, deadline);
148+
int id = dill_wait();
149+
if(dill_slow(id < 0)) return -1;
150+
if(dill_slow(id == 1)) {errno = ETIMEDOUT; return -1;}
151+
dill_assert(id == 0);
152+
}
153+
return 0;
133154
}
134155

135156
/******************************************************************************/
@@ -337,6 +358,13 @@ void dill_epilogue(void) {
337358
/* Deallocate the coroutine, unless, of course, it is already
338359
in the process of being closed. */
339360
if(!ctx->r->no_blocking1) {
361+
/* If this is the last coroutine in the bundle and there's someone
362+
waiting for hdone() on the bundle unblock them. */
363+
if(dill_list_oneitem(&ctx->r->bundle)) {
364+
struct dill_bundle *b = dill_cont(ctx->r->bundle.next,
365+
struct dill_bundle, crs);
366+
if(b->waiter) dill_trigger(b->waiter, 0);
367+
}
340368
dill_list_erase(&ctx->r->bundle);
341369
dill_cr_close(&ctx->r->vfs);
342370
}

libdill.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ DILL_EXPORT int hdone(int h, int64_t deadline);
9393
/******************************************************************************/
9494

9595
#if defined(__i386__)
96-
# define BUNDLE_SIZE 28
96+
# define BUNDLE_SIZE 32
9797
#else
98-
# define BUNDLE_SIZE 56
98+
# define BUNDLE_SIZE 64
9999
#endif
100100

101101
DILL_EXPORT int bundle(void);

list.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,16 @@ static inline void dill_list_init(struct dill_list *self) {
3939
self->prev = self;
4040
}
4141

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

47+
/* True if the list has only one item in addition to the head. */
48+
static inline int dill_list_oneitem(struct dill_list *self) {
49+
return self->next != self && self->next == self->prev;
50+
}
51+
4752
/* Returns an iterator to one past the item pointed to by 'it'. If 'it' is the
4853
list itself it returns the first item of the list. At the end of
4954
the list, it returns the list itself. */

tests/bundle.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ coroutine void worker2(void) {
3333
assert(rc == -1 && errno == ECANCELED);
3434
}
3535

36-
coroutine void worker3(void) {
37-
int rc = msleep(now() + 50);
36+
coroutine void worker3(int delay) {
37+
int rc = msleep(now() + delay);
3838
assert(rc == 0);
3939
}
4040

@@ -71,9 +71,9 @@ int main(void) {
7171

7272
int hndl5 = bundle();
7373
errno_assert(hndl5 >= 0);
74-
rc = bundle_go(hndl5, worker3());
74+
rc = bundle_go(hndl5, worker3(50));
7575
errno_assert(rc == 0);
76-
rc = bundle_go(hndl5, worker3());
76+
rc = bundle_go(hndl5, worker3(50));
7777
errno_assert(rc == 0);
7878
rc = msleep(now() + 100);
7979
errno_assert(rc == 0);
@@ -109,5 +109,47 @@ int main(void) {
109109
rc = hclose(hndl8);
110110
errno_assert(rc == 0);
111111

112+
/* Test hdone() on empty bundle. */
113+
int hndl9 = bundle();
114+
errno_assert(hndl9 >= 0);
115+
rc = hdone(hndl9, -1);
116+
errno_assert(rc == 0);
117+
rc = hclose(hndl9);
118+
errno_assert(rc == 0);
119+
120+
/* Test hdone() on bundle with one coroutine. */
121+
int hndl10 = go(worker3(50));
122+
errno_assert(hndl10 >= 0);
123+
rc = hdone(hndl10, -1);
124+
errno_assert(rc == 0);
125+
rc = hclose(hndl10);
126+
errno_assert(rc == 0);
127+
128+
/* Test hdone() on bundle with two coroutines. */
129+
int hndl11 = bundle();
130+
errno_assert(hndl11 >= 0);
131+
rc = bundle_go(hndl11, worker3(50));
132+
errno_assert(rc == 0);
133+
rc = bundle_go(hndl11, worker3(100));
134+
errno_assert(rc == 0);
135+
rc = hdone(hndl11, -1);
136+
errno_assert(rc == 0);
137+
rc = hclose(hndl11);
138+
errno_assert(rc == 0);
139+
140+
/* Test hdone() on bundle with timout. */
141+
int hndl12 = go(worker3(50));
142+
errno_assert(hndl12 >= 0);
143+
rc = hdone(hndl12, now() + 1000);
144+
errno_assert(rc == 0);
145+
rc = hclose(hndl12);
146+
errno_assert(rc == 0);
147+
int hndl13 = go(worker2());
148+
errno_assert(hndl13 >= 0);
149+
rc = hdone(hndl13, now() + 50);
150+
errno_assert(rc == -1 && errno == ETIMEDOUT);
151+
rc = hclose(hndl13);
152+
errno_assert(rc == 0);
153+
112154
return 0;
113155
}

0 commit comments

Comments
 (0)