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
--- 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, ¶ms, _dbfs_attr_res, req) == NULL)
+ if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, _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, ¶ms);
// query... we can pretend it's a getattr :)
- if (evsql_query_params(ctx->db, NULL, sql_buf, ¶ms, _dbfs_attr_res, req) == NULL)
+ if ((query = evsql_query_params(ctx->db, NULL, sql_buf, ¶ms, _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, ¶ms, dbfs_entry_res, req) == NULL)
+ if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, 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, ¶ms, _dbfs_readlink_res, req) == NULL)
+ if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, _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(¶ms, 0, parent)
|| evsql_param_string(¶ms, 1, name)
- ), EIO))
- goto error;
+ )
+ SERROR(err = EIO);
// query
- if (SETERR(err, evsql_query_params(ctx->db, NULL, sql, ¶ms, dbfs_unlink_res, req) == NULL, EIO))
- goto error;
+ if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, 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, ¶ms, dbfs_entry_res, req) == NULL)
+ if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, 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)