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:
2025-11-23 13:30:46 +00:00
parent 03bca46d88
commit 79a06a0be8
6 changed files with 696 additions and 12 deletions
+327 -1
View File
@@ -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);
}