@@ -1,10 +1,11 @@ #define FUSE_USE_VERSION 26 #include #include #include +#include #include #include #include #include #include @@ -51,10 +52,15 @@ */ pthread_mutex_t appfs_path_info_cache_mutex = PTHREAD_MUTEX_INITIALIZER; int appfs_path_info_cache_size = 8209; struct appfs_pathinfo *appfs_path_info_cache = NULL; +/* + * Global variables for AppFS Tcl Interpreter restarting + */ +int interp_reset_key = 0; + /* * AppFS Path Type: Describes the type of path a given file is */ typedef enum { APPFS_PATHTYPE_INVALID, @@ -248,12 +254,21 @@ * Return the thread-specific Tcl interpreter, creating it if needed */ static Tcl_Interp *appfs_TclInterp(void) { Tcl_Interp *interp; int pthread_ret; + static __thread int thread_interp_reset_key = 0; interp = pthread_getspecific(interpKey); + if (interp != NULL && thread_interp_reset_key != interp_reset_key) { + APPFS_DEBUG("Terminating old interpreter and restarting due to reset request."); + + Tcl_DeleteInterp(interp); + + interp = NULL; + } + if (interp == NULL) { interp = appfs_create_TclInterp(NULL); if (interp == NULL) { return(NULL); @@ -309,10 +324,21 @@ APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0)); } return(retval); } + +/* + * Request all Tcl interpreters restart + */ +static void appfs_tcl_ResetInterps(void) { + APPFS_DEBUG("Requesting reset of all interpreters."); + + __sync_add_and_fetch(&interp_reset_key, 1); + + return; +} /* * Determine the UID for the user making the current FUSE filesystem request. * This will be used to lookup the user's home directory so we can search for * locally modified files. @@ -555,10 +581,12 @@ } static void appfs_get_path_info_cache_flush(uid_t uid, int new_size) { unsigned int idx; int pthread_ret; + + APPFS_DEBUG("Flushing AppFS cache (uid = %lli, new_size = %i)", (long long) uid, new_size); pthread_ret = pthread_mutex_lock(&appfs_path_info_cache_mutex); if (pthread_ret != 0) { APPFS_DEBUG("Unable to lock path_info cache mutex !"); @@ -1429,10 +1457,37 @@ Tcl_PkgProvide(interp, "appfsd", "1.0"); return(TCL_OK); } + +/* + * Hot-restart support + */ +/* Initiate a hot-restart */ +static void appfs_hot_restart(void) { + appfs_tcl_ResetInterps(); + appfs_get_path_info_cache_flush(-1, -1); + + return; +} + +/* + * Signal handler to initiate a hot-restart + */ +static void appfs_signal_handler(int sig) { + /* Do not handle signals until FUSE has been started */ + if (!appfs_fuse_started) { + return; + } + + if (sig == SIGHUP) { + appfs_hot_restart(); + } + + return; +} /* * FUSE operations structure */ static struct fuse_operations appfs_operations = { @@ -1475,10 +1530,11 @@ int main(int argc, char **argv) { Tcl_Interp *test_interp; char *test_interp_error; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); int pthread_ret; + void *signal_ret; /* * Skip passed program name */ if (argc == 0 || argv == NULL) { @@ -1561,10 +1617,19 @@ fprintf(stderr, "%s\n", test_interp_error); return(1); } Tcl_DeleteInterp(test_interp); + + /* + * Register a signal handler for hot-restart requests + */ + signal_ret = signal(SIGHUP, appfs_signal_handler); + if (signal_ret == SIG_ERR) { + fprintf(stderr, "Unable to install signal handler for hot-restart\n"); + fprintf(stderr, "Hot-restart will not be available.\n"); + } /* * Add FUSE arguments which we always supply */ fuse_opt_parse(&args, NULL, NULL, appfs_fuse_opt_cb);