touch up the Makefile, define err_t as unsigned int in error.h, and add some preliminary interrupt support, although it will always deadlock due to a bug in libfuse
authorTero Marttila <terom@fixme.fi>
Tue, 18 Nov 2008 01:55:13 +0200
changeset 41 6abda2fa4579
parent 40 03017f5f0087
child 42 40a3b13ffc9d
touch up the Makefile, define err_t as unsigned int in error.h, and add some preliminary interrupt support, although it will always deadlock due to a bug in libfuse
Makefile
src/dbfs/attr.c
src/dbfs/common.c
src/dbfs/dbfs.h
src/dbfs/interrupt.c
src/dbfs/link.c
src/lib/error.h
--- a/Makefile	Wed Oct 22 21:07:17 2008 +0300
+++ b/Makefile	Tue Nov 18 01:55:13 2008 +0200
@@ -5,31 +5,34 @@
 INCLUDE_PATHS = -I${LIBEVENT_PATH}/include -I${LIBFUSE_PATH}/include
 LDLIBS = -levent -lfuse -lpq
 
-# default is TEST
+# default is test
 ifndef MODE
-MODE = TEST
+MODE = test
 endif
 
-ifeq ($(MODE), DEBUG)
+ifeq ($(MODE), debug)
 MODE_CFLAGS = -g -DDEBUG_ENABLED
-else ifeq ($(MODE), DEV)
+else ifeq ($(MODE), dev)
 MODE_CFLAGS = -g
-else ifeq ($(MODE), TEST)
+else ifeq ($(MODE), test)
 MODE_CFLAGS = -g -DINFO_DISABLED
-else ifeq ($(MODE), RELEASE)
+else ifeq ($(MODE), release)
 MODE_CFLAGS = -DINFO_DISABLED -O2
 endif
 
 # XXX: ugh... use `pkg-config fuse`
 DEFINES = -D_FILE_OFFSET_BITS=64
-MY_CFLAGS = -Wall -std=gnu99 $(MODE_CFLAGS)
+FIXED_CFLAGS = -Wall -std=gnu99
 
 BIN_NAMES = helloworld hello simple_hello evpq_test url_test dbfs
 BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
 
