From 8c6ba0e0587b4b28044385da90af408d72a0da01 Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Tue, 22 May 2007 19:25:59 +0000 Subject: [PATCH] Fixed bug #1721186: thread-safe reference counting. --- ChangeLog | 5 + SConstruct | 12 +- m4/acx_pthread.m4 | 235 ++++++++++++++ m4/ost_pthread.m4 | 582 ++++++++++++++++++++++++++++++++++ src/object.cpp | 4 +- src/utility/smartPtr.cpp | 131 +------- src/utility/smartPtrInt.cpp | 301 ++++++++++++++++++ vmime/utility/smartPtr.hpp | 60 ++-- vmime/utility/smartPtrInt.hpp | 107 +++++++ 9 files changed, 1266 insertions(+), 171 deletions(-) create mode 100644 m4/acx_pthread.m4 create mode 100644 m4/ost_pthread.m4 create mode 100644 src/utility/smartPtrInt.cpp create mode 100644 vmime/utility/smartPtrInt.hpp diff --git a/ChangeLog b/ChangeLog index c603d3c3..14111224 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ VERSION 0.8.2cvs ================ +2007-05-22 Vincent Richard + + * Implemented thread-safe reference counting for smart pointers, + whenever possible (GCC built-in functions / pthread / Win32). + 2007-03-28 Vincent Richard * SMTPTransport.cpp: better parsing of ESMTP extensions. diff --git a/SConstruct b/SConstruct index b5020601..cc098b85 100644 --- a/SConstruct +++ b/SConstruct @@ -151,6 +151,7 @@ libvmime_sources = [ 'utility/progressListener.cpp', 'utility/progressListener.hpp', 'utility/random.cpp', 'utility/random.hpp', 'utility/smartPtr.cpp', 'utility/smartPtr.hpp', + 'utility/smartPtrInt.cpp', 'utility/smartPtrInt.hpp', 'utility/stream.cpp', 'utility/stream.hpp', 'utility/stringProxy.cpp', 'utility/stringProxy.hpp', 'utility/stringUtils.cpp', 'utility/stringUtils.hpp', @@ -634,6 +635,8 @@ if env['with_tls'] == 'yes': env.ParseConfig('pkg-config --cflags --libs ' + libgnutls_pc) +env.Append(CXXFLAGS = ['-pthread']) + # Generate help text for command line options Help(opts.GenerateHelpText(env)) @@ -860,6 +863,7 @@ config_hpp.write(""" // Additional defines #define VMIME_HAVE_GETADDRINFO 1 +#define VMIME_HAVE_PTHREAD 1 #endif // VMIME_CONFIG_HPP_INCLUDED @@ -961,7 +965,7 @@ Default(libVmime) if env['build_tests'] == 'yes': if env['debug'] == 'yes': env = env.Copy() - env.Append(LIBS = ['cppunit', 'dl', packageVersionedGenericName + '-debug']) + env.Append(LIBS = ['cppunit', 'dl', packageVersionedGenericName + '-debug', 'pthread']) env.Append(LIBPATH=['.']) Default( env.Program( @@ -1320,6 +1324,8 @@ AM_PROG_CC_C_O AM_ICONV +OST_LIB_PTHREAD # from GNU Commons C++ + # # Some checks @@ -1713,6 +1719,10 @@ if test "x$VMIME_DETECT_PLATFORM" = "xposix"; then AC_CHECK_FUNC(getaddrinfo, [VMIME_ADDITIONAL_DEFINES="$VMIME_ADDITIONAL_DEFINES HAVE_GETADDRINFO"]) fi +# -- pthreads (POSIX) + +ACX_PTHREAD([VMIME_ADDITIONAL_DEFINES="$VMIME_ADDITIONAL_DEFINES HAVE_PTHREAD"]) + """) diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4 new file mode 100644 index 00000000..b7f692a9 --- /dev/null +++ b/m4/acx_pthread.m4 @@ -0,0 +1,235 @@ +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2005-01-14 +dnl @license GPLWithACException + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/m4/ost_pthread.m4 b/m4/ost_pthread.m4 new file mode 100644 index 00000000..d427c735 --- /dev/null +++ b/m4/ost_pthread.m4 @@ -0,0 +1,582 @@ +dnl Copyright (C) 1999-2001 Open Source Telecom Corporation. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +AC_DEFUN([OST_LIB_PTHREAD], +[ + AC_REQUIRE([OST_SYS_POSIX]) + AC_REQUIRE([OST_CC_SYSTIME]) + THREAD_FLAGS="" + THREAD_LIBS="" + ost_cv_thread_library="none" + ost_cv_rt_library="none" + ost_cv_cxx_mode=false + + AC_ARG_WITH(pthread, [ --with-pthread[=lib] using specified pthread library], + [if test "$withval" != "" ; then ost_cv_thread_library=$withval ; fi] + ) + + AC_ARG_WITH(linuxthreads, [ --with-linuxthreads use linux kernel mode library], + [ost_cv_thread_library=lthread + AC_DEFINE(WITH_LINUXTHREADS, [1], [bsd system using linuxthreads]) + if test "$withval" != "yes" ; then + THREAD_FLAGS="-D__USE_GNU -D__USE_UNIX98 -I$withval $THREAD_FLAGS" + CFLAGS="-D__USE_GNU -D__USE_UNIX98 -I$withval $CFLAGS" + else + THREAD_FLAGS="-D__USE_GNU -D__USE_UNIX98 -I/usr/local/include/pthread/linuxthreads $THREAD_FLAGS" + CFLAGS="-D__USE_GNU -D__USE_UNIX98 -I/usr/local/include/pthread/linuxthreads $CFLAGS" + fi + ]) + + AC_CHECK_HEADERS(pthread.h, [ + AC_DEFINE(HAVE_PTHREAD_H, [1], [posix thread header]) + ost_cv_posix_threads=yes], + ost_cv_posix_threads=no) + + if test $ost_cv_posix_threads = no ; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -pthread" + AC_TRY_COMPILE([#include ],[], + AC_DEFINE(HAVE_PTHREAD_H, [1]) + ost_cv_cxx_mode=true + ost_cv_posix_threads=yes) + CXXFLAGS="$SAVE_CXXFLAGS" + AC_LANG_RESTORE + fi + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + + ost_cv_posix_atomic=no + AC_CHECK_HEADERS(sys/atomic_op.h,[ + AC_DEFINE(HAVE_ATOMIC_AIX, [1], [atomic aix operations]) + ]) + AC_CHECK_HEADERS([sys/atomic.h], + ost_cv_posix_sys_atomic=yes, + ost_cv_posix_sys_atomic=no) + if test $ost_cv_posix_sys_atomic = yes ; then + AC_MSG_CHECKING([for atomic_t]) + AC_TRY_COMPILE([#include ], + [ + atomic_t at; at.counter = 1; + atomic_dec_and_test(&at); + atomic_sub(4, &at); + atomic_inc(&at); + atomic_add(3, &at); + ], + [ost_cv_posix_atomic=yes + AC_DEFINE(HAVE_WORKING_SYS_ATOMIC_H, [1], [has usable atomic functions])], + [ost_cv_posix_atomic=no]) + AC_MSG_RESULT($ost_cv_posix_atomic) + fi + + dnl check for gcc's bits/atomicity and the atomic functions therein + AC_CHECK_HEADERS([bits/atomicity.h], + ost_cv_bits_atomicity=yes, + ost_cv_bits_atomicity=no) + if test $ost_cv_bits_atomicity = yes ; then + AC_MSG_CHECKING([for _Atomic_word]) + AC_TRY_COMPILE([#include ], + [ + _Atomic_word i = 0; + __atomic_add(&i, 1); + __exchange_and_add(&i, 1); + ], + [ost_cv_gcc_atomic=yes + AC_DEFINE(HAVE_GCC_BITS_ATOMIC, [1], [has gcc atomic functions])], + [ost_cv_gcc_atomic=no]) + AC_MSG_RESULT($ost_cv_gcc_atomic) + + AC_MSG_CHECKING([for __gnu_cxx::_Atomic_word]) + AC_TRY_COMPILE([#include ], + [ + using namespace __gnu_cxx; + _Atomic_word i = 0; + __atomic_add(&i, 1); + __exchange_and_add(&i, 1); + ], + [ost_cv_gcc_cxx_atomic=yes + AC_DEFINE(HAVE_GCC_CXX_BITS_ATOMIC, [1], + [has __gnu_cxx atomic functions])], + [ost_cv_gcc_cxx_atomic=no]) + AC_MSG_RESULT($ost_cv_gcc_cxx_atomic) + fi + +AC_LANG_RESTORE + + if test "$target" = NONE ; then + targetdir="" + else + targetdir="$target" + fi + + AC_CHECK_HEADERS(thread.h) + if test "$prefix" = NONE ; then + thrprefix="/usr/$targetdir/include" + if test -d /usr/$targetdir/sys-include ; then + thrprefix="$prefix/$targetdir/sys-include" ; fi + else + thrprefix="$prefix/$targetdir/include" + if test -d "$prefix/$targetdir/sys-include" ; then + thrprefix="$prefix/$targetdir/sys-include" ; fi + fi + + if test ! -f $thrprefix/thread.h ; then + thrprefix=/usr/include + fi + + AC_SUBST(thrprefix) + + if test $ost_cv_posix_threads = yes ; then + if test "$ost_cv_thread_library" = "none" ; then + + ost_cv_thread_flags="" + for flags in -kthread -pthread -mthreads -pthreads -Kthread --threadsafe -mt ; do + + AC_MSG_CHECKING(whether ${CC-cc} accepts $flags) + echo 'void f(){}' >conftest.c + if test -z "`${CC-cc} $flags -c conftest.c 2>&1`"; then + ost_cv_thread_flags=$flags + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + rm -f conftest* + if test ! -z "$ost_cv_thread_flags" ; then break ; fi + done +# if test "$ost_cv_prog_cc_pthread" = "no" ; then +# AC_CACHE_CHECK(whether ${CC-cc} accepts -mthreads, +# ost_cv_prog_cc_mthreads, +# [echo 'void f(){}' >conftest.c +# if test -z "`${CC-cc} -mthreads -c conftest.c 2>&1`"; then +# ost_cv_prog_cc_mthreads=yes +# else +# ost_cv_prog_cc_mthreads=no +# fi +# rm -f conftest* +# ]) +# fi + ost_cv_thread_library=none + AC_CHECK_LIB(pthread, pthread_self, + ost_cv_thread_library=pthread, + AC_CHECK_LIB(c_r, pthread_self, + ost_cv_thread_library=c_r, + AC_CHECK_LIB(pthread, pthread_kill, + ost_cv_thread_library=pthread, + AC_CHECK_LIB(pthreads, pthread_self, + ost_cv_thread_library=pthreads, + AC_CHECK_LIB(thread, pthread_self, + ost_cv_thread_library=thread))))) + + if test $ost_cv_thread_library = none ; then + AC_CHECK_LIB(gthreads, pthread_self,[ + AC_CHECK_LIB(malloc, malloc) + ost_cv_thread_library=gthreads]) + fi + if test $ost_cv_thread_library = none ; then + AC_CHECK_LIB(cma, pthread_self, + ost_cv_thread_library=cma) + fi + + if test $ost_cv_thread_library = none ; then + AC_CHECK_LIB(c, pthread_self, + ost_cv_thread_library=c) + fi + + if test $ost_cv_thread_library = none ; then + AC_MSG_ERROR(no library for posix threads found!) + fi + else +# ost_cv_prog_cc_pthread=no +# ost_cv_prog_cc_mthreads=no + ost_cv_thread_flags="" + fi + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_mach_thread_np, + AC_DEFINE(HAVE_PTHREAD_MACH_THREAD_NP, [1], [has mach link]) + ) + + AC_CHECK_LIB(${ost_cv_thread_library}, nanosleep, + AC_DEFINE(HAVE_PTHREAD_NANOSLEEP, [1], [has nanosleep]),[ + AC_CHECK_LIB(posix4, nanosleep,[ + AC_DEFINE(HAVE_PTHREAD_NANOSLEEP, [1]) + THREAD_LIBS="$THREAD_LIBS -lposix4" + ],[ + AC_CHECK_LIB(rt, nanosleep,[ + AC_DEFINE(HAVE_PTHREAD_NANOSLEEP, [1]) + ost_cv_rt_library="-lrt"]) + ]) + + ]) + + AC_CHECK_LIB(rt, clock_gettime,[ + ost_cv_rt_library="-lrt" + AC_DEFINE(HAVE_HIRES_TIMER, [1], [have hires]) + ],[ + AC_CHECK_FUNCS(clock_gettime,[ + AC_DEFINE(HAVE_HIRES_TIMER, [1], [have hires]) + ]) + ]) + + AC_CHECK_LIB(rt, mlockall,[ + AC_DEFINE(HAVE_MLOCK, [1], [have mlock]) + AC_DEFINE(HAVE_MLOCKALL, [1], [have memlockall]) + ost_cv_rt_library="-lrt"], + [ + AC_CHECK_FUNCS(mlock) + AC_CHECK_FUNCS(mlockall) + ]) + + if test "$ost_cv_rt_library" != "none" ; then + THREAD_LIBS="$THREAD_LIBS $ost_cv_rt_library" ; fi + + if test ! -z "$ost_cv_thread_flags" ; then + THREAD_LIBS="$THREAD_LIBS $ost_cv_thread_flags" + else + THREAD_LIBS="$THREAD_LIBS -l$ost_cv_thread_library" + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + THREAD_FLAGS="$flag" + fi + + AC_SUBST(THREAD_FLAGS) + AC_SUBST(THREAD_LIBS) +# LIBS="$THREAD_LIBS $LIBS" + if test "$ost_cv_thread_library" != "lthread" ; then + AC_CHECK_HEADERS(pthread_np.h) + fi + AC_CHECK_HEADERS(semaphore.h) + AC_CHECK_HEADERS(sched.h) + AC_CHECK_HEADERS(sys/sched.h) + AC_CHECK_FUNCS(sched_getscheduler) + AC_CACHE_CHECK([for recursive mutex type support], ost_cv_mutex_recursive, + [ + ost_cv_mutex_recursive="none" + + if test "$ost_cv_cxx_mode" = true ; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -pthread" + fi + + AC_TRY_COMPILE( + [#include ], + [ + #ifndef PTHREAD_MUTEXTYPE_RECURSIVE + #ifdef PTHREAD_MUTEX_RECURSIVE + #define PTHREAD_MUTEXTYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE + #endif + #endif + return (int)PTHREAD_MUTEXTYPE_RECURSIVE; + ], + ost_cv_mutex_recursive="portable", + [ + AC_EGREP_HEADER(PTHREAD_MUTEXTYPE_RECURSIVE_NP,pthread.h, + ost_cv_mutex_recursive=non-portable) + AC_EGREP_HEADER(PTHREAD_MUTEX_RECURSIVE_INITIALIZER_NP, pthread.h, + ost_cv_mutex_recursive=lthread) + AC_EGREP_HEADER(PTHREAD_MUTEX_RECURSIVE_NP,pthread.h, + ost_cv_mutex_recursive=linux) + AC_EGREP_HEADER(MUTEX_TYPE_COUNTING_FAST,pthread.h, + ost_cv_mutex_recursive=counting) + ]) + if test $ost_cv_mutex_recursive = "none" ; then + if test $ost_cv_thread_library = "lthread" ; then + ost_cv_mutex_recursive=linux + fi + fi + rm -f conftest* + ]) + + if test $ost_cv_mutex_recursive = "none" ; then + AC_TRY_COMPILE( + [#include ], + [return MUTEX_TYPE_COUNTING_FAST;], + ost_cv_mutex_recursive=counting) + fi + + if test "$ost_cv_cxx_mode" = true ; then + CXXFLAGS="$SAVE_CXXFLAGS" + AC_LANG_RESTORE + fi + + + case $ost_cv_mutex_recursive in + non-portable) + AC_DEFINE(PTHREAD_MUTEXTYPE_RECURSIVE, + PTHREAD_MUTEXTYPE_RECURSIVE_NP, [mutex type]) + ;; + linux) + AC_DEFINE(PTHREAD_MUTEXTYPE_RECURSIVE, + PTHREAD_MUTEX_RECURSIVE_NP) + ;; + counting) + AC_DEFINE(PTHREAD_MUTEXTYPE_RECURSIVE, + MUTEX_TYPE_COUNTING_FAST) + ;; + esac + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_mutexattr_settype, + AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETTYPE, [1], [has setttype]), + [ + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_mutexattr_settype_np, + AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETTYPE_NP, + [1], [has non portable settype])) + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_mutexattr_setkind_np, + AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETKIND_NP, + [1], [has non portable setkind])) + ] + ) + + ost_cv_thread_rwlock=false + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_rwlock_init,[ + ost_cv_thread_rwlock=true + AC_DEFINE(HAVE_PTHREAD_RWLOCK, [1], [has rwlock support])]) + + AC_CHECK_LIB(c, pread,[ + AC_DEFINE(HAVE_PREAD_PWRITE, [1], [has pwrite])],[ + AC_CHECK_LIB(${ost_cv_thread_library}, pread,[ + AC_DEFINE(HAVE_PREAD_PWRITE, [1])],[ + AC_CHECK_LIB(c_r, pread,[AC_DEFINE(HAVE_PREAD_PWRITE)]) + ]) + ]) + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_suspend, + AC_DEFINE(HAVE_PTHREAD_SUSPEND, [1], [has suspend])) + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_attr_setstacksize, + AC_DEFINE(HAVE_PTHREAD_ATTR_SETSTACKSIZE, [1], [has stack size])) + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_yield_np, + AC_DEFINE(HAVE_PTHREAD_YIELD_NP, [1], [has np yield]),[ + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_yield, + AC_DEFINE(HAVE_PTHREAD_YIELD, [1], [has yield]),[ + AC_CHECK_LIB(${ost_cv_thread_library}, sched_yield, + AC_DEFINE(HAVE_PTHREAD_SCHED_YIELD, [1], [has sched yield])) + ]) + ]) + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_cancel,[ + AC_DEFINE(HAVE_PTHREAD_CANCEL, [1], [has cancel]) + AC_CHECK_LIB(${ost_cv_thread_library}, + pthread_setcanceltype, + AC_DEFINE(HAVE_PTHREAD_SETCANCELTYPE, [1], [has setcanceltype]), + AC_CHECK_LIB($ost_cv_thread_library, pthread_setcanel, + AC_DEFINE(HAVE_PTHREAD_SETCANCEL, [1], [has setcancel]))) + ],[ + AC_CHECK_LIB(${ost_cv_thread_library}, + pthread_setcanceltype,[ + AC_DEFINE(HAVE_PTHREAD_CANCEL) + AC_DEFINE(HAVE_PTHREAD_SETCANCELTYPE)]) + + ]) + + AC_CHECK_LIB(${ost_cv_thread_library}, pthread_delay_np, + AC_DEFINE(HAVE_PTHREAD_DELAY_NP, [1], [has non portable delay])) + + fi + + UNAME=`uname` + if test "$UNAME" = "AIX" ; then + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) + CC=$PTHREAD_CC + AC_DEFINE(COMMON_AIX_FIXES, [1], [aix fixes needed]) + fi + +AH_BOTTOM([ +#ifdef HAVE_THREAD_H +#include "@thrprefix@/thread.h" +#if defined(i386) && defined(__svr4__) && !defined(__sun) +#define _THR_UNIXWARE +#endif +#if defined(__SVR4) && defined(__sun) +#define _THR_SUNOS5 +#else +#if defined(__SVR4__) && defined(__SUN__) +#define _THR_SUNOS5 +#endif +#endif +#endif + +#ifdef HAVE_WORKING_SYS_ATOMIC_H +#include +#define HAVE_ATOMIC +#elif defined(HAVE_ATOMIC_AIX) +#include +#ifndef HAVE_ATOMIC +#define HAVE_ATOMIC +#endif +#endif + +#if defined(__cplusplus) +#if defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC) +#include +#define HAVE_ATOMIC +#endif +#endif + +#if defined(HAVE_PTHREAD_H) && ( defined(_THREAD_SAFE) || defined(_REENTRANT) ) + +#ifdef __QNX__ +#define __EXT_QNX +#endif + +#include + +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +#ifdef HAVE_SEMAPHORE_H +#include +#endif +#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef HAVE_SCHED_H +#include +#else +#ifdef HAVE_SYS_SCHED_H +#include +#endif +#endif +#endif + +#define __PTHREAD_H__ +#ifndef PTHREAD_MUTEXTYPE_RECURSIVE +#ifdef MUTEX_TYPE_COUNTING_FAST +#define PTHREAD_MUTEXTYPE_RECURSIVE MUTEX_TYPE_COUNTING_FAST +#endif +#endif +#ifndef PTHREAD_MUTEXTYPE_RECURSIVE +#ifdef PTHREAD_MUTEX_RECURSIVE +#define PTHREAD_MUTEXTYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE +#endif +#endif +#ifndef HAVE_PTHREAD_MUTEXATTR_SETTYPE +#if HAVE_PTHREAD_MUTEXATTR_SETKIND_NP +#ifndef PTHREAD_MUTEXTYPE_RECURSIVE +#define PTHREAD_MUTEXTYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#endif +#define pthread_mutexattr_gettype(x, y) pthread_mutexattr_getkind_np(x, y) +#define pthread_mutexattr_settype(x, y) pthread_mutexattr_setkind_np(x, y) +#endif +#if HAVE_PTHREAD_MUTEXATTR_SETTYPE_NP +#ifndef PTHREAD_MUTEXTYPE_RECURSIVE +#define PTHREAD_MUTEXTYPE_RECURSIVE PTHREAD_MUTEXTYPE_RECURSIVE_NP +#endif +#define pthread_mutexattr_settype(x, y) pthread_mutexattr_settype_np(x, y) +#define pthread_mutexattr_gettype(x, y) pthread_mutexattr_gettype_np(x, y) +#endif +#endif + +#ifdef HAVE_PTHREAD_MACH_THREAD_NP +#define _THR_MACH +#endif + +#ifndef HAVE_PTHREAD_YIELD +#ifdef HAVE_PTHREAD_YIELD_NP +#define pthread_yield() pthread_yield_np() +#define HAVE_PTHREAD_YIELD +#endif +#endif + +#ifndef HAVE_PTHREAD_YIELD +#ifdef HAVE_PTHREAD_SCHED_YIELD +#define pthread_yield() sched_yield() +#define HAVE_PTHREAD_YIELD +#endif +#endif + +#ifndef HAVE_PTHREAD_DELAY +#ifdef HAVE_PTHREAD_DELAY_NP +#define HAVE_PTHREAD_DELAY +#define pthread_delay(x) pthread_delay_np(x) +#endif +#if defined(HAVE_PTHREAD_NANOSLEEP) +#ifndef HAVE_PTHREAD_DELAY +#define HAVE_PTHREAD_DELAY +#ifdef __FreeBSD__ +#ifdef __cplusplus +extern "C" int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); +#endif +#endif +#define pthread_delay(x) nanosleep(x, NULL) +#endif +#endif +#endif + +#ifdef HAVE_PTHREAD_ATTR_SETSTACK +#ifndef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 32768 +#endif +#endif + +#ifndef HAVE_PTHREAD_CANCEL +#ifdef SIGCANCEL +#define CCXX_SIG_THREAD_CANCEL SIGCANCEL +#else +#define CCXX_SIG_THREAD_CANCEL SIGQUIT +#endif +#define pthread_cancel(x) pthread_kill(x, CCXX_SIG_THREAD_CANCEL) +#define pthread_setcanceltype(x, y) +#define pthread_setcancelstate(x, y) +#endif + +#ifndef HAVE_PTHREAD_SETCANCELTYPE +#ifdef HAVE_PTHREAD_SETCANCEL +enum +{ PTHREAD_CANCEL_ASYNCHRONOUS = CANCEL_ON, + PTHREAD_CANCEL_DEFERRED = CANCEL_OFF}; +enum +{ PTHREAD_CANCEL_ENABLE = CANCEL_ON, + PTHREAD_CANCEL_DISABLE = CANCEL_OFF}; +#define pthread_setcancelstate(x, y) \ + (y == NULL) ? pthread_setcancel(x) : *y = pthread_setcancel +#define pthread_setcanceltype(x, y) \ + (y == NULL) ? pthread_setasynccancel(x) | *y = pthread_setasynccancel(x) +#else +#define pthread_setcanceltype(x, y) +#define pthread_setcancelstate(x, y) +#endif +#endif + +#ifdef _AIX +#ifdef HAVE_PTHREAD_SUSPEND +#undef HAVE_PTHREAD_SUSPEND +#endif +#endif + +#endif + + + ]) + +]) + diff --git a/src/object.cpp b/src/object.cpp index 651aa1e1..c03653e9 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -33,13 +33,13 @@ namespace vmime object::object() - : m_refMgr(new utility::refManager(this)) + : m_refMgr(utility::refManager::create(this)) { } object::object(const object&) - : m_refMgr(new utility::refManager(this)) + : m_refMgr(utility::refManager::create(this)) { } diff --git a/src/utility/smartPtr.cpp b/src/utility/smartPtr.cpp index 16249df8..08a8f57c 100644 --- a/src/utility/smartPtr.cpp +++ b/src/utility/smartPtr.cpp @@ -29,135 +29,10 @@ namespace vmime { namespace utility { -// refManager - -refManager::refManager(object* obj) - : m_object(obj), m_strongCount(1), m_weakCount(1) +void refManager::deleteObjectImpl(object* obj) { -} - - -refManager::~refManager() -{ -} - - -const bool refManager::addStrong() -{ - if (m_strongCount <= 0) - return false; - - m_strongCount.increment(); - m_weakCount.increment(); - - return true; -} - - -void refManager::releaseStrong() -{ - m_strongCount.decrement(); - - if (m_strongCount.compareExchange(0, -424242) == 0) // prevent from adding strong refs later - deleteObject(); - - releaseWeak(); -} - - -void refManager::addWeak() -{ - m_weakCount.increment(); -} - - -void refManager::releaseWeak() -{ - if (m_weakCount.decrement() == 0) - deleteManager(); -} - - -object* refManager::getObject() -{ - return m_object; -} - - -void refManager::deleteManager() -{ - delete this; -} - - -void refManager::deleteObject() -{ - try - { - m_object->setRefManager(0); - delete m_object; - } - catch (...) - { - // Exception in destructor - } - - m_object = 0; -} - - -const long refManager::getStrongRefCount() const -{ - return m_strongCount; -} - - -const long refManager::getWeakRefCount() const -{ - return m_weakCount; -} - - - -// refCounter - -refCounter::refCounter(const long initialValue) - : m_value(initialValue) -{ -} - - -refCounter::~refCounter() -{ -} - - -const long refCounter::increment() -{ - return ++m_value; -} - - -const long refCounter::decrement() -{ - return --m_value; -} - - -const long refCounter::compareExchange(const long compare, const long exchangeWith) -{ - const int prev = m_value; - - if (m_value == compare) - m_value = exchangeWith; - - return prev; -} - - -refCounter::operator long() const -{ - return m_value; + obj->setRefManager(0); + delete obj; } diff --git a/src/utility/smartPtrInt.cpp b/src/utility/smartPtrInt.cpp new file mode 100644 index 00000000..a3036310 --- /dev/null +++ b/src/utility/smartPtrInt.cpp @@ -0,0 +1,301 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/smartPtrInt.hpp" +#include "vmime/object.hpp" + +#if defined(_WIN32) +# include +#elif defined(VMIME_HAVE_PTHREAD) +# include +#endif + + +namespace vmime { +namespace utility { + + +// static +refManager* refManager::create(object* obj) +{ + return new refManagerImpl(obj); +} + + +// +// refManager +// + +refManagerImpl::refManagerImpl(object* obj) + : m_object(obj), m_strongCount(1), m_weakCount(1) +{ +} + + +refManagerImpl::~refManagerImpl() +{ +} + + +const bool refManagerImpl::addStrong() +{ + if (m_strongCount <= 0) + return false; + + m_strongCount.increment(); + m_weakCount.increment(); + + return true; +} + + +void refManagerImpl::releaseStrong() +{ + if (m_strongCount.decrement() <= 0) + deleteObject(); + + releaseWeak(); +} + + +void refManagerImpl::addWeak() +{ + m_weakCount.increment(); +} + + +void refManagerImpl::releaseWeak() +{ + if (m_weakCount.decrement() <= 0) + deleteManager(); +} + + +object* refManagerImpl::getObject() +{ + return m_object; +} + + +void refManagerImpl::deleteManager() +{ + delete this; +} + + +void refManagerImpl::deleteObject() +{ + try + { + deleteObjectImpl(m_object); + } + catch (...) + { + // Exception in destructor + } + + m_object = 0; +} + + +const long refManagerImpl::getStrongRefCount() const +{ + return m_strongCount; +} + + +const long refManagerImpl::getWeakRefCount() const +{ + return m_weakCount; +} + + + +// +// refCounter +// + +#ifdef _WIN32 + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ + return InterlockedIncrement(&m_value); +} + + +const long refCounter::decrement() +{ + return InterlockedDecrement(&m_value); +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#elif defined(__GNUC__) && defined(__GLIBCPP__) + + +refCounter::refCounter(const long initialValue) + : m_value(static_cast (initialValue)) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return __exchange_and_add(&m_value, 1) + 1; +#else + return __gnu_cxx::__exchange_and_add(&m_value, 1) + 1; +#endif +} + + +const long refCounter::decrement() +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return __exchange_and_add(&m_value, -1) - 1; +#else + return __gnu_cxx::__exchange_and_add(&m_value, -1) - 1; +#endif +} + + +refCounter::operator long() const +{ +#if __GNUC_MINOR__ < 4 && __GNUC__ < 4 + return static_cast (__exchange_and_add(&m_value, 0)); +#else + return static_cast (__gnu_cxx::__exchange_and_add(&m_value, 0)); +#endif +} + + +#elif defined(VMIME_HAVE_PTHREAD) + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&m_mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + + +refCounter::~refCounter() +{ + pthread_mutex_destroy(&m_mutex); +} + + +const long refCounter::increment() +{ + long value; + + pthread_mutex_lock(&m_mutex); + value = ++m_value; + pthread_mutex_unlock(&m_mutex); + + return value; +} + + +const long refCounter::decrement() +{ + long value; + + pthread_mutex_lock(&m_mutex); + value = --m_value; + pthread_mutex_unlock(&m_mutex); + + return value; +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#else // not thread-safe implementation + + +refCounter::refCounter(const long initialValue) + : m_value(initialValue) +{ +} + + +refCounter::~refCounter() +{ +} + + +const long refCounter::increment() +{ + return ++m_value; +} + + +const long refCounter::decrement() +{ + return --m_value; +} + + +refCounter::operator long() const +{ + return m_value; +} + + +#endif + + +} // utility +} // vmime + diff --git a/vmime/utility/smartPtr.hpp b/vmime/utility/smartPtr.hpp index c52752ed..9b97121c 100644 --- a/vmime/utility/smartPtr.hpp +++ b/vmime/utility/smartPtr.hpp @@ -58,86 +58,66 @@ public: }; -/** Reference counter for shared pointers. - */ - -class refCounter -{ -public: - - refCounter(const long initialValue); - ~refCounter(); - - const long increment(); - const long decrement(); - const long compareExchange(const long compare, const long exchangeWith); - - operator long() const; - -private: - - long m_value; -}; - - /** Manage the life cycle of an object. */ class refManager { +protected: + + refManager() {} + public: - refManager(object* obj); - ~refManager(); + virtual ~refManager() {} + + /** Create a ref manager for the specified object. + * + * @return a new manager + */ + static refManager* create(object* obj); /** Add a strong reference to the managed object. */ - const bool addStrong(); + virtual const bool addStrong() = 0; /** Release a strong reference to the managed object. * If it is the last reference, the object is destroyed. */ - void releaseStrong(); + virtual void releaseStrong() = 0; /** Add a weak reference to the managed object. */ - void addWeak(); + virtual void addWeak() = 0; /** Release a weak reference to the managed object. * If it is the last weak reference, the manager is destroyed. */ - void releaseWeak(); + virtual void releaseWeak() = 0; /** Return a raw pointer to the managed object. * * @return pointer to the managed object */ - object* getObject(); + virtual object* getObject() = 0; /** Return the number of strong refs to this object. * For debugging purposes only. * * @return strong reference count */ - const long getStrongRefCount() const; + virtual const long getStrongRefCount() const = 0; /** Return the number of weak refs to this object. * For debugging purposes only. * * @return weak reference count */ - const long getWeakRefCount() const; + virtual const long getWeakRefCount() const = 0; -private: +protected: - void deleteManager(); - void deleteObject(); - - - object* m_object; - - refCounter m_strongCount; - refCounter m_weakCount; + void deleteObjectImpl(object* obj); }; diff --git a/vmime/utility/smartPtrInt.hpp b/vmime/utility/smartPtrInt.hpp new file mode 100644 index 00000000..b47ce504 --- /dev/null +++ b/vmime/utility/smartPtrInt.hpp @@ -0,0 +1,107 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_UTILITY_SMARTPTRIMPL_HPP_INCLUDED +#define VMIME_UTILITY_SMARTPTRIMPL_HPP_INCLUDED + + +#include "vmime/config.hpp" +#include "vmime/utility/smartPtr.hpp" + + +namespace vmime { +namespace utility { + + +/** Reference counter for shared pointers. + */ + +class refCounter +{ +public: + + refCounter(const long initialValue); + ~refCounter(); + + const long increment(); + const long decrement(); + + operator long() const; + +private: + +#if defined(_WIN32) + long m_value; +#elif defined(__GNUC__) && defined(__GLIBCPP__) + mutable volatile int m_value; +#elif defined (VMIME_HAVE_PTHREAD) + volatile long m_value; + pthread_mutex_t m_mutex; +#else // not thread-safe implementation + long m_value; +#endif + +}; + + +/** Separate implementation of refManager, to avoid polluting global + * namespace with system-specific inclusions/definitions. + */ + +class refManagerImpl : public refManager +{ +public: + + refManagerImpl(object* obj); + ~refManagerImpl(); + + const bool addStrong(); + void releaseStrong(); + + void addWeak(); + void releaseWeak(); + + object* getObject(); + + const long getStrongRefCount() const; + const long getWeakRefCount() const; + +private: + + void deleteManager(); + void deleteObject(); + + + object* m_object; + + refCounter m_strongCount; + refCounter m_weakCount; +}; + + +} // utility +} // vmime + + +#endif // VMIME_UTILITY_SMARTPTRIMPL_HPP_INCLUDED +