Skip to content

Commit 5e43b3e

Browse files
committed
Adding protothread fiddle
This adds an initial cut of a protothread implementation. Needs to be factored into something a little more clean. It does work and has a small test. Note that this does some things differently than standard protothreads with several macros that build a lot of boilerplate for you. You get a function to call that sets up the protothread to run with the arguments you pass.�
1 parent f06b110 commit 5e43b3e

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

pt/pt.h

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Test code for Protothread implementation.
3+
*
4+
* This is based on Adam Dunkel's Protothreads.
5+
*
6+
*/
7+
8+
#ifndef __PT_H__
9+
#define __PT_H__
10+
11+
#define FEP_2(WHAT, WHAT_LAST, X, Y) WHAT_LAST(X,Y)
12+
#define FEP_4(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_2(WHAT, WHAT_LAST, __VA_ARGS__)
13+
#define FEP_6(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_4(WHAT, WHAT_LAST, __VA_ARGS__)
14+
#define FEP_8(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_6(WHAT, WHAT_LAST, __VA_ARGS__)
15+
#define FEP_10(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_8(WHAT, WHAT_LAST, __VA_ARGS__)
16+
#define FEP_12(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_10(WHAT, WHAT_LAST, __VA_ARGS__)
17+
#define FEP_14(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_12(WHAT, WHAT_LAST, __VA_ARGS__)
18+
#define FEP_16(WHAT, WHAT_LAST, X, Y, ...) WHAT(X,Y)FEP_14(WHAT, WHAT_LAST, __VA_ARGS__)
19+
20+
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,NAME,...) NAME
21+
#define FOREACH_PAIR(action, ...) \
22+
GET_MACRO(__VA_ARGS__,FEP_16,OOPS15,FEP_14,OOPS13,FEP_12,OOPS11,FEP_10,OOPS9,FEP_8,OOPS7,FEP_6,OOPS5,FEP_4,OOPS3,FEP_2,OOPS1,)(action,action,__VA_ARGS__)
23+
#define FOREACH_PAIR_LAST(action, action_last, ...) \
24+
GET_MACRO(__VA_ARGS__,FEP_16,OOPS15,FEP_14,OOPS13,FEP_12,OOPS11,FEP_10,OOPS9,FEP_8,OOPS7,FEP_6,OOPS5,FEP_4,OOPS3,FEP_2,OOPS1,)(action,action_last,__VA_ARGS__)
25+
26+
27+
typedef void *pt_context_p;
28+
29+
#define PT_TERMINATE (0)
30+
#define PT_RESUME (1)
31+
32+
#define PT_MAKE_FUNC_ARG(T,V) PT_MAKE_FUNC_ARG_1(T,V)
33+
#define PT_MAKE_FUNC_ARG_1(T,V) T V,
34+
#define PT_MAKE_FUNC_ARG_LAST(T,V) PT_MAKE_FUNC_ARG_LAST_1(T,V)
35+
#define PT_MAKE_FUNC_ARG_LAST_1(T,V) T V
36+
#define PT_MAKE_STRUCT_FIELD(T,V) PT_MAKE_STRUCT_FIELD_1(T,V)
37+
#define PT_MAKE_STRUCT_FIELD_1(T,V) T V;
38+
#define PT_MAKE_ARG_ASSIGN(T,V) PT_MAKE_ARG_ASSIGN_1(T,V)
39+
#define PT_MAKE_ARG_ASSIGN_1(T,V) pt_args->V = V;
40+
41+
#define PT_CONCAT(A,B) PT_CONCAT_1(A,B)
42+
#define PT_CONCAT_1(A,B) A##B
43+
44+
#define PT_FUNC(name, ...) \
45+
struct PT_CONCAT(pt_args_,name) { \
46+
FOREACH_PAIR(PT_MAKE_STRUCT_FIELD,__VA_ARGS__) \
47+
}; \
48+
static int PT_CONCAT(pt_func_,name)(void *args_arg, void **ctx_arg); \
49+
int name(FOREACH_PAIR_LAST(PT_MAKE_FUNC_ARG, PT_MAKE_FUNC_ARG_LAST, __VA_ARGS__)) {\
50+
struct pt_args_##name *pt_args = calloc(1, sizeof(struct pt_args_##name)); \
51+
if(!pt_args) return -1; \
52+
FOREACH_PAIR(PT_MAKE_ARG_ASSIGN,__VA_ARGS__) \
53+
return pt_schedule(PT_CONCAT(pt_func_,name),pt_args); \
54+
} \
55+
int PT_CONCAT(pt_func_,name)(void *args_arg, void **ctx_arg) { \
56+
struct PT_CONCAT(pt_args_,name) *args = (struct PT_CONCAT(pt_args_,name) *)args_arg;
57+
58+
#define PT_CONTEXT(...) \
59+
struct pt_ctx { \
60+
int pt_state; \
61+
FOREACH_PAIR(PT_MAKE_STRUCT_FIELD,__VA_ARGS__) \
62+
} *ctx = (struct pt_ctx *)(*ctx_arg); \
63+
if(!ctx) { \
64+
ctx = calloc(1, sizeof(struct pt_ctx)); \
65+
if(!ctx) return PT_TERMINATE; \
66+
*ctx_arg = ctx; \
67+
}
68+
69+
#define PT_BODY \
70+
switch(ctx->pt_state) { \
71+
case 0:
72+
73+
#define PT_EXIT \
74+
do { ctx->pt_state = 0; return PT_TERMINATE; } while(0)
75+
76+
#define PT_END \
77+
default: \
78+
break; \
79+
} \
80+
PT_EXIT; \
81+
}
82+
83+
#define PT_YIELD ctx->pt_state = __LINE__; return PT_RESUME; case __LINE__: do {} while(0)
84+
#define PT_WAIT_WHILE(cond) do {ctx->pt_state = __LINE__; case __LINE__: if((cond)) return PT_RESUME; } while(0)
85+
#define PT_WAIT_UNTIL(cond) do {ctx->pt_state = __LINE__; case __LINE__: if(!(cond)) return PT_RESUME; } while(0)
86+
87+
88+
89+
#endif

