Implemented async better.
This commit is contained in:
@@ -17,3 +17,5 @@ char str_pool[STR_POOL_SIZE];
|
||||
int str_pool_idx = 0;
|
||||
long ax = 0;
|
||||
int return_flag = 0;
|
||||
Coroutine coroutines[MAX_COROUTINES];
|
||||
int coroutine_count = 0;
|
||||
|
||||
+13
-5
@@ -241,18 +241,26 @@ void statement() {
|
||||
void scan_functions() {
|
||||
int i = 0;
|
||||
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
|
||||
if (i + 2 < MAX_TOK && i + 2 < tk_idx &&
|
||||
(tokens[i].type == Int || tokens[i].type == Char || tokens[i].type == Double) &&
|
||||
tokens[i+1].type == Id && tokens[i+2].type == '(') {
|
||||
int is_async = 0;
|
||||
int offset = 0;
|
||||
if (tokens[i].type == Async) {
|
||||
is_async = 1;
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
if (i + 2 + offset < MAX_TOK && i + 2 + offset < tk_idx &&
|
||||
(tokens[i+offset].type == Int || tokens[i+offset].type == Char || tokens[i+offset].type == Double) &&
|
||||
tokens[i+1+offset].type == Id && tokens[i+2+offset].type == '(') {
|
||||
|
||||
if (func_cnt >= 100) {
|
||||
error("Too many functions defined");
|
||||
}
|
||||
Func *f = &funcs[func_cnt++];
|
||||
Token *name = &tokens[i+1];
|
||||
Token *name = &tokens[i+1+offset];
|
||||
strncpy(f->name, name->text, name->val); f->name[name->val] = 0;
|
||||
f->is_async = is_async;
|
||||
|
||||
i += 3;
|
||||
i += 3 + offset;
|
||||
f->params_start = i;
|
||||
int params = 0;
|
||||
while(i < MAX_TOK && i < tk_idx && tokens[i].type != ')') {
|
||||
|
||||
@@ -1035,6 +1035,259 @@ long native_async_result(long *args, int argc) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static pthread_mutex_t coroutine_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int coroutine_initialized = 0;
|
||||
|
||||
void init_coroutines() {
|
||||
if (!coroutine_initialized) {
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
for (int i = 0; i < MAX_COROUTINES; i++) {
|
||||
coroutines[i].active = 0;
|
||||
coroutines[i].complete = 0;
|
||||
coroutines[i].result = 0;
|
||||
coroutines[i].thread = NULL;
|
||||
}
|
||||
coroutine_count = 0;
|
||||
coroutine_initialized = 1;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_coroutine() {
|
||||
init_coroutines();
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
for (int i = 0; i < MAX_COROUTINES; i++) {
|
||||
if (!coroutines[i].active) {
|
||||
coroutines[i].active = 1;
|
||||
coroutines[i].complete = 0;
|
||||
coroutines[i].result = 0;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int coroutine_id;
|
||||
} CoroutineThreadData;
|
||||
|
||||
void* coroutine_thread_func(void *arg) {
|
||||
CoroutineThreadData *data = (CoroutineThreadData*)arg;
|
||||
int coro_id = data->coroutine_id;
|
||||
free(data);
|
||||
|
||||
if (coro_id < 0 || coro_id >= MAX_COROUTINES) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Coroutine *coro = &coroutines[coro_id];
|
||||
|
||||
int func_idx = coro->func_idx;
|
||||
int argc = coro->argc;
|
||||
long args[10];
|
||||
for (int i = 0; i < argc && i < 10; i++) {
|
||||
args[i] = coro->args[i];
|
||||
}
|
||||
|
||||
if (func_idx < 0 || func_idx >= func_cnt) {
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
coro->complete = 1;
|
||||
coro->result = 0;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
|
||||
long saved_memory[MEM_SIZE];
|
||||
Symbol saved_locals[VAR_MAX];
|
||||
int saved_pc, saved_sp, saved_bp, saved_loc_cnt;
|
||||
long saved_ax;
|
||||
int saved_return_flag;
|
||||
|
||||
for (int i = 0; i < MEM_SIZE; i++) {
|
||||
saved_memory[i] = memory[i];
|
||||
}
|
||||
for (int i = 0; i < loc_cnt && i < VAR_MAX; i++) {
|
||||
saved_locals[i] = locals[i];
|
||||
}
|
||||
saved_pc = pc;
|
||||
saved_sp = sp;
|
||||
saved_bp = bp;
|
||||
saved_loc_cnt = loc_cnt;
|
||||
saved_ax = ax;
|
||||
saved_return_flag = return_flag;
|
||||
|
||||
int old_loc_cnt = loc_cnt;
|
||||
|
||||
if (sp >= MEM_SIZE || bp < 0 || bp >= MEM_SIZE) {
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
coro->complete = 1;
|
||||
coro->result = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memory[sp] = bp;
|
||||
bp = sp++;
|
||||
if (sp >= MEM_SIZE) {
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
coro->complete = 1;
|
||||
coro->result = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memory[sp++] = 0;
|
||||
memory[sp++] = old_loc_cnt;
|
||||
|
||||
int param_base = sp;
|
||||
for (int i = 0; i < argc && i < 10; i++) {
|
||||
if (sp >= MEM_SIZE) break;
|
||||
memory[sp++] = args[i];
|
||||
}
|
||||
|
||||
int scan_pc = funcs[func_idx].params_start;
|
||||
int param_idx = 0;
|
||||
while (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
|
||||
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char || tokens[scan_pc].type == Double) {
|
||||
scan_pc++;
|
||||
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
|
||||
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
|
||||
Token *param_name = &tokens[scan_pc];
|
||||
Symbol *sym = &locals[loc_cnt++];
|
||||
int name_len = param_name->val;
|
||||
if (name_len > 31) name_len = 31;
|
||||
strncpy(sym->name, param_name->text, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = Int;
|
||||
sym->addr = param_base + param_idx;
|
||||
sym->is_array = 0;
|
||||
param_idx++;
|
||||
}
|
||||
}
|
||||
scan_pc++;
|
||||
}
|
||||
|
||||
pc = funcs[func_idx].entry_point;
|
||||
return_flag = 0;
|
||||
ax = 0;
|
||||
|
||||
extern void statement();
|
||||
statement();
|
||||
|
||||
long result_val = ax;
|
||||
|
||||
for (int i = 0; i < MEM_SIZE; i++) {
|
||||
memory[i] = saved_memory[i];
|
||||
}
|
||||
for (int i = 0; i < saved_loc_cnt && i < VAR_MAX; i++) {
|
||||
locals[i] = saved_locals[i];
|
||||
}
|
||||
pc = saved_pc;
|
||||
sp = saved_sp;
|
||||
bp = saved_bp;
|
||||
loc_cnt = saved_loc_cnt;
|
||||
ax = saved_ax;
|
||||
return_flag = saved_return_flag;
|
||||
|
||||
coro->result = result_val;
|
||||
coro->complete = 1;
|
||||
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int create_coroutine(int func_idx, long *args, int argc) {
|
||||
int coro_id = alloc_coroutine();
|
||||
if (coro_id < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Coroutine *coro = &coroutines[coro_id];
|
||||
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
coro->func_idx = func_idx;
|
||||
coro->argc = argc;
|
||||
for (int i = 0; i < argc && i < 10; i++) {
|
||||
coro->args[i] = args[i];
|
||||
}
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
|
||||
CoroutineThreadData *thread_data = malloc(sizeof(CoroutineThreadData));
|
||||
thread_data->coroutine_id = coro_id;
|
||||
|
||||
pthread_t *thread = malloc(sizeof(pthread_t));
|
||||
pthread_create(thread, NULL, coroutine_thread_func, thread_data);
|
||||
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
coro->thread = thread;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
|
||||
return coro_id;
|
||||
}
|
||||
|
||||
long native_await(long *args, int argc) {
|
||||
if (!args || argc < 1) return 0;
|
||||
int coro_id = (int)args[0];
|
||||
|
||||
if (coro_id < 0 || coro_id >= MAX_COROUTINES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Coroutine *coro = &coroutines[coro_id];
|
||||
if (!coro->active) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_t *thread = (pthread_t*)coro->thread;
|
||||
if (thread) {
|
||||
pthread_join(*thread, NULL);
|
||||
free(thread);
|
||||
coro->thread = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
long result = coro->result;
|
||||
coro->active = 0;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
long native_gather(long *args, int argc) {
|
||||
if (!args || argc < 1) return 0;
|
||||
|
||||
int coro_ids[100];
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < argc && i < 100; i++) {
|
||||
coro_ids[count++] = (int)args[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int coro_id = coro_ids[i];
|
||||
if (coro_id < 0 || coro_id >= MAX_COROUTINES) continue;
|
||||
|
||||
Coroutine *coro = &coroutines[coro_id];
|
||||
if (!coro->active) continue;
|
||||
|
||||
pthread_t *thread = (pthread_t*)coro->thread;
|
||||
if (thread) {
|
||||
pthread_join(*thread, NULL);
|
||||
free(thread);
|
||||
coro->thread = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&coroutine_mutex);
|
||||
coro->active = 0;
|
||||
pthread_mutex_unlock(&coroutine_mutex);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void register_native_functions() {
|
||||
register_native_func("socket", native_socket);
|
||||
register_native_func("bind", native_bind);
|
||||
@@ -1089,4 +1342,6 @@ void register_native_functions() {
|
||||
register_native_func("async_wait", native_async_wait);
|
||||
register_native_func("async_poll", native_async_poll);
|
||||
register_native_func("async_result", native_async_result);
|
||||
register_native_func("await", native_await);
|
||||
register_native_func("gather", native_gather);
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
void register_native_func(char *name, NativeFunc func);
|
||||
void register_native_functions();
|
||||
int create_coroutine(int func_idx, long *args, int argc);
|
||||
|
||||
#endif
|
||||
|
||||
+17
-1
@@ -31,7 +31,18 @@ long factor() {
|
||||
Token *t = &tokens[pc];
|
||||
long val = 0;
|
||||
|
||||
if (t->type == Num) {
|
||||
if (t->type == Await) {
|
||||
pc++;
|
||||
match('(');
|
||||
long coro_id = expression();
|
||||
match(')');
|
||||
|
||||
extern long native_await(long*, int);
|
||||
long args[1];
|
||||
args[0] = coro_id;
|
||||
return native_await(args, 1);
|
||||
}
|
||||
else if (t->type == Num) {
|
||||
pc++;
|
||||
return t->val;
|
||||
}
|
||||
@@ -94,6 +105,11 @@ long factor() {
|
||||
}
|
||||
match(')');
|
||||
|
||||
if (funcs[f_idx].is_async) {
|
||||
extern int create_coroutine(int func_idx, long *args, int argc);
|
||||
return create_coroutine(f_idx, args, argc);
|
||||
}
|
||||
|
||||
int ret_pc = pc;
|
||||
int old_loc_cnt = loc_cnt;
|
||||
int old_bp = bp;
|
||||
|
||||
@@ -42,6 +42,8 @@ void tokenize(char *src) {
|
||||
else if (!strcmp(buf, "printf")) t->type = Printf;
|
||||
else if (!strcmp(buf, "break")) t->type = Break;
|
||||
else if (!strcmp(buf, "continue")) t->type = Continue;
|
||||
else if (!strcmp(buf, "async")) t->type = Async;
|
||||
else if (!strcmp(buf, "await")) t->type = Await;
|
||||
else t->type = Id;
|
||||
|
||||
t->val = len;
|
||||
|
||||
+22
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
enum {
|
||||
Num = 128, Dbl, Str, Id, Int, Char, Double, Else, If, While, Return, Printf,
|
||||
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue
|
||||
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue, Async, Await
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -31,6 +31,7 @@ typedef struct {
|
||||
int entry_point;
|
||||
int param_count;
|
||||
int params_start;
|
||||
int is_async;
|
||||
} Func;
|
||||
|
||||
typedef long (*NativeFunc)(long*, int);
|
||||
@@ -40,6 +41,24 @@ typedef struct {
|
||||
NativeFunc func;
|
||||
} NativeFuncDef;
|
||||
|
||||
#define MAX_COROUTINES 100
|
||||
|
||||
typedef struct Coroutine {
|
||||
int active;
|
||||
int complete;
|
||||
long result;
|
||||
void *thread;
|
||||
int func_idx;
|
||||
long args[10];
|
||||
int argc;
|
||||
int pc_saved;
|
||||
int sp_saved;
|
||||
int bp_saved;
|
||||
int loc_cnt_saved;
|
||||
Symbol locals_saved[VAR_MAX];
|
||||
long memory_saved[MEM_SIZE];
|
||||
} Coroutine;
|
||||
|
||||
extern Token tokens[MAX_TOK];
|
||||
extern int tk_idx;
|
||||
extern int pc;
|
||||
@@ -57,5 +76,7 @@ extern char str_pool[STR_POOL_SIZE];
|
||||
extern int str_pool_idx;
|
||||
extern long ax;
|
||||
extern int return_flag;
|
||||
extern Coroutine coroutines[MAX_COROUTINES];
|
||||
extern int coroutine_count;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user