summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-19 09:48:59 +0200
committerPaul Buetow <paul@buetow.org>2026-03-19 09:48:59 +0200
commit3ad5fbe368771a5023bf36fecd45586bcbb94b93 (patch)
tree4b0acc9da6a7aac4e99b1a811c0eb3e55051958d
parent8db49370807f2a3e4ebed8422047b69dde395a22 (diff)
refactor: table-drive syscall dispatchers (task 466)
-rw-r--r--ioriot/src/generate/gioop.c276
-rw-r--r--ioriot/src/generate/gioop.h1
-rw-r--r--ioriot/src/replay/rioop.c225
-rw-r--r--ioriot/src/replay/rioop.h1
-rw-r--r--ioriot/src/utests.c8
5 files changed, 236 insertions, 275 deletions
diff --git a/ioriot/src/generate/gioop.c b/ioriot/src/generate/gioop.c
index b16f893..fb1b7a1 100644
--- a/ioriot/src/generate/gioop.c
+++ b/ioriot/src/generate/gioop.c
@@ -14,9 +14,118 @@
#include "gioop.h"
+typedef status_e (*gioop_handler_f)(gwriter_s *w, gtask_s *t, generate_s *g);
+
+typedef struct {
+ const char *op;
+ gioop_handler_f handler;
+} gioop_entry_s;
+
+#define _GIOOP_ENTRY_COUNT(entries) \
+ (sizeof(entries) / sizeof((entries)[0]))
+
+static status_e
+_gioop_ignore(gwriter_s *w, gtask_s *t, generate_s *g)
+{
+ (void)w;
+ (void)t;
+ (void)g;
+
+ return SUCCESS;
+}
+
+static gioop_handler_f
+_gioop_find_handler(const gioop_entry_s *entries, const size_t num_entries,
+ const char *op)
+{
+ if (op == NULL)
+ return NULL;
+
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (Eq(entries[i].op, op))
+ return entries[i].handler;
+ }
+
+ return NULL;
+}
+
+static const gioop_entry_s _GIOOP_PREOPEN[] = {
+ {"open", gioop_open},
+ {"openat", gioop_openat},
+ {"creat", gioop_creat},
+};
+
+static const gioop_entry_s _GIOOP_DISPATCH[] = {
+ {"close", gioop_close},
+ {"stat", gioop_stat},
+ {"statfs", gioop_statfs},
+ {"statfs64", gioop_statfs64},
+ {"fstat", gioop_fstat},
+ {"fstatat", gioop_fstatat},
+ {"fstatfs", gioop_fstatfs},
+ {"fstatfs64", gioop_fstatfs64},
+ {"rename", gioop_rename},
+ {"renameat", gioop_renameat},
+ {"renameat2", gioop_renameat2},
+ {"read", gioop_read},
+ {"readv", gioop_readv},
+ {"readahead", gioop_readahead},
+ {"readdir", gioop_readdir},
+ {"readlink", gioop_readlink},
+ {"readlinkat", gioop_readlinkat},
+ {"write", gioop_write},
+ {"writev", gioop_writev},
+ {"lseek", gioop_lseek},
+ {"llseek", gioop_llseek},
+ {"getdents", gioop_getdents},
+ {"mkdir", gioop_mkdir},
+ {"rmdir", gioop_rmdir},
+ {"mkdirat", gioop_mkdirat},
+ {"unlink", gioop_unlink},
+ {"unlinkat", gioop_unlinkat},
+ {"lstat", gioop_lstat},
+ {"fsync", gioop_fsync},
+ {"fdatasync", gioop_fdatasync},
+ {"sync", gioop_sync},
+ {"syncfs", gioop_syncfs},
+ {"sync_file_range", gioop_sync_file_range},
+ {"fcntl", gioop_fcntl},
+ {"mmap2", _gioop_ignore},
+ {"munmap", _gioop_ignore},
+ {"mremap", _gioop_ignore},
+ {"msync", _gioop_ignore},
+ {"chmod", gioop_chmod},
+ {"fchmodat", gioop_chmod},
+ {"fchmod", gioop_fchmod},
+ {"chown", gioop_chown},
+ {"chown16", gioop_chown},
+ {"lchown", gioop_lchown},
+ {"lchown16", gioop_lchown},
+ {"fchown", gioop_fchown},
+ {"fchownat", gioop_chown},
+ {"exit_group", gioop_exit_group},
+};
+
+void gioop_test(void)
+{
+ const size_t preopen_count = _GIOOP_ENTRY_COUNT(_GIOOP_PREOPEN);
+ const size_t dispatch_count = _GIOOP_ENTRY_COUNT(_GIOOP_DISPATCH);
+
+ assert(_gioop_find_handler(_GIOOP_PREOPEN, preopen_count, "open") ==
+ gioop_open);
+ assert(_gioop_find_handler(_GIOOP_DISPATCH, dispatch_count, "close") ==
+ gioop_close);
+ assert(_gioop_find_handler(_GIOOP_DISPATCH, dispatch_count, "msync") ==
+ _gioop_ignore);
+ assert(_gioop_find_handler(_GIOOP_DISPATCH, dispatch_count, NULL) == NULL);
+ assert(_gioop_find_handler(_GIOOP_DISPATCH, dispatch_count,
+ "definitely_unknown") == NULL);
+}
+
status_e gioop_run(gwriter_s *w, gtask_s *t)
{
status_e ret = SUCCESS;
+ gioop_handler_f handler = NULL;
// There was already an error in the parser (parser.c) processing this
// task! Don't process it futher.
@@ -31,14 +140,11 @@ status_e gioop_run(gwriter_s *w, gtask_s *t)
generate_gprocess_by_realpid(g, t);
// One of the open syscalls may openes a file handle succesfully
- if (Eq(t->op, "open")) {
- Cleanup(gioop_open(w, t, g));
-
- } else if (Eq(t->op, "openat")) {
- Cleanup(gioop_openat(w, t, g));
-
- } else if (Eq(t->op, "creat")) {
- Cleanup(gioop_creat(w, t, g));
+ handler = _gioop_find_handler(_GIOOP_PREOPEN,
+ _GIOOP_ENTRY_COUNT(_GIOOP_PREOPEN),
+ t->op);
+ if (handler != NULL) {
+ Cleanup(handler(w, t, g));
}
// Get the virtual file descriptor of a given real fd and store a pointer
@@ -48,155 +154,15 @@ status_e gioop_run(gwriter_s *w, gtask_s *t)
Cleanup_unless(SUCCESS, ret);
}
-
- if (Eq(t->op, "close")) {
- Cleanup(gioop_close(w, t, g));
-
- } else if (Eq(t->op, "stat")) {
- Cleanup(gioop_stat(w, t, g));
-
- } else if (Eq(t->op, "statfs")) {
- Cleanup(gioop_statfs(w, t, g));
-
- } else if (Eq(t->op, "statfs64")) {
- Cleanup(gioop_statfs64(w, t, g));
-
- } else if (Eq(t->op, "fstat")) {
- Cleanup(gioop_fstat(w, t, g));
-
- } else if (Eq(t->op, "fstatat")) {
- Cleanup(gioop_fstatat(w, t, g));
-
- } else if (Eq(t->op, "fstatfs")) {
- Cleanup(gioop_fstatfs(w, t, g));
-
- } else if (Eq(t->op, "fstatfs64")) {
- Cleanup(gioop_fstatfs64(w, t, g));
-
- } else if (Eq(t->op, "rename")) {
- Cleanup(gioop_rename(w, t, g));
-
- } else if (Eq(t->op, "renameat")) {
- Cleanup(gioop_renameat(w, t, g));
-
- } else if (Eq(t->op, "renameat2")) {
- Cleanup(gioop_renameat2(w, t, g));
-
- } else if (Eq(t->op, "read")) {
- Cleanup(gioop_read(w, t, g));
-
- } else if (Eq(t->op, "readv")) {
- Cleanup(gioop_readv(w, t, g));
-
- } else if (Eq(t->op, "readahead")) {
- Cleanup(gioop_readahead(w, t, g));
-
- } else if (Eq(t->op, "readdir")) {
- Cleanup(gioop_readdir(w, t, g));
-
- } else if (Eq(t->op, "readlink")) {
- Cleanup(gioop_readlink(w, t, g));
-
- } else if (Eq(t->op, "readlinkat")) {
- Cleanup(gioop_readlinkat(w, t, g));
-
- } else if (Eq(t->op, "write")) {
- Cleanup(gioop_write(w, t, g));
-
- } else if (Eq(t->op, "writev")) {
- Cleanup(gioop_writev(w, t, g));
-
- } else if (Eq(t->op, "lseek")) {
- Cleanup(gioop_lseek(w, t, g));
-
- } else if (Eq(t->op, "llseek")) {
- Cleanup(gioop_llseek(w, t, g));
-
- } else if (Eq(t->op, "getdents")) {
- Cleanup(gioop_getdents(w, t, g));
-
- } else if (Eq(t->op, "mkdir")) {
- Cleanup(gioop_mkdir(w, t, g));
-
- } else if (Eq(t->op, "rmdir")) {
- Cleanup(gioop_rmdir(w, t, g));
-
- } else if (Eq(t->op, "mkdirat")) {
- Cleanup(gioop_mkdirat(w, t, g));
-
- } else if (Eq(t->op, "unlink")) {
- Cleanup(gioop_unlink(w, t, g));
-
- } else if (Eq(t->op, "unlinkat")) {
- Cleanup(gioop_unlinkat(w, t, g));
-
- } else if (Eq(t->op, "lstat")) {
- Cleanup(gioop_lstat(w, t, g));
-
- } else if (Eq(t->op, "fsync")) {
- Cleanup(gioop_fsync(w, t, g));
-
- } else if (Eq(t->op, "fdatasync")) {
- Cleanup(gioop_fdatasync(w, t, g));
-
- } else if (Eq(t->op, "sync")) {
- Cleanup(gioop_sync(w, t, g));
-
- } else if (Eq(t->op, "syncfs")) {
- Cleanup(gioop_syncfs(w, t, g));
-
- } else if (Eq(t->op, "sync_file_range")) {
- Cleanup(gioop_sync_file_range(w, t, g));
-
- } else if (Eq(t->op, "fcntl")) {
- Cleanup(gioop_fcntl(w, t, g));
-
- } else if (Eq(t->op, "mmap2")) {
- // Support for mmap added later
-
- } else if (Eq(t->op, "munmap")) {
- // Support for mmap added later
-
- } else if (Eq(t->op, "mremap")) {
- // Support for mmap added later
-
- } else if (Eq(t->op, "msync")) {
- // Support for mmap added later
-
- } else if (Eq(t->op, "chmod")) {
- Cleanup(gioop_chmod(w, t, g));
-
- } else if (Eq(t->op, "fchmodat")) {
- Cleanup(gioop_chmod(w, t, g));
-
- } else if (Eq(t->op, "fchmod")) {
- Cleanup(gioop_fchmod(w, t, g));
-
- } else if (Eq(t->op, "chown")) {
- Cleanup(gioop_chown(w, t, g));
-
- } else if (Eq(t->op, "chown16")) {
- Cleanup(gioop_chown(w, t, g));
-
- } else if (Eq(t->op, "lchown")) {
- Cleanup(gioop_lchown(w, t, g));
-
- } else if (Eq(t->op, "lchown16")) {
- Cleanup(gioop_lchown(w, t, g));
-
- } else if (Eq(t->op, "fchown")) {
- Cleanup(gioop_fchown(w, t, g));
-
- } else if (Eq(t->op, "fchownat")) {
- Cleanup(gioop_chown(w, t, g));
-
- } else if (Eq(t->op, "exit_group")) {
- Cleanup(gioop_exit_group(w, t, g));
-
- } else {
- Cleanup(ERROR;);
+ handler = _gioop_find_handler(_GIOOP_DISPATCH,
+ _GIOOP_ENTRY_COUNT(_GIOOP_DISPATCH),
+ t->op);
+ if (handler != NULL) {
+ Cleanup(handler(w, t, g));
}
+ Cleanup(ERROR);
+
cleanup:
#ifdef LOG_FILTERED
diff --git a/ioriot/src/generate/gioop.h b/ioriot/src/generate/gioop.h
index 1df57c1..2266e09 100644
--- a/ioriot/src/generate/gioop.h
+++ b/ioriot/src/generate/gioop.h
@@ -55,6 +55,7 @@ void gioop_close_all_vfd_cb(void *data, void *data2);
* @return SUCCESS if everything went fine
*/
status_e gioop_run(gwriter_s *w, gtask_s *t);
+void gioop_test(void);
status_e gioop_open(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_openat(gwriter_s *w, gtask_s *t, generate_s *g);
diff --git a/ioriot/src/replay/rioop.c b/ioriot/src/replay/rioop.c
index 5ec64b5..2b3d98c 100644
--- a/ioriot/src/replay/rioop.c
+++ b/ioriot/src/replay/rioop.c
@@ -17,6 +17,16 @@
#include "../vfd.h"
#include "rworker.h"
+typedef void (*rioop_handler_f)(rprocess_s *p, rthread_s *t, rtask_s *task);
+
+typedef struct {
+ int op;
+ rioop_handler_f handler;
+} rioop_entry_s;
+
+#define _RIOOP_ENTRY_COUNT(entries) \
+ (sizeof(entries) / sizeof((entries)[0]))
+
// Printing error messages
#define _Error(...) \
fprintf(stderr, "%s:%d ERROR: ", __FILE__, __LINE__); \
@@ -70,136 +80,111 @@ _rioop_get_pwd(const char *user, struct passwd *pwd, char *buf,
return result;
}
-void rioop_run(rprocess_s *p, rthread_s *t, rtask_s *task)
+static void
+_rioop_noop(rprocess_s *p, rthread_s *t, rtask_s *task)
{
- _Init_op(2);
-
- switch (op) {
- // stat() syscalls
- case FSTAT:
- rioop_fstat(p, t, task);
- break;
- case FSTATFS:
- case FSTATFS64:
- //Error("op(%d) not implemented", op);
- break;
- case FSTAT_AT:
- case LSTAT:
- case STAT:
- rioop_stat(p, t, task);
- break;
- case STATFS:
- case STATFS64:
- //Error("op(%d) not implemented", op);
- break;
-
- // read() syscalls
- case READ:
- case READV:
- rioop_read(p, t, task);
- break;
- case READAHEAD:
- //Error("op(%d) not implemented", op);
- break;
- case READLINK:
- case READLINK_AT:
- //Error("op(%d) not implemented", op);
- break;
-
- // write() syscalls
- case WRITE:
- case WRITEV:
- rioop_write(p, t, task);
- break;
-
- // open() and other syscalls which may creat
- case OPEN:
- case OPEN_AT:
- rioop_open(p, t, task, -1);
- break;
- case CREAT:
- // A call to crat() is equivalent to calling open() with flags..
- rioop_open(p, t, task, O_CREAT|O_WRONLY|O_TRUNC);
- break;
- case MKDIR:
- case MKDIR_AT:
- rioop_mkdir(p, t, task);
- break;
-
- // rename() syscalls
- case RENAME:
- case RENAME_AT:
- case RENAME_AT2:
- rioop_rename(p, t, task);
- break;
+ (void)p;
+ (void)t;
+ (void)task;
+}
- // close() and unlink() syscalls
- case CLOSE:
- rioop_close(p, t, task);
- break;
- case UNLINK:
- case UNLINK_AT:
- rioop_unlink(p, t, task);
- break;
- case RMDIR:
- rioop_rmdir(p, t, task);
- break;
+static void
+_rioop_open_default(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ rioop_open(p, t, task, -1);
+}
- // sync() syscalls
- case FSYNC:
- rioop_fsync(p, t, task);
- break;
- case FDATASYNC:
- rioop_fdatasync(p, t, task);
- break;
- case SYNC:
- case SYNCFS:
- case SYNC_FILE_RANGE:
- //Error("op(%d) not implemented", op);
- break;
+static void
+_rioop_open_creat(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ rioop_open(p, t, task, O_CREAT|O_WRONLY|O_TRUNC);
+}
- // Other syscalls
- case FCNTL:
- rioop_fcntl(p, t, task);
- break;
- case GETDENTS:
- rioop_getdents(p, t, task);
- break;
- case LSEEK:
- case LLSEEK:
- rioop_lseek(p, t, task);
- break;
+static rioop_handler_f
+_rioop_find_handler(const rioop_entry_s *entries, const size_t num_entries,
+ const int op)
+{
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (entries[i].op == op)
+ return entries[i].handler;
+ }
- // chmod() syscalls
- case CHMOD:
- rioop_chmod(p, t, task);
- break;
- case FCHMOD:
- rioop_fchmod(p, t, task);
- break;
+ return NULL;
+}
- // chown() syscalls
- case CHOWN:
- rioop_chown(p, t, task);
- break;
- case FCHOWN:
- case FCHOWNAT:
- rioop_fchown(p, t, task);
- break;
- case LCHOWN:
- rioop_lchown(p, t, task);
- break;
+static const rioop_entry_s _RIOOP_HANDLERS[] = {
+ {FSTAT, rioop_fstat},
+ {FSTATFS, _rioop_noop},
+ {FSTATFS64, _rioop_noop},
+ {FSTAT_AT, rioop_stat},
+ {LSTAT, rioop_stat},
+ {STAT, rioop_stat},
+ {STATFS, _rioop_noop},
+ {STATFS64, _rioop_noop},
+ {READ, rioop_read},
+ {READV, rioop_read},
+ {READAHEAD, _rioop_noop},
+ {READLINK, _rioop_noop},
+ {READLINK_AT, _rioop_noop},
+ {WRITE, rioop_write},
+ {WRITEV, rioop_write},
+ {OPEN, _rioop_open_default},
+ {OPEN_AT, _rioop_open_default},
+ {CREAT, _rioop_open_creat},
+ {MKDIR, rioop_mkdir},
+ {MKDIR_AT, rioop_mkdir},
+ {RENAME, rioop_rename},
+ {RENAME_AT, rioop_rename},
+ {RENAME_AT2, rioop_rename},
+ {CLOSE, rioop_close},
+ {UNLINK, rioop_unlink},
+ {UNLINK_AT, rioop_unlink},
+ {RMDIR, rioop_rmdir},
+ {FSYNC, rioop_fsync},
+ {FDATASYNC, rioop_fdatasync},
+ {SYNC, _rioop_noop},
+ {SYNCFS, _rioop_noop},
+ {SYNC_FILE_RANGE, _rioop_noop},
+ {FCNTL, rioop_fcntl},
+ {GETDENTS, rioop_getdents},
+ {LSEEK, rioop_lseek},
+ {LLSEEK, rioop_lseek},
+ {CHMOD, rioop_chmod},
+ {FCHMOD, rioop_fchmod},
+ {CHOWN, rioop_chown},
+ {FCHOWN, rioop_fchown},
+ {FCHOWNAT, rioop_fchown},
+ {LCHOWN, rioop_lchown},
+ {META_EXIT_GROUP, _rioop_noop},
+ {META_TIMELINE, _rioop_noop},
+};
+
+void rioop_test(void)
+{
+ const size_t handler_count = _RIOOP_ENTRY_COUNT(_RIOOP_HANDLERS);
+
+ assert(_rioop_find_handler(_RIOOP_HANDLERS, handler_count, OPEN) ==
+ _rioop_open_default);
+ assert(_rioop_find_handler(_RIOOP_HANDLERS, handler_count, CREAT) ==
+ _rioop_open_creat);
+ assert(_rioop_find_handler(_RIOOP_HANDLERS, handler_count, READAHEAD) ==
+ _rioop_noop);
+ assert(_rioop_find_handler(_RIOOP_HANDLERS, handler_count, -1) == NULL);
+}
- // Meta operations (I/O replay internal use only).
- case META_EXIT_GROUP:
- break;
- case META_TIMELINE:
- break;
+void rioop_run(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_op(2);
+ rioop_handler_f handler = _rioop_find_handler(_RIOOP_HANDLERS,
+ _RIOOP_ENTRY_COUNT(
+ _RIOOP_HANDLERS),
+ op);
- default:
+ if (handler == NULL) {
Error("op(%d) not implemented", op);
- break;
}
+
+ handler(p, t, task);
}
void rioop_stat(rprocess_s *p, rthread_s *t, rtask_s *task)
diff --git a/ioriot/src/replay/rioop.h b/ioriot/src/replay/rioop.h
index 4db4284..aff2a21 100644
--- a/ioriot/src/replay/rioop.h
+++ b/ioriot/src/replay/rioop.h
@@ -29,6 +29,7 @@
* @param task The replay task object
*/
void rioop_run(rprocess_s *p, rthread_s *t, rtask_s *task);
+void rioop_test(void);
void rioop_close(rprocess_s *p, rthread_s *t, rtask_s *task);
void rioop_fcntl(rprocess_s *p, rthread_s *t, rtask_s *task);
diff --git a/ioriot/src/utests.c b/ioriot/src/utests.c
index 1e332f9..3f573e1 100644
--- a/ioriot/src/utests.c
+++ b/ioriot/src/utests.c
@@ -19,6 +19,8 @@
#include "datas/hmap.h"
#include "datas/list.h"
#include "datas/rbuffer.h"
+#include "generate/gioop.h"
+#include "replay/rioop.h"
#include "replay/replay.h"
#include "utils/utils.h"
@@ -39,6 +41,12 @@ void utests_run()
fprintf(stderr, "Running utils_test()\n");
utils_test();
+ fprintf(stderr, "Running gioop_test()\n");
+ gioop_test();
+
+ fprintf(stderr, "Running rioop_test()\n");
+ rioop_test();
+
fprintf(stderr, "Running replay_test()\n");
replay_test();