diff options
author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_subr/error.c | |
parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) |
Diffstat (limited to 'subversion/libsvn_subr/error.c')
-rw-r--r-- | subversion/libsvn_subr/error.c | 111 |
1 files changed, 96 insertions, 15 deletions
diff --git a/subversion/libsvn_subr/error.c b/subversion/libsvn_subr/error.c index ffb2495f4cc51..1b2e7357e1fae 100644 --- a/subversion/libsvn_subr/error.c +++ b/subversion/libsvn_subr/error.c @@ -28,6 +28,10 @@ #include <apr_pools.h> #include <apr_strings.h> +#if defined(SVN_DEBUG) && APR_HAS_THREADS +#include <apr_thread_proc.h> +#endif + #include <zlib.h> #ifndef SVN_ERR__TRACING @@ -38,12 +42,57 @@ #include "svn_pools.h" #include "svn_utf.h" +#include "private/svn_error_private.h" +#include "svn_private_config.h" + +#if defined(SVN_DEBUG) && APR_HAS_THREADS +#include "private/svn_atomic.h" +#include "pools.h" +#endif + + #ifdef SVN_DEBUG -/* XXX FIXME: These should be protected by a thread mutex. - svn_error__locate and make_error_internal should cooperate - in locking and unlocking it. */ +# if APR_HAS_THREADS +static apr_threadkey_t *error_file_key = NULL; +static apr_threadkey_t *error_line_key = NULL; + +/* No-op destructor for apr_threadkey_private_create(). */ +static void null_threadkey_dtor(void *stuff) {} + +/* Implements svn_atomic__str_init_func_t. + Callback used by svn_error__locate to initialize the thread-local + error location storage. This function will never return an + error string. */ +static const char * +locate_init_once(void *ignored_baton) +{ + /* Strictly speaking, this is a memory leak, since we're creating an + unmanaged, top-level pool and never destroying it. We do this + because this pool controls the lifetime of the thread-local + storage for error locations, and that storage must always be + available. */ + apr_pool_t *threadkey_pool = svn_pool__create_unmanaged(TRUE); + apr_status_t status; -/* XXX TODO: Define mutex here #if APR_HAS_THREADS */ + status = apr_threadkey_private_create(&error_file_key, + null_threadkey_dtor, + threadkey_pool); + if (status == APR_SUCCESS) + status = apr_threadkey_private_create(&error_line_key, + null_threadkey_dtor, + threadkey_pool); + + /* If anything went wrong with the creation of the thread-local + storage, we'll revert to the old, thread-agnostic behaviour */ + if (status != APR_SUCCESS) + error_file_key = error_line_key = NULL; + + return NULL; +} +# endif /* APR_HAS_THREADS */ + +/* These location variables will be used in no-threads mode or if + thread-local storage is not available. */ static const char * volatile error_file = NULL; static long volatile error_line = -1; @@ -51,9 +100,6 @@ static long volatile error_line = -1; static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>"; #endif /* SVN_DEBUG */ -#include "svn_private_config.h" -#include "private/svn_error_private.h" - /* * Undefine the helpers for creating errors. @@ -76,11 +122,25 @@ static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>"; void svn_error__locate(const char *file, long line) { -#if defined(SVN_DEBUG) - /* XXX TODO: Lock mutex here */ +#ifdef SVN_DEBUG +# if APR_HAS_THREADS + static volatile svn_atomic_t init_status = 0; + svn_atomic__init_once_no_error(&init_status, locate_init_once, NULL); + + if (error_file_key && error_line_key) + { + apr_status_t status; + status = apr_threadkey_private_set((char*)file, error_file_key); + if (status == APR_SUCCESS) + status = apr_threadkey_private_set((void*)line, error_line_key); + if (status == APR_SUCCESS) + return; + } +# endif /* APR_HAS_THREADS */ + error_file = file; error_line = line; -#endif +#endif /* SVN_DEBUG */ } @@ -103,6 +163,9 @@ make_error_internal(apr_status_t apr_err, { apr_pool_t *pool; svn_error_t *new_error; +#ifdef SVN_DEBUG + apr_status_t status = APR_ENOTIMPL; +#endif /* Reuse the child's pool, or create our own. */ if (child) @@ -121,16 +184,34 @@ make_error_internal(apr_status_t apr_err, new_error->apr_err = apr_err; new_error->child = child; new_error->pool = pool; -#if defined(SVN_DEBUG) - new_error->file = error_file; - new_error->line = error_line; - /* XXX TODO: Unlock mutex here */ + +#ifdef SVN_DEBUG +#if APR_HAS_THREADS + if (error_file_key && error_line_key) + { + void *item; + status = apr_threadkey_private_get(&item, error_file_key); + if (status == APR_SUCCESS) + { + new_error->file = item; + status = apr_threadkey_private_get(&item, error_line_key); + if (status == APR_SUCCESS) + new_error->line = (long)item; + } + } +# endif /* APR_HAS_THREADS */ + + if (status != APR_SUCCESS) + { + new_error->file = error_file; + new_error->line = error_line; + } if (! child) apr_pool_cleanup_register(pool, new_error, err_abort, apr_pool_cleanup_null); -#endif +#endif /* SVN_DEBUG */ return new_error; } |