+# modules
+module_objs = $(patsubst src/%.c,obj/%.o,$(wildcard src/$(1)/*.c))
+
 # complex modules
-EVSQL_OBJS = obj/evsql/evsql.o obj/evsql/util.o obj/evpq.o
-DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/op_base.o obj/dbfs/trans.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o obj/dbfs/attr.o obj/dbfs/link.o obj/dbfs/tree.o obj/dbfs/mk.o
+EVSQL_OBJS = $(call module_objs,evsql) obj/evpq.o
+DBFS_OBJS = $(call module_objs,dbfs) obj/dirbuf.o 
 
 # first target
 all: ${BIN_PATHS}
@@ -43,9 +46,10 @@
 bin/dbfs: ${DBFS_OBJS} ${EVSQL_OBJS} obj/evfuse.o obj/lib/log.o obj/lib/signals.o
 
 # computed
-LDFLAGS = ${LIBRARY_PATHS} ${LIBRARY_LIST}
-CFLAGSX = ${DEFINES} ${MY_CFLAGS}
-CFLAGS = ${INCLUDE_PATHS} ${CFLAGSX}
+LDFLAGS = ${LIBRARY_PATHS}
+
+CPPFLAGS = ${INCLUDE_PATHS} ${DEFINES}
+CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS}
 
 SRC_PATHS = $(wildcard src/*.c) $(wildcard src/*/*.c)
 SRC_NAMES = $(patsubst src/%,%,$(SRC_PATHS))
--- a/src/dbfs/attr.c	Wed Oct 22 21:07:17 2008 +0300
+++ b/src/dbfs/attr.c	Tue Nov 18 01:55:13 2008 +0200
@@ -50,6 +50,7 @@
 
 void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
     
     (void) fi;
@@ -75,10 +76,11 @@
         SERROR(err = EIO);
         
     // query
-    if (evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_attr_res, req) == NULL)
+    if ((query = evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_attr_res, req)) == NULL)
         SERROR(err = EIO);
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
@@ -91,6 +93,7 @@
 
 void dbfs_setattr (struct fuse_req *req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
     int ret;
     
@@ -160,10 +163,11 @@
     evsql_query_debug(sql_buf, &params);
     
     // query... we can pretend it's a getattr :)
-    if (evsql_query_params(ctx->db, NULL, sql_buf, &params, _dbfs_attr_res, req) == NULL)
+    if ((query = evsql_query_params(ctx->db, NULL, sql_buf, &params, _dbfs_attr_res, req)) == NULL)
         SERROR(err = EIO);
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
--- a/src/dbfs/common.c	Wed Oct 22 21:07:17 2008 +0300
+++ b/src/dbfs/common.c	Tue Nov 18 01:55:13 2008 +0200
@@ -50,7 +50,7 @@
 }
 
 err_t dbfs_check_result (const struct evsql_result_info *res, size_t rows, size_t cols) {
-    int err;
+    err_t err;
 
     // number of rows returned/affected
     size_t nrows = evsql_result_rows(res) ? : evsql_result_affected(res);
--- a/src/dbfs/dbfs.h	Wed Oct 22 21:07:17 2008 +0300
+++ b/src/dbfs/dbfs.h	Tue Nov 18 01:55:13 2008 +0200
@@ -9,6 +9,7 @@
 #include "ops.h"
 #include "../evfuse.h"
 #include "../evsql.h"
+#include "../lib/error.h"
 
 /*
  * Structs and functions shared between all dbfs components
@@ -23,9 +24,6 @@
     struct evfuse *ev_fuse;
 };
 
-// used for error returns
-typedef int err_t;
-
 // XXX: not sure how this should work
 #define CACHE_TIMEOUT 1.0
 
@@ -67,4 +65,43 @@
  */
 int _dbfs_stat_info (struct stat *st, const struct evsql_result_info *res, size_t row, size_t col_offset);
 
+/** interrupt.c 
+ *  
+ * Fuse interrupts are handled using fuse_req_interrupt_func. Calling this registers a callback function with the req,
+ * which may or may not be called either by fuse_req_interrupt_func, or later on via evfuse's event handler. It is
+ * assumed that this will never be called after a call to fuse_reply_*.
+ *
+ * Hence, to handle an interrupt, we must first ensure that fuse_reply_* will not be called afterwards (it'll return
+ * an error), and then we must call fuse_reply_err(req, EINTR).
+ *
+ * In the simplest case, we can simply submit a query, and then abort it once the req is interrupted (now or later).
+ * In the more complicated case, we can check if the request was interrupted, if not, do the query and handle
+ * interrupts.
+ */
+
+/*
+ * Useable as a callback to fuse_req_interrupt_func, will abort the given query and err the req.
+ */
+void dbfs_interrupt_query (struct fuse_req *req, void *query_ptr);
+
+/*
+ * XXX: More complicated state, is this actually needed?
+ */
+struct dbfs_interrupt_ctx {
+    struct fuse_req *req;
+    struct evsql_query *query;
+
+    int interrupted : 1;
+};
+
+/*
+ * Register as a fuse interrupt function for simple requests that only run one query without allocating any resources.
+ *
+ * This will abort the query if the interrupt is run, causing it's callback to not be called.
+ *
+ * Returns nonzero if the request was already interrupted, zero otherwise. Be careful that the interrupt does not get
+ * fired between you checking for it and setting query.
+ */
+int dbfs_interrupt_register (struct fuse_req *req, struct dbfs_interrupt_ctx *ctx);
+
 #endif /* DBFS_DBFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbfs/interrupt.c	Tue Nov 18 01:55:13 2008 +0200
@@ -0,0 +1,37 @@
+
+#include "dbfs.h"
+
+void dbfs_interrupt_query (struct fuse_req *req, void *query_ptr) {
+    struct evsql_query *query = query_ptr;
+    err_t err;
+
+    // abort
+    evsql_query_abort(NULL, query);
+
+    // error the req
+    if ((err = -fuse_reply_err(req, EINTR)))
+        PWARNING("fuse_reply_err", err);
+}
+
+void _dbfs_interrupt_ctx (struct fuse_req *req, void *ctx_ptr) {
+    // dereference ctx
+    struct dbfs_interrupt_ctx *ctx = ctx_ptr;
+    
+    // just cancel query if pending
+    if (ctx->query) {
+        evsql_query_abort(NULL, ctx->query);
+        ctx->query = NULL;
+    }
+
+    // mark as interrupted
+    ctx->interrupted = 1;
+}
+
+int dbfs_interrupt_register (struct fuse_req *req, struct dbfs_interrupt_ctx *ctx) {
+    // initialize
+    ctx->query = NULL;
+    ctx->interrupted = 0;
+
+    // just pass over to fuse_req_interrupt_func
+    fuse_req_interrupt_func(req, _dbfs_interrupt_ctx, ctx);
+}
--- a/src/dbfs/link.c	Wed Oct 22 21:07:17 2008 +0300
+++ b/src/dbfs/link.c	Tue Nov 18 01:55:13 2008 +0200
@@ -52,6 +52,7 @@
 
 void dbfs_lookup (struct fuse_req *req, fuse_ino_t parent, const char *name) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
 
     INFO("[dbfs.lookup] parent=%lu name=%s", parent, name);
@@ -78,10 +79,11 @@
         EERROR(err = EIO, "evsql_param_*");
 
     // query
-    if (evsql_query_params(ctx->db, NULL, sql, &params, dbfs_entry_res, req) == NULL)
+    if ((query = evsql_query_params(ctx->db, NULL, sql, &params, dbfs_entry_res, req)) == NULL)
         EERROR(err = EIO, "evsql_query_params");
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
@@ -130,6 +132,7 @@
 
 void dbfs_readlink (struct fuse_req *req, fuse_ino_t ino) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
     
     INFO("[dbfs.readlink %p] ino=%lu", req, ino);
@@ -153,10 +156,11 @@
         SERROR(err = EIO);
         
     // query
-    if (evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_readlink_res, req) == NULL)
+    if ((query = evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_readlink_res, req)) == NULL)
         SERROR(err = EIO);
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
@@ -194,6 +198,7 @@
 
 void dbfs_unlink (struct fuse_req *req, fuse_ino_t parent, const char *name) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
     
     INFO("[dbfs.unlink %p] parent=%lu, name=%s", req, parent, name);