pt/pt_test.c

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <unistd.h>
4+
5+
#include "pt.h"
6+
7+
8+
typedef int (*pt_func)(void *, void **);
9+
10+
struct pt_entry {
11+
struct pt_entry *next;
12+
void *args;
13+
void *ctx;
14+
pt_func func;
15+
};
16+
17+
18+
static struct pt_entry *pt_list;
19+
20+
int pt_schedule(pt_func func, void *args)
21+
{
22+
struct pt_entry *entry = calloc(1,sizeof(struct pt_entry));
23+
if(!entry) {
24+
fprintf(stderr,"oops, cannot allocate new pt entry!");
25+
return -1;
26+
}
27+
28+
entry->func = func;
29+
entry->args = args;
30+
31+
entry->next = pt_list;
32+
pt_list = entry;
33+
34+
return 1;
35+
}
36+
37+
int pt_run(void)
38+
{
39+
struct pt_entry *curr = pt_list;
40+
struct pt_entry *last = NULL;
41+
42+
while(pt_list) {
43+
if(curr->func(curr->args,&curr->ctx) == PT_TERMINATE) {
44+
struct pt_entry *next = curr->next;
45+
46+
if(curr->args) free(curr->args);
47+
if(curr->ctx) free(curr->ctx);
48+
free(curr);
49+
50+
if(!last) {
51+
pt_list = next;
52+
} else {
53+
last->next = next;
54+
}
55+
56+
curr = next;
57+
} else {
58+
last = curr;
59+
curr = curr->next;
60+
}
61+
62+
if(!curr) {
63+
curr = pt_list;
64+
last = NULL;
65+
}
66+
}
67+
68+
return 1;
69+
}
70+
71+
72+
73+
74+
PT_FUNC(test,char*,name,int,start_val,int,end_val)
75+
PT_CONTEXT(int,i)
76+
PT_BODY
77+
for(ctx->i = args->start_val; ctx->i <= args->end_val; ctx->i++) {
78+
printf("%s count %d\n",args->name,ctx->i);
79+
PT_YIELD;
80+
}
81+
PT_END
82+
83+
84+
int main(int argc, char **argv)
85+
{
86+
test("Test 1",3,7);
87+
test("Test 2", 10,20);
88+
test("Test 3", 1,5);
89+
90+
pt_run();
91+
92+
return 0;
93+
}

0 commit comments

Comments
 (0)