summaryrefslogtreecommitdiff
path: root/src/debug/fast_mutex.h
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2011-05-24 00:38:44 +0300
committerAndrei Karas <akaras@inbox.ru>2011-05-24 00:38:44 +0300
commitd2c42029b98c665725768b891aa877eb3267664f (patch)
treeb232b9a20e45ecb4e7ec2133d7806669054708a6 /src/debug/fast_mutex.h
parentfe39570810969993f51a0ff6045d0a5d4397a5e5 (diff)
downloadmv-d2c42029b98c665725768b891aa877eb3267664f.tar.gz
mv-d2c42029b98c665725768b891aa877eb3267664f.tar.bz2
mv-d2c42029b98c665725768b891aa877eb3267664f.tar.xz
mv-d2c42029b98c665725768b891aa877eb3267664f.zip
Add simple memory leak detector.
Can be enabled by configure option -enable-memdebug=yes. Known issue: not all memory allocations hooked with it.
Diffstat (limited to 'src/debug/fast_mutex.h')
-rw-r--r--src/debug/fast_mutex.h314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/debug/fast_mutex.h b/src/debug/fast_mutex.h
new file mode 100644
index 000000000..a6adb2db3
--- /dev/null
+++ b/src/debug/fast_mutex.h
@@ -0,0 +1,314 @@
+// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+// vim:tabstop=4:shiftwidth=4:expandtab:
+
+/*
+ * Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgement in the product
+ * documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ * This file is part of Stones of Nvwa:
+ * http://sourceforge.net/projects/nvwa
+ *
+ * original version changed for ManaPlus
+ *
+ * Copyright (C) 2011 ManaPlus developers
+ */
+
+/**
+ * @file fast_mutex.h
+ *
+ * A fast mutex implementation for POSIX and Win32.
+ *
+ * @version 1.18, 2005/05/06
+ * @author Wu Yongwei
+ *
+ */
+
+#ifndef _FAST_MUTEX_H
+#define _FAST_MUTEX_H
+
+# if !defined(_NOTHREADS)
+# if !defined(_WIN32THREADS) && \
+ (defined(_WIN32) && defined(_MT))
+// Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC,
+// or -mthreads in MinGW GCC.
+# define _WIN32THREADS
+# elif !defined(_PTHREADS) && \
+ defined(_REENTRANT)
+// Automatically use _PTHREADS when specifying -pthread in GCC.
+// N.B. I do not detect on _PTHREAD_H since libstdc++-v3 under
+// Linux will silently include <pthread.h> anyway.
+# define _PTHREADS
+# endif
+# endif
+
+# if !defined(_PTHREADS) && !defined(_WIN32THREADS) && !defined(_NOTHREADS)
+# define _NOTHREADS
+# endif
+
+# if defined(_NOTHREADS)
+# if defined(_PTHREADS) || defined(_WIN32THREADS)
+# undef _NOTHREADS
+# error "Cannot define multi-threaded mode with -D_NOTHREADS"
+# if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT)
+# error "Be sure to specify -mthreads with -D_WIN32THREADS"
+# endif
+# endif
+# endif
+
+# ifndef _FAST_MUTEX_CHECK_INITIALIZATION
+/**
+ * Macro to control whether to check for initialization status for each
+ * lock/unlock operation. Defining it to a non-zero value will enable
+ * the check, so that the construction/destruction of a static object
+ * using a static fast_mutex not yet constructed or already destroyed
+ * will work (with lock/unlock operations ignored). Defining it to zero
+ * will disable to check.
+ */
+# define _FAST_MUTEX_CHECK_INITIALIZATION 1
+# endif
+
+# if defined(_PTHREADS) && defined(_WIN32THREADS)
+// Some C++ libraries have _PTHREADS defined even on Win32 platforms.
+// Thus this hack.
+# undef _PTHREADS
+# endif
+
+# ifdef _DEBUG
+# include <stdio.h>
+# include <stdlib.h>
+/** Macro for fast_mutex assertions. Real version (for debug mode). */
+# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
+ if (!(_Expr)) { \
+ fprintf(stderr, "fast_mutex::%s\n", _Msg); \
+ abort(); \
+ }
+# else
+/** Macro for fast_mutex assertions. Fake version (for release mode). */
+# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
+ ((void)0)
+# endif
+
+# ifdef _PTHREADS
+# include <pthread.h>
+/**
+ * Macro alias to `volatile' semantics. Here it is truly volatile since
+ * it is in a multi-threaded (POSIX threads) environment.
+ */
+# define __VOLATILE volatile
+ /**
+ * Class for non-reentrant fast mutexes. This is the implementation
+ * for POSIX threads.
+ */
+ class fast_mutex
+ {
+ pthread_mutex_t _M_mtx_impl;
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ bool _M_initialized;
+# endif
+# ifdef _DEBUG
+ bool _M_locked;
+# endif
+ public:
+ fast_mutex()
+# ifdef _DEBUG
+ : _M_locked(false)
+# endif
+ {
+ ::pthread_mutex_init(&_M_mtx_impl, NULL);
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ _M_initialized = true;
+# endif
+ }
+ ~fast_mutex()
+ {
+ _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ _M_initialized = false;
+# endif
+ ::pthread_mutex_destroy(&_M_mtx_impl);
+ }
+ void lock()
+ {
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ if (!_M_initialized)
+ return;
+# endif
+ ::pthread_mutex_lock(&_M_mtx_impl);
+# ifdef _DEBUG
+ // The following assertion should _always_ be true for a
+ // real `fast' pthread_mutex. However, this assertion can
+ // help sometimes, when people forget to use `-lpthread' and
+ // glibc provides an empty implementation. Having this
+ // assertion is also more consistent.
+ _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
+ _M_locked = true;
+# endif
+ }
+ void unlock()
+ {
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ if (!_M_initialized)
+ return;
+# endif
+# ifdef _DEBUG
+ _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
+ _M_locked = false;
+# endif
+ ::pthread_mutex_unlock(&_M_mtx_impl);
+ }
+ private:
+ fast_mutex(const fast_mutex&);
+ fast_mutex& operator=(const fast_mutex&);
+ };
+# endif // _PTHREADS
+
+# ifdef _WIN32THREADS
+# include <windows.h>
+/**
+ * Macro alias to `volatile' semantics. Here it is truly volatile since
+ * it is in a multi-threaded (Win32 threads) environment.
+ */
+# define __VOLATILE volatile
+ /**
+ * Class for non-reentrant fast mutexes. This is the implementation
+ * for Win32 threads.
+ */
+ class fast_mutex
+ {
+ CRITICAL_SECTION _M_mtx_impl;
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ bool _M_initialized;
+# endif
+# ifdef _DEBUG
+ bool _M_locked;
+# endif
+ public:
+ fast_mutex()
+# ifdef _DEBUG
+ : _M_locked(false)
+# endif
+ {
+ ::InitializeCriticalSection(&_M_mtx_impl);
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ _M_initialized = true;
+# endif
+ }
+ ~fast_mutex()
+ {
+ _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ _M_initialized = false;
+# endif
+ ::DeleteCriticalSection(&_M_mtx_impl);
+ }
+ void lock()
+ {
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ if (!_M_initialized)
+ return;
+# endif
+ ::EnterCriticalSection(&_M_mtx_impl);
+# ifdef _DEBUG
+ _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
+ _M_locked = true;
+# endif
+ }
+ void unlock()
+ {
+# if _FAST_MUTEX_CHECK_INITIALIZATION
+ if (!_M_initialized)
+ return;
+# endif
+# ifdef _DEBUG
+ _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
+ _M_locked = false;
+# endif
+ ::LeaveCriticalSection(&_M_mtx_impl);
+ }
+ private:
+ fast_mutex(const fast_mutex&);
+ fast_mutex& operator=(const fast_mutex&);
+ };
+# endif // _WIN32THREADS
+
+# ifdef _NOTHREADS
+/**
+ * Macro alias to `volatile' semantics. Here it is not truly volatile
+ * since it is in a single-threaded environment.
+ */
+# define __VOLATILE
+ /**
+ * Class for non-reentrant fast mutexes. This is the null
+ * implementation for single-threaded environments.
+ */
+ class fast_mutex
+ {
+# ifdef _DEBUG
+ bool _M_locked;
+# endif
+ public:
+ fast_mutex()
+# ifdef _DEBUG
+ : _M_locked(false)
+# endif
+ {
+ }
+ ~fast_mutex()
+ {
+ _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
+ }
+ void lock()
+ {
+# ifdef _DEBUG
+ _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
+ _M_locked = true;
+# endif
+ }
+ void unlock()
+ {
+# ifdef _DEBUG
+ _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
+ _M_locked = false;
+# endif
+ }
+ private:
+ fast_mutex(const fast_mutex&);
+ fast_mutex& operator=(const fast_mutex&);
+ };
+# endif // _NOTHREADS
+
+/** An acquistion-on-initialization lock class based on fast_mutex. */
+class fast_mutex_autolock
+{
+ fast_mutex& _M_mtx;
+public:
+ explicit fast_mutex_autolock(fast_mutex& __mtx) : _M_mtx(__mtx)
+ {
+ _M_mtx.lock();
+ }
+ ~fast_mutex_autolock()
+ {
+ _M_mtx.unlock();
+ }
+private:
+ fast_mutex_autolock(const fast_mutex_autolock&);
+ fast_mutex_autolock& operator=(const fast_mutex_autolock&);
+};
+
+#endif // _FAST_MUTEX_H