@@ -2,10 +2,11 @@ #include #include #include #include +#include #include #include #include #include #include @@ -119,10 +120,12 @@ *error_string = strdup("Unable to create Tcl interpreter."); } return(NULL); } + + Tcl_Preserve(interp); tcl_ret = Tcl_Init(interp); if (tcl_ret != TCL_OK) { fprintf(stderr, "Unable to initialize Tcl. Aborting.\n"); fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); @@ -129,10 +132,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -143,10 +150,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -157,10 +168,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -176,10 +191,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -197,10 +216,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -212,10 +235,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -230,10 +257,14 @@ if (error_string) { *error_string = strdup(Tcl_GetStringResult(interp)); } + Tcl_Release(interp); + + APPFS_DEBUG("Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } @@ -241,10 +272,17 @@ * Hide some Tcl commands that we do not care to use and which may * slow down run-time operations. */ Tcl_HideCommand(interp, "auto_load_index", "auto_load_index"); Tcl_HideCommand(interp, "unknown", "unknown"); + Tcl_HideCommand(interp, "exit", "exit"); + + /* + * Release the hold we have on the interpreter so that it may be + * deleted if needed + */ + Tcl_Release(interp); /* * Return the completely initialized interpreter */ return(interp); @@ -267,12 +305,14 @@ Tcl_DeleteInterp(interp); interp = NULL; - thread_interp_reset_key = global_interp_reset_key; + pthread_ret = pthread_setspecific(interpKey, interp); } + + thread_interp_reset_key = global_interp_reset_key; if (interp == NULL) { interp = appfs_create_TclInterp(NULL); if (interp == NULL) { @@ -279,10 +319,12 @@ return(NULL); } pthread_ret = pthread_setspecific(interpKey, interp); if (pthread_ret != 0) { + APPFS_DEBUG("pthread_setspecific() failed. Terminating Tcl interpreter."); + Tcl_DeleteInterp(interp); return(NULL); } } @@ -453,24 +495,28 @@ /* * Generate an inode for a given path. The inode should be computed in such * a way that it is unlikely to be duplicated and remains the same for a given * file */ +#if UINT_MAX < 4294967295 +#error Integer size is too small +#endif static long long appfs_get_path_inode(const char *path) { - long long retval; + int retval; const char *p; retval = 10; for (p = path; *p; p++) { retval %= 4290960290ULL; retval += *p; - retval <<= 7; + retval <<= 6; } retval += 10; - retval %= 4294967296ULL; + retval %= 4294967286ULL; + retval += 10; return(retval); } /* @@ -642,12 +688,15 @@ Tcl_WideInt attr_value_wide; int attr_value_int; static __thread Tcl_Obj *attr_key_type = NULL, *attr_key_perms = NULL, *attr_key_size = NULL, *attr_key_time = NULL, *attr_key_source = NULL, *attr_key_childcount = NULL, *attr_key_packaged = NULL; int cache_ret; int tcl_ret; + uid_t fsuid; - cache_ret = appfs_get_path_info_cache_get(path, appfs_get_fsuid(), pathinfo); + fsuid = appfs_get_fsuid(); + + cache_ret = appfs_get_path_info_cache_get(path, fsuid, pathinfo); if (cache_ret == 0) { if (pathinfo->type == APPFS_PATHTYPE_DOES_NOT_EXIST) { return(-ENOENT); } @@ -670,11 +719,11 @@ APPFS_DEBUG("::appfs::getattr(%s) failed.", path); APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); pathinfo->type = APPFS_PATHTYPE_DOES_NOT_EXIST; - appfs_get_path_info_cache_add(path, appfs_get_fsuid(), pathinfo); + appfs_get_path_info_cache_add(path, fsuid, pathinfo); Tcl_Release(interp); return(-ENOENT); } @@ -789,11 +838,11 @@ pathinfo->time = 0; } Tcl_Release(interp); - appfs_get_path_info_cache_add(path, appfs_get_fsuid(), pathinfo); + appfs_get_path_info_cache_add(path, fsuid, pathinfo); return(0); } static char *appfs_prepare_to_create(const char *path) { @@ -1543,10 +1592,33 @@ appfs_hot_restart(); } return; } + +/* + * Terminate a thread + */ +static void appfs_terminate_interp(void *_interp) { + Tcl_Interp *interp; + + APPFS_DEBUG("Called: _interp = %p", _interp); + + if (_interp == NULL) { + APPFS_DEBUG("Terminating thread with no interpreter"); + + return; + } + + interp = _interp; + + APPFS_DEBUG("Terminating interpreter due to thread termination"); + + Tcl_DeleteInterp(interp); + + return; +} /* * FUSE operations structure */ static struct fuse_operations appfs_operations = { @@ -1624,11 +1696,11 @@ /* * Create a thread-specific-data (TSD) key for each thread to refer * to its own Tcl interpreter. Tcl interpreters must be unique per * thread and new threads are dynamically created by FUSE. */ - pthread_ret = pthread_key_create(&interpKey, NULL); + pthread_ret = pthread_key_create(&interpKey, appfs_terminate_interp); if (pthread_ret != 0) { fprintf(stderr, "Unable to create TSD key for Tcl. Aborting.\n"); return(1); }