Skip to content

Commit 101bb31

Browse files
yinamydhil
andauthored
Add switch to fiber interface, support fiber_switch in asyncify implementation (#15)
* Created hello_switch.c (hello_.c but using fiber_switch) Created asyncify_switch_implc.c with new fiber_switch function (but it doesn't work yet!) * Revert "Created hello_switch.c (hello_.c but using fiber_switch)" This reverts commit a1f8811. * Reapply "Created hello_switch.c (hello_.c but using fiber_switch)" (that was a huge mistake!) This reverts commit 542f29c. * Updated hello_switch.c to working version * Implemented fiber-switch interface with asyncify, it works with hello_switch.c * Apply suggestions from code review Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Renamed fiber-switch.h to fiber_switch.h * Created `fiber_main` in `asyncify_switch_impl.c` as per Daniel's suggestion, updated the hello world test program accordingly * Removed fiber-switch.h * Update inc/fiber_switch.h Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Changed get_active_fiber() to get_main_fiber(), added a check to fiber_main() to make it work after Daniel's changes * Added/implemented a function `fiber_return_switch` to interface, which switches to a target fiber and destroys the existing one. Added test file racecar.c for `fiber_return_switch`. * Changed `fiber_entry_point_t` to take one more argument Removed `get_main_fiber` function from `fiber_switch.h` Updated test files `hello_switch` and `racecar` to make them work again * Added itersum_switch.c * Added treesum_switch.c * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update src/asyncify/asyncify_switch_impl.c Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> * Update inc/fiber_switch.h Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com> --------- Co-authored-by: Daniel Hillerström <1827113+dhil@users.noreply.github.com>
1 parent 4c014da commit 101bb31

File tree

7 files changed

+709
-1
lines changed

7 files changed

+709
-1
lines changed

Makefile

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,23 @@ endif
2020
all: hello sieve itersum treesum
2121

2222
.PHONY: hello
23-
hello: hello_asyncify.wasm hello_wasmfx.wasm
23+
hello: hello_asyncify.wasm hello_asyncify_switch.wasm racecar.wasm hello_wasmfx.wasm
2424

2525
hello_asyncify.wasm: inc/fiber.h src/asyncify/asyncify_impl.c examples/hello.c
2626
$(WASICC) -DSTACK_POOL_SIZE=$(STACK_POOL_SIZE) -DASYNCIFY_DEFAULT_STACK_SIZE=$(ASYNCIFY_DEFAULT_STACK_SIZE) src/asyncify/asyncify_impl.c $(WASIFLAGS) examples/hello.c -o hello_asyncfiy.pre.wasm
2727
$(ASYNCIFY) hello_asyncfiy.pre.wasm -o hello_asyncify.wasm
2828
chmod +x hello_asyncify.wasm
2929

30+
hello_asyncify_switch.wasm: inc/fiber_switch.h src/asyncify/asyncify_switch_impl.c examples/hello_switch.c
31+
$(WASICC) -DSTACK_POOL_SIZE=$(STACK_POOL_SIZE) -DASYNCIFY_DEFAULT_STACK_SIZE=$(ASYNCIFY_DEFAULT_STACK_SIZE) src/asyncify/asyncify_switch_impl.c $(WASIFLAGS) examples/hello_switch.c -o hello_asyncfiy_switch.pre.wasm
32+
$(ASYNCIFY) hello_asyncfiy_switch.pre.wasm -o hello_asyncify_switch.wasm
33+
chmod +x hello_asyncify_switch.wasm
34+
35+
racecar.wasm: inc/fiber_switch.h src/asyncify/asyncify_switch_impl.c examples/racecar.c
36+
$(WASICC) -DSTACK_POOL_SIZE=$(STACK_POOL_SIZE) -DASYNCIFY_DEFAULT_STACK_SIZE=$(ASYNCIFY_DEFAULT_STACK_SIZE) src/asyncify/asyncify_switch_impl.c $(WASIFLAGS) examples/racecar.c -o racecar.pre.wasm
37+
$(ASYNCIFY) racecar.pre.wasm -o racecar.wasm
38+
chmod +x racecar.wasm
39+
3040
hello_wasmfx.wasm: inc/fiber.h src/wasmfx/imports.wat src/wasmfx/wasmfx_impl.c examples/hello.c
3141
$(WASICC) $(SHADOW_STACK_FLAG) -DWASMFX_CONT_SHADOW_STACK_SIZE=$(WASMFX_CONT_SHADOW_STACK_SIZE) -DWASMFX_CONT_TABLE_INITIAL_CAPACITY=$(WASMFX_CONT_TABLE_INITIAL_CAPACITY) -Wl,--export-table,--export-memory,--export=__stack_pointer src/wasmfx/wasmfx_impl.c $(WASIFLAGS) examples/hello.c -o hello_wasmfx.pre.wasm
3242
$(WASM_INTERP) -d -i src/wasmfx/imports.wat -o fiber_wasmfx_imports.wasm

examples/hello_switch.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Cooperative printing of "hello world"
2+
#include <assert.h>
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <fiber_switch.h>
9+
10+
static fiber_t hello_fiber;
11+
static fiber_t world_fiber;
12+
13+
static bool hello_done;
14+
static bool world_done;
15+
16+
17+
void* hello(void *arg, fiber_t main_fiber) {
18+
uint32_t i = (uint32_t)(uintptr_t)arg;
19+
20+
static const char s[] = "hlowrd";
21+
22+
do {
23+
putc(s[i], stdout);
24+
i = (uint32_t)(uintptr_t)fiber_switch(world_fiber, (void*)(uintptr_t)i, &hello_fiber);
25+
} while (!world_done && world_fiber != NULL);
26+
27+
hello_done = true;
28+
fiber_return_switch(main_fiber, (void*)(uintptr_t)i);
29+
return NULL;
30+
}
31+
32+
void* world(void *arg, fiber_t __attribute__((unused))main_fiber) {
33+
uint32_t i = (uint32_t)(uintptr_t)arg;
34+
static const char s[] = "el ol";
35+
36+
do {
37+
putc(s[i], stdout);
38+
i++;
39+
i = (uint32_t)(uintptr_t)fiber_switch(hello_fiber, (void*)(uintptr_t)i, &world_fiber);
40+
} while (i < strlen(s));
41+
42+
world_done = true;
43+
fiber_switch(hello_fiber, (void*)(uintptr_t)i, &world_fiber);
44+
return NULL;
45+
}
46+
47+
void *prog(void * __attribute__((unused))result, fiber_t dummy) {
48+
49+
hello_fiber = fiber_alloc((fiber_entry_point_t)hello);
50+
world_fiber = fiber_alloc((fiber_entry_point_t)world);
51+
52+
hello_done = false;
53+
world_done = false;
54+
55+
uint32_t i = 0;
56+
57+
// Initial switch must be from *some* fiber, so we use dummy.
58+
(void)fiber_switch(hello_fiber, (void*)(uintptr_t)i, &dummy);
59+
60+
putc('\n', stdout);
61+
fflush(stdout);
62+
63+
fiber_free(hello_fiber);
64+
fiber_free(world_fiber);
65+
66+
return NULL;
67+
}
68+
69+
int main(int __attribute__((unused)) argc, char * __attribute__((unused))argv[]) {
70+
71+
void *result = fiber_main(prog, NULL);
72+
73+
return (int)(intptr_t)result;
74+
}

examples/itersum_switch.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Iterative sum; an iterative variation of `treesum.c`
2+
// Now using `switch`!
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
#include <stdio.h>
6+
#include <fiber_switch.h>
7+
8+
static fiber_t run_fiber;
9+
static fiber_t sum_fiber;
10+
11+
static int argc_global;
12+
static char** argv_global;
13+
14+
15+
void* sum(void *arg, fiber_t __attribute__((unused))main_fiber) {
16+
int32_t max = (int32_t)(intptr_t)arg;
17+
for (int32_t i = 0; i < max; i++) {
18+
fiber_switch(run_fiber, (void*)(intptr_t)i, &sum_fiber);
19+
}
20+
fiber_return_switch(run_fiber, NULL);
21+
return NULL;
22+
}
23+
24+
int32_t run(int32_t max, fiber_t main_fiber) {
25+
26+
sum_fiber = fiber_alloc((fiber_entry_point_t)sum);
27+
int32_t result = 0, i = 0;
28+
29+
30+
void* val = fiber_switch(sum_fiber, (void*)(intptr_t)max, &run_fiber);
31+
32+
while (i++ < max) {
33+
result += (int32_t)(intptr_t)val;
34+
val = fiber_switch(sum_fiber, NULL, &run_fiber);
35+
}
36+
37+
fiber_free(sum_fiber);
38+
fiber_return_switch(main_fiber, (void*)(intptr_t)result);
39+
return 0;
40+
}
41+
42+
void *prog(void * __attribute__((unused))unused_result, fiber_t dummy) {
43+
44+
run_fiber = fiber_alloc((fiber_entry_point_t)run);
45+
46+
if (argc_global != 2) {
47+
fprintf(stderr, "Wrong number of arguments. Expected: 1");
48+
return 0;
49+
}
50+
51+
int i = atoi(argv_global[1]);
52+
53+
int32_t result = (int32_t)fiber_switch(run_fiber, (void*)(intptr_t)i, &dummy);
54+
55+
printf("%d\n", result);
56+
57+
fiber_free(run_fiber);
58+
59+
return 0;
60+
}
61+
62+
int main(int argc, char** argv) {
63+
64+
argc_global = argc;
65+
argv_global = argv;
66+
67+
void *result = fiber_main(prog, NULL);
68+
69+
return (int)(intptr_t)result;
70+
}

examples/racecar.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Cooperative printing of "racecar"
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <fiber_switch.h>
8+
9+
static volatile fiber_t main_fiber;
10+
static volatile fiber_t rr;
11+
static volatile fiber_t cc;
12+
static volatile fiber_t aa;
13+
static volatile fiber_t e;
14+
15+
void* rr_func(void *__attribute__((unused))arg, fiber_t main_fiber) {
16+
putc('r', stdout);
17+
fiber_switch(aa, NULL, &rr);
18+
putc('r', stdout);
19+
fiber_return_switch(main_fiber, NULL);
20+
return NULL;
21+
}
22+
23+
void* aa_func(void *__attribute__((unused))arg, fiber_t __attribute__((unused))dummy) {
24+
putc('a', stdout);
25+
fiber_switch(cc, NULL, &aa);
26+
putc('a', stdout);
27+
fiber_return_switch(rr, NULL);
28+
return NULL;
29+
}
30+
31+
void* cc_func(void *__attribute__((unused))arg, fiber_t __attribute__((unused))dummy) {
32+
putc('c', stdout);
33+
fiber_switch(e, NULL, &cc);
34+
putc('c', stdout);
35+
fiber_return_switch(aa, NULL);
36+
return NULL;
37+
}
38+
39+
void* e_func(void *__attribute__((unused))arg, fiber_t __attribute__((unused))dummy) {
40+
putc('e', stdout);
41+
fiber_return_switch(cc, NULL);
42+
return NULL;
43+
}
44+
45+
void *prog(void * __attribute__((unused))result, fiber_t __attribute__((unused))dummy) {
46+
47+
rr = fiber_alloc(rr_func);
48+
aa = fiber_alloc(aa_func);
49+
cc = fiber_alloc(cc_func);
50+
e = fiber_alloc(e_func);
51+
52+
(void)fiber_switch(rr, NULL, &main_fiber);
53+
54+
putc('\n', stdout);
55+
fflush(stdout);
56+
57+
return NULL;
58+
}
59+
60+
int main(int __attribute__((unused)) argc, char * __attribute__((unused))argv[]) {
61+
62+
void *result = fiber_main(prog, NULL);
63+
64+
return (int)(intptr_t)result;
65+
}

examples/treesum_switch.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Tree traversal; a recursive variation of `itersum.c`
2+
// Now using `switch`!
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
#include <stdbool.h>
6+
#include <stdio.h>
7+
#include <fiber_switch.h>
8+
9+
static int argc_global;
10+
static char** argv_global;
11+
12+
static fiber_t runner;
13+
static fiber_t walker;
14+
15+
static bool walk_done = false;
16+
17+
typedef struct node {
18+
enum { LEAF, FORK } tag;
19+
union {
20+
// Leaf.
21+
int32_t val;
22+
// Fork
23+
struct {
24+
struct node *left;
25+
struct node *right;
26+
};
27+
};
28+
} node_t;
29+
30+
node_t* build_tree(int32_t depth, int32_t val) {
31+
node_t *node = (node_t*)malloc(sizeof(node_t));
32+
if (depth == 0) {
33+
node->tag = LEAF;
34+
node->val = val;
35+
} else {
36+
node->tag = FORK;
37+
node_t *subtree = build_tree(depth - 1, val + 1);
38+
node->left = subtree;
39+
node->right = subtree;
40+
}
41+
return node;
42+
}
43+
44+
void free_tree(node_t *node) {
45+
enum { LEAF, FORK } tag = node->tag;
46+
if (tag == FORK) {
47+
if (node->left == node->right) {
48+
free_tree(node->left);
49+
} else {
50+
free_tree(node->left);
51+
free_tree(node->right);
52+
}
53+
}
54+
free(node);
55+
}
56+
57+
void walk_tree(node_t *node) {
58+
if (node->tag == LEAF) {
59+
fiber_switch(runner, (void*)(intptr_t)node->val, &walker);
60+
} else {
61+
walk_tree(node->left);
62+
walk_tree(node->right);
63+
}
64+
}
65+
66+
void* tree_walker(void *node, fiber_t __attribute__((unused))main_fiber) {
67+
walk_tree((node_t*)node);
68+
walk_done = true;
69+
fiber_return_switch(runner, NULL);
70+
return NULL;
71+
}
72+
73+
int32_t run(node_t* tree, fiber_t main_fiber) {
74+
int32_t sum = 0;
75+
walker = fiber_alloc((fiber_entry_point_t)tree_walker);
76+
void* val = fiber_switch(walker, (void*)tree, &runner);
77+
78+
while (!walk_done) {
79+
sum += (int32_t)(intptr_t)val;
80+
val = fiber_switch(walker, NULL, &runner);
81+
}
82+
83+
fiber_free(walker);
84+
fiber_return_switch(main_fiber, (void*)(intptr_t)sum);
85+
86+
return 0;
87+
}
88+
89+
void *prog(void * __attribute__((unused))unused_result, fiber_t dummy) {
90+
91+
if (argc_global != 2) {
92+
fprintf(stderr, "Wrong number of arguments. Expected: 1");
93+
return 0;
94+
}
95+
96+
int i = atoi(argv_global[1]);
97+
98+
node_t *tree = build_tree((int32_t)i, 0);
99+
100+
runner = fiber_alloc((fiber_entry_point_t)run);
101+
102+
int32_t result = (int32_t)fiber_switch(runner, (void*)(intptr_t)tree, &dummy);
103+
104+
fiber_free(runner);
105+
106+
free_tree(tree);
107+
108+
printf("%d\n", result);
109+
110+
return 0;
111+
}
112+
113+
int main(int argc, char** argv) {
114+
115+
argc_global = argc;
116+
argv_global = argv;
117+
118+
void *result = fiber_main(prog, NULL);
119+
120+
return (int)(intptr_t)result;
121+
}

0 commit comments

Comments
 (0)