feat: add async I/O, double type, file I/O, and break/continue to RC interpreter
Implement multi-threaded async file and socket operations with pthread-based worker pool, add double floating-point type with conversion and arithmetic functions, introduce file I/O system with fopen/fclose/fread/fwrite/fgets/fputs, and add break/continue control flow statements. Update Makefile with new test and example targets, extend README and TUTORIAL.md with comprehensive documentation and usage examples, and include async_demo.rc example and async_io_test.rc test suite.
This commit is contained in:
+327
-1
@@ -7,10 +7,193 @@
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include "types.h"
|
||||
#include "native_functions.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
#define MAX_ASYNC_OPS 100
|
||||
|
||||
typedef struct {
|
||||
int active;
|
||||
int complete;
|
||||
long result;
|
||||
pthread_t thread;
|
||||
void *data;
|
||||
} AsyncOp;
|
||||
|
||||
static AsyncOp async_ops[MAX_ASYNC_OPS];
|
||||
static pthread_mutex_t async_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int async_initialized = 0;
|
||||
|
||||
typedef struct {
|
||||
FILE *f;
|
||||
int addr;
|
||||
int size;
|
||||
} AsyncFileReadData;
|
||||
|
||||
typedef struct {
|
||||
FILE *f;
|
||||
long buf_arg;
|
||||
int size;
|
||||
} AsyncFileWriteData;
|
||||
|
||||
typedef struct {
|
||||
int sockfd;
|
||||
int addr;
|
||||
int len;
|
||||
int flags;
|
||||
} AsyncRecvData;
|
||||
|
||||
typedef struct {
|
||||
int sockfd;
|
||||
long buf_arg;
|
||||
int len;
|
||||
int flags;
|
||||
} AsyncSendData;
|
||||
|
||||
void init_async() {
|
||||
if (!async_initialized) {
|
||||
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
|
||||
async_ops[i].active = 0;
|
||||
async_ops[i].complete = 0;
|
||||
async_ops[i].result = 0;
|
||||
async_ops[i].data = NULL;
|
||||
}
|
||||
async_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_async_op() {
|
||||
init_async();
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
|
||||
if (!async_ops[i].active) {
|
||||
async_ops[i].active = 1;
|
||||
async_ops[i].complete = 0;
|
||||
async_ops[i].result = 0;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void* async_fread_thread(void *arg) {
|
||||
int id = *(int*)arg;
|
||||
free(arg);
|
||||
AsyncFileReadData *data = (AsyncFileReadData*)async_ops[id].data;
|
||||
|
||||
char temp_buf[8192];
|
||||
int size = data->size;
|
||||
if (size > 8192) size = 8192;
|
||||
|
||||
int result = fread(temp_buf, 1, size, data->f);
|
||||
if (result > 0) {
|
||||
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
|
||||
memory[data->addr + i] = temp_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
async_ops[id].result = result;
|
||||
async_ops[id].complete = 1;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
free(data);
|
||||
async_ops[id].data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* async_fwrite_thread(void *arg) {
|
||||
int id = *(int*)arg;
|
||||
free(arg);
|
||||
AsyncFileWriteData *data = (AsyncFileWriteData*)async_ops[id].data;
|
||||
|
||||
long result = -1;
|
||||
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
|
||||
result = fwrite((char*)data->buf_arg, 1, data->size, data->f);
|
||||
} else if (data->buf_arg < MEM_SIZE) {
|
||||
char temp_buf[8192];
|
||||
int size = data->size;
|
||||
if (size > 8192) size = 8192;
|
||||
if (data->buf_arg + size > MEM_SIZE) {
|
||||
size = MEM_SIZE - data->buf_arg;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
temp_buf[i] = (char)memory[data->buf_arg + i];
|
||||
}
|
||||
result = fwrite(temp_buf, 1, size, data->f);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
async_ops[id].result = result;
|
||||
async_ops[id].complete = 1;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
free(data);
|
||||
async_ops[id].data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* async_recv_thread(void *arg) {
|
||||
int id = *(int*)arg;
|
||||
free(arg);
|
||||
AsyncRecvData *data = (AsyncRecvData*)async_ops[id].data;
|
||||
|
||||
char temp_buf[8192];
|
||||
int len = data->len;
|
||||
if (len > 8192) len = 8192;
|
||||
|
||||
int result = recv(data->sockfd, temp_buf, len, data->flags);
|
||||
if (result > 0) {
|
||||
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
|
||||
memory[data->addr + i] = temp_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
async_ops[id].result = result;
|
||||
async_ops[id].complete = 1;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
free(data);
|
||||
async_ops[id].data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* async_send_thread(void *arg) {
|
||||
int id = *(int*)arg;
|
||||
free(arg);
|
||||
AsyncSendData *data = (AsyncSendData*)async_ops[id].data;
|
||||
|
||||
long result = -1;
|
||||
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
|
||||
result = send(data->sockfd, (char*)data->buf_arg, data->len, data->flags);
|
||||
} else if (data->buf_arg < MEM_SIZE) {
|
||||
char temp_buf[8192];
|
||||
int len = data->len;
|
||||
if (len > 8192) len = 8192;
|
||||
if (data->buf_arg + len > MEM_SIZE) {
|
||||
len = MEM_SIZE - data->buf_arg;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
temp_buf[i] = (char)memory[data->buf_arg + i];
|
||||
}
|
||||
result = send(data->sockfd, temp_buf, len, data->flags);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
async_ops[id].result = result;
|
||||
async_ops[id].complete = 1;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
free(data);
|
||||
async_ops[id].data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void register_native_func(char *name, NativeFunc func) {
|
||||
if (!name || !func || native_func_cnt >= 100) {
|
||||
return;
|
||||
@@ -28,7 +211,12 @@ long native_socket(long *args, int argc) {
|
||||
int domain = (int)args[0];
|
||||
int type = (int)args[1];
|
||||
int protocol = (int)args[2];
|
||||
return socket(domain, type, protocol);
|
||||
int sockfd = socket(domain, type, protocol);
|
||||
if (sockfd >= 0) {
|
||||
int opt = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
}
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
long native_bind(long *args, int argc) {
|
||||
@@ -716,6 +904,137 @@ long native_double_div(long *args, int argc) {
|
||||
return result.l;
|
||||
}
|
||||
|
||||
long native_async_fread(long *args, int argc) {
|
||||
if (!args || argc < 3) return -1;
|
||||
FILE *f = (FILE*)args[0];
|
||||
int addr = (int)args[1];
|
||||
int size = (int)args[2];
|
||||
if (!f || addr < 0 || addr >= MEM_SIZE || size <= 0) return -1;
|
||||
|
||||
int id = alloc_async_op();
|
||||
if (id < 0) return -1;
|
||||
|
||||
AsyncFileReadData *data = malloc(sizeof(AsyncFileReadData));
|
||||
data->f = f;
|
||||
data->addr = addr;
|
||||
data->size = size;
|
||||
async_ops[id].data = data;
|
||||
|
||||
int *id_ptr = malloc(sizeof(int));
|
||||
*id_ptr = id;
|
||||
pthread_create(&async_ops[id].thread, NULL, async_fread_thread, id_ptr);
|
||||
return id;
|
||||
}
|
||||
|
||||
long native_async_fwrite(long *args, int argc) {
|
||||
if (!args || argc < 3) return -1;
|
||||
FILE *f = (FILE*)args[0];
|
||||
long buf_arg = args[1];
|
||||
int size = (int)args[2];
|
||||
if (!f || size <= 0) return -1;
|
||||
|
||||
int id = alloc_async_op();
|
||||
if (id < 0) return -1;
|
||||
|
||||
AsyncFileWriteData *data = malloc(sizeof(AsyncFileWriteData));
|
||||
data->f = f;
|
||||
data->buf_arg = buf_arg;
|
||||
data->size = size;
|
||||
async_ops[id].data = data;
|
||||
|
||||
int *id_ptr = malloc(sizeof(int));
|
||||
*id_ptr = id;
|
||||
pthread_create(&async_ops[id].thread, NULL, async_fwrite_thread, id_ptr);
|
||||
return id;
|
||||
}
|
||||
|
||||
long native_async_recv(long *args, int argc) {
|
||||
if (!args || argc < 4) return -1;
|
||||
int sockfd = (int)args[0];
|
||||
int addr = (int)args[1];
|
||||
int len = (int)args[2];
|
||||
int flags = (int)args[3];
|
||||
if (addr < 0 || addr >= MEM_SIZE) return -1;
|
||||
|
||||
int id = alloc_async_op();
|
||||
if (id < 0) return -1;
|
||||
|
||||
AsyncRecvData *data = malloc(sizeof(AsyncRecvData));
|
||||
data->sockfd = sockfd;
|
||||
data->addr = addr;
|
||||
data->len = len;
|
||||
data->flags = flags;
|
||||
async_ops[id].data = data;
|
||||
|
||||
int *id_ptr = malloc(sizeof(int));
|
||||
*id_ptr = id;
|
||||
pthread_create(&async_ops[id].thread, NULL, async_recv_thread, id_ptr);
|
||||
return id;
|
||||
}
|
||||
|
||||
long native_async_send(long *args, int argc) {
|
||||
if (!args || argc < 4) return -1;
|
||||
int sockfd = (int)args[0];
|
||||
long buf_arg = args[1];
|
||||
int len = (int)args[2];
|
||||
int flags = (int)args[3];
|
||||
|
||||
int id = alloc_async_op();
|
||||
if (id < 0) return -1;
|
||||
|
||||
AsyncSendData *data = malloc(sizeof(AsyncSendData));
|
||||
data->sockfd = sockfd;
|
||||
data->buf_arg = buf_arg;
|
||||
data->len = len;
|
||||
data->flags = flags;
|
||||
async_ops[id].data = data;
|
||||
|
||||
int *id_ptr = malloc(sizeof(int));
|
||||
*id_ptr = id;
|
||||
pthread_create(&async_ops[id].thread, NULL, async_send_thread, id_ptr);
|
||||
return id;
|
||||
}
|
||||
|
||||
long native_async_wait(long *args, int argc) {
|
||||
if (!args || argc < 1) return -1;
|
||||
int id = (int)args[0];
|
||||
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return -1;
|
||||
|
||||
pthread_join(async_ops[id].thread, NULL);
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
long result = async_ops[id].result;
|
||||
async_ops[id].active = 0;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
long native_async_poll(long *args, int argc) {
|
||||
if (!args || argc < 1) return 0;
|
||||
int id = (int)args[0];
|
||||
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return 0;
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
int complete = async_ops[id].complete;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
return complete;
|
||||
}
|
||||
|
||||
long native_async_result(long *args, int argc) {
|
||||
if (!args || argc < 1) return -1;
|
||||
int id = (int)args[0];
|
||||
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return -1;
|
||||
|
||||
pthread_mutex_lock(&async_mutex);
|
||||
long result = async_ops[id].result;
|
||||
async_ops[id].active = 0;
|
||||
pthread_mutex_unlock(&async_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void register_native_functions() {
|
||||
register_native_func("socket", native_socket);
|
||||
register_native_func("bind", native_bind);
|
||||
@@ -763,4 +1082,11 @@ void register_native_functions() {
|
||||
register_native_func("double_sub", native_double_sub);
|
||||
register_native_func("double_mul", native_double_mul);
|
||||
register_native_func("double_div", native_double_div);
|
||||
register_native_func("async_fread", native_async_fread);
|
||||
register_native_func("async_fwrite", native_async_fwrite);
|
||||
register_native_func("async_recv", native_async_recv);
|
||||
register_native_func("async_send", native_async_send);
|
||||
register_native_func("async_wait", native_async_wait);
|
||||
register_native_func("async_poll", native_async_poll);
|
||||
register_native_func("async_result", native_async_result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user