forked from edubart/minicoro
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmt-example.c
More file actions
154 lines (131 loc) · 3.74 KB
/
mt-example.c
File metadata and controls
154 lines (131 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#define MINICORO_IMPL
#include "minicoro.h"
#define C89THREAD_IMPLEMENTATION
#include "thirdparty/c89thread.h"
#include <stdio.h>
#define NUM_THREADS 4
#define NUM_TASKS 100
#define NUM_ITERATIONS 500
#define EXPECTED_RESULT 2396583362
static c89mtx_t mutex;
static c89thrd_t threads[NUM_THREADS];
static mco_coro* tasks[NUM_TASKS];
static void fail_mco(const char* message, mco_result res) {
printf("%s: %s\n", message, mco_result_description(res));
exit(-1);
}
static void fail(const char* message) {
printf("%s\n", message);
exit(-1);
}
static void fibonacci_task(mco_coro* co) {
unsigned int m = 1;
unsigned int n = 1;
for(unsigned int i=0;i<NUM_ITERATIONS;++i) {
/* Yield the next Fibonacci number. */
mco_result res = mco_yield(co);
if(res != MCO_SUCCESS)
fail_mco("Failed to yield coroutine", res);
unsigned int tmp = m + n;
m = n;
n = tmp;
}
/* Yield the last Fibonacci number. */
mco_push(co, &m, sizeof(m));
}
static mco_coro* create_fibonacci_task() {
/* Create the coroutine. */
mco_coro* co;
mco_desc desc = mco_desc_init(fibonacci_task, 0);
mco_result res = mco_create(&co, &desc);
if(res != MCO_SUCCESS)
fail_mco("Failed to create coroutine", res);
/* Return the task as a coroutine. */
return co;
}
int thread_worker(void* data) {
(void)data;
while(1) {
mco_coro* task = NULL;
int task_id = 0;
if(c89mtx_lock(&mutex) != c89thrd_success)
fail("Unable to lock mutex");
for(int i=0;i<NUM_TASKS;++i) {
if(tasks[i] != NULL) {
task = tasks[i];
tasks[i] = NULL;
task_id = i;
break;
}
}
if(c89mtx_unlock(&mutex) != c89thrd_success)
fail("Unable to unlock mutex");
if(!task) {
/* All tasks finished. */
return 0;
}
mco_result res = mco_resume(task);
if(res != MCO_SUCCESS)
fail_mco("Failed to yield coroutine", res);
switch(mco_status(task)) {
case MCO_SUSPENDED: { /* Task is not finished yet. */
/* Add it back to task list. */
if(c89mtx_lock(&mutex) != c89thrd_success)
fail("Unable to lock mutex");
tasks[task_id] = task;
if(c89mtx_unlock(&mutex) != c89thrd_success)
fail("Unable to unlock mutex");
break;
}
case MCO_DEAD: { /* Task finished. */
/* Retrieve storage set in last coroutine yield. */
unsigned int ret = 0;
res = mco_pop(task, &ret, sizeof(ret));
if(res != MCO_SUCCESS)
fail_mco("Failed to retrieve coroutine storage", res);
/* Check task result. */
if(ret != EXPECTED_RESULT) {
printf("Unexpected result %u\n", ret);
exit(-1);
}
/* Destroy the task. */
mco_result res = mco_destroy(task);
if(res != MCO_SUCCESS)
fail_mco("Failed to destroy coroutine", res);
break;
}
default: {
fail("Unexpected task state");
break;
}
}
}
return 0;
}
int main() {
/* Initialize mutex. */
if(c89mtx_init(&mutex, c89mtx_plain) != c89thrd_success)
fail("Failed to create mutex");
/* Create coroutine tasks. */
for(int i=0;i<NUM_TASKS;++i) {
tasks[i] = create_fibonacci_task();
}
/* Create thread workers. */
for(size_t i=0;i<NUM_THREADS;++i) {
if(c89thrd_create(&threads[i], thread_worker, NULL) != c89thrd_success)
fail("Failed to create a thread");
}
/* Wait all threads to finish. */
for(size_t i=0;i<NUM_THREADS;++i) {
if(c89thrd_join(threads[i], NULL) != c89thrd_success)
fail("Failed to join a thread!");
}
for(int i=0;i<NUM_TASKS;++i) {
if(tasks[i] != NULL)
fail("A task is unfinished");
}
/* Destroy mutex. */
c89mtx_destroy(&mutex);
printf("Multithread test succeeded!\n");
return 0;
}