Skip to content

Commit 6f38fb5

Browse files
committed
Refactor coroutine macros
Since for the original version, programmers may misuse these macros, to avoid such situation, we have modified macros that are used for controlling coroutines and macros that programmers use for declaring coroutine functions and their corresponding contexts. First of all, cr_proto was introduced as the generator of coroutine function declarations, and all coroutines should be specified with this macro. By introducing cr_proto, we have wrapped the argument that refers to the coroutine context into a fixed name variable called ctx, which will be refered by controlling macros such as cr_begin, cr_end, cr_wait and so on. Invoking these macros is valid only in a coroutine function that was generated by cr_proto, otherwise, compiler will report errors. Next, we have modified structure cr that its field local is removed, and macro cr_context is introduced for programmers to declare the coroutine contexts. The name assigned to cr_context should be identical with the one used to generate the coroutine function. After generated a coroutine function and its corresponding context, programmers could launch that coroutine via macro cr_run. Finally, to declare static variables in coroutine, macro cr_local is introduced, which helps to mark wheather a variable is a part of coroutine or just for temporary usage. Abstract using of coroutine macros With in this version, a set of macros are introduced, which aim to provide standard style for someone declare or access the coroutine function and its corresponding context. One should declare a coroutine function with cr_func_def macro, and its corresponding context with cr_context macro, the argument name provides to those macros for the same coroutine should be identical. After declaration, one could run a coroutine by cr_run macro. Wrapping a set of cr_run macros in a loop makes several coroutines execute concurrently. Since the declaration of a coroutine funciton is wrapped by macro cr_func_def, there is no need to provide the context as argument of macros that contorl the coroutine, such as cr_begin, cr_end, cr_wait etc. That argument was hardcoded as __ct in the body of those macros. To pass arguments to a coroutine, one can provide a pointer to that argument as parameter of cr_context_init macro, and to extact them in the coroutine, two macros, cr_arg and cr_arg_member, were introduced. Macro cr_arg will cast __ct->arg to the pointer of corresponding type, while cr_arg_member will return a pointer to the specific member of given structure type that __ct->arg points to. Finally, to define a static variable with in the coroutine, one can define them with cr_local macro, which helps to hightlight wheather a variable is a part of that coroutine or just for temporary usage. Rename macros and variables To make the name of macros and variables indicate purpose of themself more clearly, some of them were renamed. Following lists the modified macros and variables: * Macro cr_func_def is renamed as cr_define, which will avoid confusing and make programmers focus on dealing body of coroutine. * Hardcoded __ct is renamed as ctx which stands for context.\ * The name of structure sock_w_loc_t is changed to conn_data_t, since it aims to hold data used for connection. Make coroutine function be declared in C-Style Macro cr_proto is introduced to replace cr_define, which makes programmers to declare a coroutine function in C-style, that is, more flexible than cr_define. Macro cr_run is modified to make respond to cr_proto. The new version of cr_run accepts variable length argument list. From now, programmers could specify arguments that are going to be passed to coroutines, by listing arguments after name while starting coroutine with macro cr_run. Since the way of passing arguments was changed, the field arg in structure cr is removed and macros that aimed to fetch value from arg are also removed.
1 parent e2cdfe2 commit 6f38fb5

File tree

1 file changed

+64
-53
lines changed

1 file changed

+64
-53
lines changed

