commit 97b15a1d7c51764888d2172711e3f3a71fb01916 Author: Nick Mathewson nickm@torproject.org Date: Fri Jun 22 10:30:45 2018 -0400
Extract the locking and logging code
The locking code gets its own module, since it's more fundamental than the higher-level locking code.
Extracting the logging code was the whole point here. :) --- .gitignore | 2 + Makefile.am | 4 ++ src/common/compat_pthreads.c | 80 +--------------------------- src/common/compat_threads.c | 28 ---------- src/common/compat_threads.h | 42 +-------------- src/common/compat_winthreads.c | 27 ---------- src/common/include.am | 2 - src/common/util.c | 51 ------------------ src/common/util.h | 37 ------------- src/include.am | 2 + src/lib/lock/.may_include | 5 ++ src/lib/lock/compat_mutex.c | 34 ++++++++++++ src/lib/lock/compat_mutex.h | 60 +++++++++++++++++++++ src/lib/lock/compat_mutex_pthreads.c | 97 ++++++++++++++++++++++++++++++++++ src/lib/lock/compat_mutex_winthreads.c | 39 ++++++++++++++ src/lib/lock/include.am | 24 +++++++++ src/lib/log/.may_include | 3 ++ src/lib/log/include.am | 19 +++++++ src/lib/log/ratelim.c | 54 +++++++++++++++++++ src/lib/log/ratelim.h | 46 ++++++++++++++++ src/{common/log.c => lib/log/torlog.c} | 24 +++++++-- src/{common => lib/log}/torlog.h | 0 src/rust/build.rs | 1 + 23 files changed, 413 insertions(+), 268 deletions(-)
diff --git a/.gitignore b/.gitignore index 6a48ba275..f141fee17 100644 --- a/.gitignore +++ b/.gitignore @@ -175,6 +175,8 @@ uptime-*.json /src/lib/libtor-err-testing.a /src/lib/libtor-intmath.a /src/lib/libtor-intmath-testing.a +/src/lib/libtor-lock.a +/src/lib/libtor-lock-testing.a /src/lib/libtor-malloc.a /src/lib/libtor-malloc-testing.a /src/lib/libtor-string.a diff --git a/Makefile.am b/Makefile.am index 172ab36f6..b6200c6a2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,6 +40,8 @@ endif # "Common" libraries used to link tor's utility code. TOR_UTIL_LIBS = \ src/common/libor.a \ + src/lib/libtor-log.a \ + src/lib/libtor-lock.a \ src/lib/libtor-container.a \ src/lib/libtor-string.a \ src/lib/libtor-malloc.a \ @@ -52,6 +54,8 @@ TOR_UTIL_LIBS = \ # and tests) TOR_UTIL_TESTING_LIBS = \ src/common/libor-testing.a \ + src/lib/libtor-log-testing.a \ + src/lib/libtor-lock-testing.a \ src/lib/libtor-container-testing.a \ src/lib/libtor-string-testing.a \ src/lib/libtor-malloc-testing.a \ diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c index c2f8609db..c2bde962f 100644 --- a/src/common/compat_pthreads.c +++ b/src/common/compat_pthreads.c @@ -91,83 +91,6 @@ spawn_exit(void) pthread_exit(NULL); }
-/** A mutex attribute that we're going to use to tell pthreads that we want - * "recursive" mutexes (i.e., once we can re-lock if we're already holding - * them.) */ -static pthread_mutexattr_t attr_recursive; - -/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set - * up with tor_mutex_init() or tor_mutex_new(); not both. */ -void -tor_mutex_init(tor_mutex_t *mutex) -{ - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); // LCOV_EXCL_LINE - const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - raw_assert_unreached_msg("Error creating a mutex."); - // LCOV_EXCL_STOP - } -} - -/** As tor_mutex_init, but initialize a mutex suitable that may be - * non-recursive, if the OS supports that. */ -void -tor_mutex_init_nonrecursive(tor_mutex_t *mutex) -{ - int err; - if (!threads_initialized) - tor_threads_init(); // LCOV_EXCL_LINE - err = pthread_mutex_init(&mutex->mutex, NULL); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - raw_assert_unreached_msg("Error creating a mutex."); - // LCOV_EXCL_STOP - } -} - -/** Wait until <b>m</b> is free, then acquire it. */ -void -tor_mutex_acquire(tor_mutex_t *m) -{ - int err; - raw_assert(m); - err = pthread_mutex_lock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - raw_assert_unreached_msg("Error locking a mutex."); - // LCOV_EXCL_STOP - } -} -/** Release the lock <b>m</b> so another thread can have it. */ -void -tor_mutex_release(tor_mutex_t *m) -{ - int err; - raw_assert(m); - err = pthread_mutex_unlock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - raw_assert_unreached_msg("Error unlocking a mutex."); - // LCOV_EXCL_STOP - } -} -/** Clean up the mutex <b>m</b> so that it no longer uses any system - * resources. Does not free <b>m</b>. This function must only be called on - * mutexes from tor_mutex_init(). */ -void -tor_mutex_uninit(tor_mutex_t *m) -{ - int err; - raw_assert(m); - err = pthread_mutex_destroy(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - raw_assert_unreached_msg("Error destroying a mutex."); - // LCOV_EXCL_STOP - } -} /** Return an integer representing this thread. */ unsigned long tor_get_thread_id(void) @@ -328,8 +251,7 @@ void tor_threads_init(void) { if (!threads_initialized) { - pthread_mutexattr_init(&attr_recursive); - pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + tor_locking_init(); const int ret1 = pthread_attr_init(&attr_detached); tor_assert(ret1 == 0); #ifndef PTHREAD_CREATE_DETACHED diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c index 250ac48c0..89214ab1d 100644 --- a/src/common/compat_threads.c +++ b/src/common/compat_threads.c @@ -29,33 +29,6 @@ #include <unistd.h> #endif
-/** Return a newly allocated, ready-for-use mutex. */ -tor_mutex_t * -tor_mutex_new(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init(m); - return m; -} -/** Return a newly allocated, ready-for-use mutex. This one might be - * non-recursive, if that's faster. */ -tor_mutex_t * -tor_mutex_new_nonrecursive(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init_nonrecursive(m); - return m; -} -/** Release all storage and system resources held by <b>m</b>. */ -void -tor_mutex_free_(tor_mutex_t *m) -{ - if (!m) - return; - tor_mutex_uninit(m); - tor_free(m); -} - /** Allocate and return a new condition variable. */ tor_cond_t * tor_cond_new(void) @@ -404,4 +377,3 @@ atomic_counter_exchange(atomic_counter_t *counter, size_t newval) return oldval; } #endif /* !defined(HAVE_STDATOMIC_H) */ - diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h index 19e0a4f11..d1fdfc96c 100644 --- a/src/common/compat_threads.h +++ b/src/common/compat_threads.h @@ -9,54 +9,15 @@ #include "orconfig.h" #include "lib/cc/torint.h" #include "lib/testsupport/testsupport.h" - -#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) -#include <pthread.h> -#endif +#include "lib/lock/compat_mutex.h"
#ifdef HAVE_STDATOMIC_H #include <stdatomic.h> #endif
-#if defined(_WIN32) -#define USE_WIN32_THREADS -#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) -#define USE_PTHREADS -#else -#error "No threading system was found" -#endif /* defined(_WIN32) || ... */ - int spawn_func(void (*func)(void *), void *data); void spawn_exit(void) ATTR_NORETURN;
-/* Because we use threads instead of processes on most platforms (Windows, - * Linux, etc), we need locking for them. On platforms with poor thread - * support or broken gethostbyname_r, these functions are no-ops. */ - -/** A generic lock structure for multithreaded builds. */ -typedef struct tor_mutex_t { -#if defined(USE_WIN32_THREADS) - /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ - CRITICAL_SECTION mutex; -#elif defined(USE_PTHREADS) - /** Pthreads-only: with pthreads, we implement locks with - * pthread_mutex_t. */ - pthread_mutex_t mutex; -#else - /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ - int _unused; -#endif /* defined(USE_WIN32_THREADS) || ... */ -} tor_mutex_t; - -tor_mutex_t *tor_mutex_new(void); -tor_mutex_t *tor_mutex_new_nonrecursive(void); -void tor_mutex_init(tor_mutex_t *m); -void tor_mutex_init_nonrecursive(tor_mutex_t *m); -void tor_mutex_acquire(tor_mutex_t *m); -void tor_mutex_release(tor_mutex_t *m); -void tor_mutex_free_(tor_mutex_t *m); -#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) -void tor_mutex_uninit(tor_mutex_t *m); unsigned long tor_get_thread_id(void); void tor_threads_init(void);
@@ -220,4 +181,3 @@ atomic_counter_exchange(atomic_counter_t *counter, size_t newval) #endif /* defined(HAVE_STDATOMIC_H) */
#endif /* !defined(TOR_COMPAT_THREADS_H) */ - diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c index 807c7b4ae..28981980b 100644 --- a/src/common/compat_winthreads.c +++ b/src/common/compat_winthreads.c @@ -54,33 +54,6 @@ spawn_exit(void) // LCOV_EXCL_STOP }
-void -tor_mutex_init(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} -void -tor_mutex_init_nonrecursive(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} - -void -tor_mutex_uninit(tor_mutex_t *m) -{ - DeleteCriticalSection(&m->mutex); -} -void -tor_mutex_acquire(tor_mutex_t *m) -{ - raw_assert(m); - EnterCriticalSection(&m->mutex); -} -void -tor_mutex_release(tor_mutex_t *m) -{ - LeaveCriticalSection(&m->mutex); -} unsigned long tor_get_thread_id(void) { diff --git a/src/common/include.am b/src/common/include.am index 422397886..d4404fb1b 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -38,7 +38,6 @@ LIBOR_A_SRC = \ src/common/compat_threads.c \ src/common/compat_time.c \ src/common/confline.c \ - src/common/log.c \ src/common/memarea.c \ src/common/util.c \ src/common/util_bug.c \ @@ -94,7 +93,6 @@ COMMONHEADERS = \ src/common/storagedir.h \ src/common/timers.h \ src/common/token_bucket.h \ - src/common/torlog.h \ src/common/util.h \ src/common/util_bug.h \ src/common/util_format.h \ diff --git a/src/common/util.c b/src/common/util.c index 5efbb2bbf..2948e264d 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1310,57 +1310,6 @@ format_time_interval(char *out, size_t out_len, long interval) }
/* ===== - * Rate limiting - * ===== */ - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number - * of calls to rate_limit_is_ready (including this one!) since the last time - * rate_limit_is_ready returned nonzero. Otherwise return 0. - * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning - * about this event and stop counting. */ -static int -rate_limit_is_ready(ratelim_t *lim, time_t now) -{ - if (lim->rate + lim->last_allowed <= now) { - int res = lim->n_calls_since_last_time + 1; - lim->last_allowed = now; - lim->n_calls_since_last_time = 0; - return res; - } else { - if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { - ++lim->n_calls_since_last_time; - } - - return 0; - } -} - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly - * allocated string indicating how many messages were suppressed, suitable to - * append to a log message. Otherwise return NULL. */ -char * -rate_limit_log(ratelim_t *lim, time_t now) -{ - int n; - if ((n = rate_limit_is_ready(lim, now))) { - if (n == 1) { - return tor_strdup(""); - } else { - char *cp=NULL; - const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ - tor_asprintf(&cp, - " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); - return cp; - } - } else { - return NULL; - } -} - -/* ===== * File helpers * ===== */
diff --git a/src/common/util.h b/src/common/util.h index 8f6ec34dc..9936c421d 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -126,43 +126,6 @@ int parse_iso_time_nospace(const char *cp, time_t *t); int parse_http_time(const char *buf, struct tm *tm); int format_time_interval(char *out, size_t out_len, long interval);
-/* Rate-limiter */ - -/** A ratelim_t remembers how often an event is occurring, and how often - * it's allowed to occur. Typical usage is something like: - * - <pre> - if (possibly_very_frequent_event()) { - const int INTERVAL = 300; - static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); - char *m; - if ((m = rate_limit_log(&warning_limit, approx_time()))) { - log_warn(LD_GENERAL, "The event occurred!%s", m); - tor_free(m); - } - } - </pre> - - As a convenience wrapper for logging, you can replace the above with: - <pre> - if (possibly_very_frequent_event()) { - static ratelim_t warning_limit = RATELIM_INIT(300); - log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, - "The event occurred!"); - } - </pre> - */ -typedef struct ratelim_t { - int rate; - time_t last_allowed; - int n_calls_since_last_time; -} ratelim_t; - -#define RATELIM_INIT(r) { (r), 0, 0 } -#define RATELIM_TOOMANY (16*1000*1000) - -char *rate_limit_log(ratelim_t *lim, time_t now); - /* File helpers */ ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket); ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); diff --git a/src/include.am b/src/include.am index d69a2fd01..7eb6c069a 100644 --- a/src/include.am +++ b/src/include.am @@ -8,6 +8,8 @@ include src/lib/crypt_ops/include.am include src/lib/defs/include.am include src/lib/include.libdonna.am include src/lib/intmath/include.am +include src/lib/lock/include.am +include src/lib/log/include.am include src/lib/malloc/include.am include src/lib/string/include.am include src/lib/testsupport/include.am diff --git a/src/lib/lock/.may_include b/src/lib/lock/.may_include new file mode 100644 index 000000000..9522e3af4 --- /dev/null +++ b/src/lib/lock/.may_include @@ -0,0 +1,5 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/lock/*.h +lib/malloc/*.h diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c new file mode 100644 index 000000000..e0f6224a8 --- /dev/null +++ b/src/lib/lock/compat_mutex.c @@ -0,0 +1,34 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" +#include "lib/malloc/util_malloc.h" + +/** Return a newly allocated, ready-for-use mutex. */ +tor_mutex_t * +tor_mutex_new(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init(m); + return m; +} +/** Return a newly allocated, ready-for-use mutex. This one might be + * non-recursive, if that's faster. */ +tor_mutex_t * +tor_mutex_new_nonrecursive(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init_nonrecursive(m); + return m; +} +/** Release all storage and system resources held by <b>m</b>. */ +void +tor_mutex_free_(tor_mutex_t *m) +{ + if (!m) + return; + tor_mutex_uninit(m); + tor_free(m); +} diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h new file mode 100644 index 000000000..92978086a --- /dev/null +++ b/src/lib/lock/compat_mutex.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_MUTEX_H +#define TOR_COMPAT_MUTEX_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) +#include <pthread.h> +#endif + +#if defined(_WIN32) +#include <windows.h> +#endif + +#if defined(_WIN32) +#define USE_WIN32_THREADS +#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) +#define USE_PTHREADS +#else +#error "No threading system was found" +#endif /* defined(_WIN32) || ... */ + +/* Because we use threads instead of processes on most platforms (Windows, + * Linux, etc), we need locking for them. On platforms with poor thread + * support or broken gethostbyname_r, these functions are no-ops. */ + +/** A generic lock structure for multithreaded builds. */ +typedef struct tor_mutex_t { +#if defined(USE_WIN32_THREADS) + /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ + CRITICAL_SECTION mutex; +#elif defined(USE_PTHREADS) + /** Pthreads-only: with pthreads, we implement locks with + * pthread_mutex_t. */ + pthread_mutex_t mutex; +#else + /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ + int _unused; +#endif /* defined(USE_WIN32_MUTEX) || ... */ +} tor_mutex_t; + +tor_mutex_t *tor_mutex_new(void); +tor_mutex_t *tor_mutex_new_nonrecursive(void); +void tor_mutex_init(tor_mutex_t *m); +void tor_mutex_init_nonrecursive(tor_mutex_t *m); +void tor_mutex_acquire(tor_mutex_t *m); +void tor_mutex_release(tor_mutex_t *m); +void tor_mutex_free_(tor_mutex_t *m); +#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) +void tor_mutex_uninit(tor_mutex_t *m); + +void tor_locking_init(void); + +#endif /* !defined(TOR_COMPAT_MUTEX_H) */ diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c new file mode 100644 index 000000000..390da4fb8 --- /dev/null +++ b/src/lib/lock/compat_mutex_pthreads.c @@ -0,0 +1,97 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" +#include "lib/cc/compat_compiler.h" +#include "lib/err/torerr.h" + +/** A mutex attribute that we're going to use to tell pthreads that we want + * "recursive" mutexes (i.e., once we can re-lock if we're already holding + * them.) */ +static pthread_mutexattr_t attr_recursive; +static int attr_initialized = 0; + +void +tor_locking_init(void) +{ + if (!attr_initialized) { + pthread_mutexattr_init(&attr_recursive); + pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + attr_initialized = 1; + } +} + +/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set + * up with tor_mutex_init() or tor_mutex_new(); not both. */ +void +tor_mutex_init(tor_mutex_t *mutex) +{ + if (PREDICT_UNLIKELY(!attr_initialized)) + tor_locking_init(); // LCOV_EXCL_LINE + const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** As tor_mutex_init, but initialize a mutex suitable that may be + * non-recursive, if the OS supports that. */ +void +tor_mutex_init_nonrecursive(tor_mutex_t *mutex) +{ + int err; + if (!attr_initialized) + tor_locking_init(); // LCOV_EXCL_LINE + err = pthread_mutex_init(&mutex->mutex, NULL); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** Wait until <b>m</b> is free, then acquire it. */ +void +tor_mutex_acquire(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_lock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error locking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Release the lock <b>m</b> so another thread can have it. */ +void +tor_mutex_release(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_unlock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error unlocking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Clean up the mutex <b>m</b> so that it no longer uses any system + * resources. Does not free <b>m</b>. This function must only be called on + * mutexes from tor_mutex_init(). */ +void +tor_mutex_uninit(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_destroy(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error destroying a mutex."); + // LCOV_EXCL_STOP + } +} diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c new file mode 100644 index 000000000..c92eb6291 --- /dev/null +++ b/src/lib/lock/compat_mutex_winthreads.c @@ -0,0 +1,39 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" + +void +tor_locking_init(void) +{ +} + +void +tor_mutex_init(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} +void +tor_mutex_init_nonrecursive(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} + +void +tor_mutex_uninit(tor_mutex_t *m) +{ + DeleteCriticalSection(&m->mutex); +} +void +tor_mutex_acquire(tor_mutex_t *m) +{ + raw_assert(m); + EnterCriticalSection(&m->mutex); +} +void +tor_mutex_release(tor_mutex_t *m) +{ + LeaveCriticalSection(&m->mutex); +} diff --git a/src/lib/lock/include.am b/src/lib/lock/include.am new file mode 100644 index 000000000..4e6f44434 --- /dev/null +++ b/src/lib/lock/include.am @@ -0,0 +1,24 @@ + +noinst_LIBRARIES += src/lib/libtor-lock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-lock-testing.a +endif + +src_lib_libtor_lock_a_SOURCES = \ + src/lib/lock/compat_mutex.c + +if THREADS_PTHREADS +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_pthreads.c +endif +if THREADS_WIN32 +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_winthreads.c +endif + +src_lib_libtor_lock_testing_a_SOURCES = \ + $(src_lib_libtor_lock_a_SOURCES) +src_lib_libtor_lock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/lock/compat_mutex.h diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include new file mode 100644 index 000000000..380680640 --- /dev/null +++ b/src/lib/log/.may_include @@ -0,0 +1,3 @@ + +lib/cc/*.h +lib/malloc/*.h diff --git a/src/lib/log/include.am b/src/lib/log/include.am new file mode 100644 index 000000000..f9f327e2d --- /dev/null +++ b/src/lib/log/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-log.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-log-testing.a +endif + +src_lib_libtor_log_a_SOURCES = \ + src/lib/log/ratelim.c \ + src/lib/log/torlog.c + +src_lib_libtor_log_testing_a_SOURCES = \ + $(src_lib_libtor_log_a_SOURCES) +src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/log/ratelim.h \ + src/lib/log/torlog.h diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c new file mode 100644 index 000000000..2d276055b --- /dev/null +++ b/src/lib/log/ratelim.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/log/ratelim.h" +#include "lib/malloc/util_malloc.h" + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number + * of calls to rate_limit_is_ready (including this one!) since the last time + * rate_limit_is_ready returned nonzero. Otherwise return 0. + * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning + * about this event and stop counting. */ +static int +rate_limit_is_ready(ratelim_t *lim, time_t now) +{ + if (lim->rate + lim->last_allowed <= now) { + int res = lim->n_calls_since_last_time + 1; + lim->last_allowed = now; + lim->n_calls_since_last_time = 0; + return res; + } else { + if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { + ++lim->n_calls_since_last_time; + } + + return 0; + } +} + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly + * allocated string indicating how many messages were suppressed, suitable to + * append to a log message. Otherwise return NULL. */ +char * +rate_limit_log(ratelim_t *lim, time_t now) +{ + int n; + if ((n = rate_limit_is_ready(lim, now))) { + if (n == 1) { + return tor_strdup(""); + } else { + char *cp=NULL; + const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; + /* XXXX this is not exactly correct: the messages could have occurred + * any time between the old value of lim->allowed and now. */ + tor_asprintf(&cp, + " [%s%d similar message(s) suppressed in last %d seconds]", + opt_over, n-1, lim->rate); + return cp; + } + } else { + return NULL; + } +} diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h new file mode 100644 index 000000000..efaeb9bf6 --- /dev/null +++ b/src/lib/log/ratelim.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RATELIM_H +#define TOR_RATELIM_H + +/* Rate-limiter */ + +/** A ratelim_t remembers how often an event is occurring, and how often + * it's allowed to occur. Typical usage is something like: + * + <pre> + if (possibly_very_frequent_event()) { + const int INTERVAL = 300; + static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); + char *m; + if ((m = rate_limit_log(&warning_limit, approx_time()))) { + log_warn(LD_GENERAL, "The event occurred!%s", m); + tor_free(m); + } + } + </pre> + + As a convenience wrapper for logging, you can replace the above with: + <pre> + if (possibly_very_frequent_event()) { + static ratelim_t warning_limit = RATELIM_INIT(300); + log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, + "The event occurred!"); + } + </pre> + */ +typedef struct ratelim_t { + int rate; + time_t last_allowed; + int n_calls_since_last_time; +} ratelim_t; + +#define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_TOOMANY (16*1000*1000) + +char *rate_limit_log(ratelim_t *lim, time_t now); + +#endif diff --git a/src/common/log.c b/src/lib/log/torlog.c similarity index 98% rename from src/common/log.c rename to src/lib/log/torlog.c index bb4b1e121..e67442e68 100644 --- a/src/common/log.c +++ b/src/lib/log/torlog.c @@ -29,12 +29,14 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#include "common/util.h" + #define LOG_PRIVATE #include "common/torlog.h" #include "lib/container/smartlist.h" #include "lib/err/torerr.h" +#include "lib/intmath/bits.h" #include "lib/malloc/util_malloc.h" +#include "lib/string/util_string.h" #include "lib/wallclock/tor_gettimeofday.h" #include "lib/wallclock/approx_time.h"
@@ -304,6 +306,22 @@ log_prefix_(char *buf, size_t buf_len, int severity) return n+r; }
+/** Minimal version of write_all, for use by logging. */ +static int +write_all_to_fd(int fd, const char *buf, size_t count) +{ + size_t written = 0; + raw_assert(count < SSIZE_MAX); + + while (written < count) { + ssize_t result = write(fd, buf+written, count-written); + if (result<0) + return -1; + written += result; + } + return 0; +} + /** If lf refers to an actual file that we have just opened, and the file * contains no data, log an "opening new logfile" message at the top. * @@ -337,7 +355,7 @@ log_tor_version(logfile_t *lf, int reset) tor_snprintf(buf+n, sizeof(buf)-n, "Tor %s opening %slog file.\n", VERSION, is_new?"new ":""); } - if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */ + if (write_all_to_fd(lf->fd, buf, strlen(buf)) < 0) /* error */ return -1; /* failed */ return 0; } @@ -551,7 +569,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, lf->callback(severity, domain, msg_after_prefix); } } else { - if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ + if (write_all_to_fd(lf->fd, buf, msg_len) < 0) { /* error */ /* don't log the error! mark this log entry to be blown away, and * continue. */ lf->seems_dead = 1; diff --git a/src/common/torlog.h b/src/lib/log/torlog.h similarity index 100% rename from src/common/torlog.h rename to src/lib/log/torlog.h diff --git a/src/rust/build.rs b/src/rust/build.rs index 03506fe84..8bb9eb295 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -151,6 +151,7 @@ pub fn main() { // moving forward! cfg.component("tor-crypt-ops-testing"); cfg.component("or-testing"); + cfg.component("libtor-lock"); cfg.component("tor-container-testing"); cfg.component("tor-string-testing"); cfg.component("tor-malloc");
tor-commits@lists.torproject.org