@@ -211,17 +216,18 @@
     };
 
     // build params
-    if (SETERR(err, (0
+    if (0
         ||  evsql_param_uint32(&params, 0, parent)
         ||  evsql_param_string(&params, 1, name)
-    ), EIO))
-        goto error;
+    )
+        SERROR(err = EIO);
         
     // query
-    if (SETERR(err, evsql_query_params(ctx->db, NULL, sql, &params, dbfs_unlink_res, req) == NULL, EIO))
-        goto error;
+    if ((query = evsql_query_params(ctx->db, NULL, sql, &params, dbfs_unlink_res, req)) == NULL)
+        SERROR(err = EIO);
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
@@ -233,6 +239,7 @@
 
 void dbfs_link (struct fuse_req *req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) {
     struct dbfs *ctx = fuse_req_userdata(req);
+    struct evsql_query *query;
     int err;
     
     INFO("[dbfs.link %p] ino=%lu, newparent=%lu, newname=%s", req, ino, newparent, newname);
@@ -257,10 +264,11 @@
         SERROR(err = EIO);
         
     // query
-    if (evsql_query_params(ctx->db, NULL, sql, &params, dbfs_entry_res, req) == NULL)
+    if ((query = evsql_query_params(ctx->db, NULL, sql, &params, dbfs_entry_res, req)) == NULL)
         SERROR(err = EIO);
 
-    // XXX: handle interrupts
+    // handle interrupts
+    fuse_req_interrupt_func(req, dbfs_interrupt_query, query);
     
     // wait
     return;
--- a/src/lib/error.h	Wed Oct 22 21:07:17 2008 +0300
+++ b/src/lib/error.h	Tue Nov 18 01:55:13 2008 +0200
@@ -3,6 +3,11 @@
 
 #include "log.h"
 
+/*
+ * err_t is always positive
+ */
+typedef unsigned int err_t;
+
 #define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0)
 #define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0)
 #define EERROR(_err, ...) do { eerr_func(__func__, (_err), __VA_ARGS__); goto error; } while (0)