tinync/tinync.c

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,50 @@ enum {
1414
struct cr {
1515
void *label;
1616
int status;
17-
void *local; /* private local storage */
1817
};
1918

20-
#define cr_init() \
19+
#define cr_context_name(name) __cr_context_##name
20+
#define cr_context(name) struct cr cr_context_name(name)
21+
#define cr_context_init() \
2122
{ \
2223
.label = NULL, .status = CR_BLOCKED \
2324
}
24-
#define cr_begin(o) \
25-
do { \
26-
if ((o)->status == CR_FINISHED) \
27-
return; \
28-
if ((o)->label) \
29-
goto *(o)->label; \
25+
26+
#define cr_func_name(name) __cr_func_##name
27+
#define cr_proto(name, ...) cr_func_name(name)(struct cr * ctx, ##__VA_ARGS__)
28+
29+
#define cr_run(name, ...) \
30+
cr_func_name(name)(&cr_context_name(name), ##__VA_ARGS__)
31+
32+
#define cr_local static
33+
34+
#define cr_begin() \
35+
do { \
36+
if ((ctx)->status == CR_FINISHED) \
37+
return; \
38+
if ((ctx)->label) \
39+
goto *(ctx)->label; \
3040
} while (0)
3141
#define cr_label(o, stat) \
3242
do { \
3343
(o)->status = (stat); \
3444
__cr_line(label) : (o)->label = &&__cr_line(label); \
3545
} while (0)
36-
#define cr_end(o) cr_label(o, CR_FINISHED)
46+
#define cr_end() cr_label(ctx, CR_FINISHED)
3747

38-
#define cr_status(o) (o)->status
48+
#define cr_status(name) cr_context_name(name).status
3949

40-
#define cr_wait(o, cond) \
41-
do { \
42-
cr_label(o, CR_BLOCKED); \
43-
if (!(cond)) \
44-
return; \
50+
#define cr_wait(cond) \
51+
do { \
52+
cr_label(ctx, CR_BLOCKED); \
53+
if (!(cond)) \
54+
return; \
4555
} while (0)
4656

47-
#define cr_exit(o, stat) \
48-
do { \
49-
cr_label(o, stat); \
50-
return; \
57+
#define cr_exit(stat) \
58+
do { \
59+
cr_label(ctx, stat); \
60+
return; \
5161
} while (0)
5262

5363
#define cr_queue(T, size) \
@@ -70,9 +80,9 @@ struct cr {
7080
(cr_queue_empty(q) ? NULL : &(q)->buf[(q)->r++ % cr_queue_len(q)])
7181

7282
/* Wrap system calls and other functions that return -1 and set errno */
73-
#define cr_sys(o, call) \
74-
cr_wait(o, (errno = 0) || !(((call) == -1) && \
75-
(errno == EAGAIN || errno == EWOULDBLOCK || \
83+
#define cr_sys(call) \
84+
cr_wait((errno = 0) || \
85+
!(((call) == -1) && (errno == EAGAIN || errno == EWOULDBLOCK || \
7686
errno == EINPROGRESS || errno == EINTR)))
7787

7888
#include <arpa/inet.h>
@@ -87,47 +97,47 @@ struct cr {
8797

8898
typedef cr_queue(uint8_t, 4096) byte_queue_t;
8999

90-
static void stdin_loop(struct cr *o, byte_queue_t *out)
100+
static void cr_proto(stdin_loop, byte_queue_t *out)
91101
{
92-
static uint8_t b;
93-
static int r;
94-
cr_begin(o);
102+
cr_local uint8_t b;
103+
cr_local int r;
104+
cr_begin();
95105
for (;;) {
96-
cr_sys(o, r = read(STDIN_FILENO, &b, 1));
106+
cr_sys(r = read(STDIN_FILENO, &b, 1));
97107
if (r == 0) {
98-
cr_wait(o, cr_queue_empty(out));
99-
cr_exit(o, 1);
108+
cr_wait(cr_queue_empty(out));
109+
cr_exit(1);
100110
}
101-
cr_wait(o, !cr_queue_full(out));
111+
cr_wait(!cr_queue_full(out));
102112
cr_queue_push(out, b);
103113
}
104-
cr_end(o);
114+
cr_end();
105115
}
106116

107-
static void socket_write_loop(struct cr *o, int fd, byte_queue_t *in)
117+
static void cr_proto(socket_write_loop, byte_queue_t *in, int fd)
108118
{
109-
static uint8_t *b;
110-
cr_begin(o);
119+
cr_local uint8_t *b;
120+
cr_begin();
111121
for (;;) {
112-
cr_wait(o, !cr_queue_empty(in));
122+
cr_wait(!cr_queue_empty(in));
113123
b = cr_queue_pop(in);
114-
cr_sys(o, send(fd, b, 1, 0));
124+
cr_sys(send(fd, b, 1, 0));
115125
}
116-
cr_end(o);
126+
cr_end();
117127
}
118128

119-
static void socket_read_loop(struct cr *o, int fd)
129+
static void cr_proto(socket_read_loop, int fd)
120130
{
121-
static uint8_t b;
122-
static int r;
123-
cr_begin(o);
131+
cr_local uint8_t b;
132+
cr_local int r;
133+
cr_begin();
124134
for (;;) {
125-
cr_sys(o, r = recv(fd, &b, 1, 0));
135+
cr_sys(r = recv(fd, &b, 1, 0));
126136
if (r == 0)
127-
cr_exit(o, 1);
128-
cr_sys(o, write(STDOUT_FILENO, &b, 1));
137+
cr_exit(1);
138+
cr_sys(write(STDOUT_FILENO, &b, 1));
129139
}
130-
cr_end(o);
140+
cr_end();
131141
}
132142

133143
static int nonblock(int fd)
@@ -176,23 +186,24 @@ int main(int argc, char *argv[])
176186
};
177187
connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
178188

179-
struct cr cr_stdin = cr_init();
180-
struct cr cr_socket_read = cr_init();
181-
struct cr cr_socket_write = cr_init();
182189
byte_queue_t queue = cr_queue_init();
183190

184-
while (cr_status(&cr_stdin) == CR_BLOCKED &&
185-
cr_status(&cr_socket_read) == CR_BLOCKED) {
191+
cr_context(stdin_loop) = cr_context_init();
192+
cr_context(socket_read_loop) = cr_context_init();
193+
cr_context(socket_write_loop) = cr_context_init();
194+
195+
while (cr_status(stdin_loop) == CR_BLOCKED &&
196+
cr_status(socket_read_loop) == CR_BLOCKED) {
186197
if (cr_queue_empty(&queue)) {
187198
fd_set fds;
188199
FD_ZERO(&fds);
189200
FD_SET(STDIN_FILENO, &fds);
190201
FD_SET(fd, &fds);
191202
select(fd + 1, &fds, NULL, NULL, NULL);
192203
}
193-
socket_read_loop(&cr_socket_read, fd);
194-
socket_write_loop(&cr_socket_write, fd, &queue);
195-
stdin_loop(&cr_stdin, &queue);
204+
cr_run(socket_read_loop, fd);
205+
cr_run(socket_write_loop, &queue, fd);
206+
cr_run(stdin_loop, &queue);
196207
}
197208

198209
close(fd);

0 commit comments

Comments
 (0)