Fixed bug #1721186: thread-safe reference counting.

This commit is contained in:
Vincent Richard 2007-05-22 19:25:59 +00:00
parent c8bb57fd93
commit 8c6ba0e058
9 changed files with 1266 additions and 171 deletions

View File

@ -2,6 +2,11 @@
VERSION 0.8.2cvs
================
2007-05-22 Vincent Richard <vincent@vincent-richard.net>
* Implemented thread-safe reference counting for smart pointers,
whenever possible (GCC built-in functions / pthread / Win32).
2007-03-28 Vincent Richard <vincent@vincent-richard.net>
* SMTPTransport.cpp: better parsing of ESMTP extensions.

View File

@ -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"])
""")

235
m4/acx_pthread.m4 Normal file
View File

@ -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 <stevenj@alum.mit.edu>
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.h>],
[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 <pthread.h>], [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

582
m4/ost_pthread.m4 Normal file
View File

@ -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 <pthread.h>],[],
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 <sys/atomic.h>],
[
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 <bits/atomicity.h>],
[
_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 <bits/atomicity.h>],
[
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 <pthread.h>],
[
#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 <pthread.h>],
[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 <sys/atomic.h>
#define HAVE_ATOMIC
#elif defined(HAVE_ATOMIC_AIX)
#include <sys/atomic_op.h>
#ifndef HAVE_ATOMIC
#define HAVE_ATOMIC
#endif
#endif
#if defined(__cplusplus)
#if defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC)
#include <bits/atomicity.h>
#define HAVE_ATOMIC
#endif
#endif
#if defined(HAVE_PTHREAD_H) && ( defined(_THREAD_SAFE) || defined(_REENTRANT) )
#ifdef __QNX__
#define __EXT_QNX
#endif
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
#ifdef HAVE_SEMAPHORE_H
#include <semaphore.h>
#endif
#ifdef _POSIX_PRIORITY_SCHEDULING
#ifdef HAVE_SCHED_H
#include <sched.h>
#else
#ifdef HAVE_SYS_SCHED_H
#include <sys/sched.h>
#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
])
])

View File

@ -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))
{
}

View File

@ -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;
}

301
src/utility/smartPtrInt.cpp Normal file
View File

@ -0,0 +1,301 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2007 Vincent Richard <vincent@vincent-richard.net>
//
// 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 <windows.h>
#elif defined(VMIME_HAVE_PTHREAD)
# include <pthread.h>
#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 <int>(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 <long>(__exchange_and_add(&m_value, 0));
#else
return static_cast <long>(__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

View File

@ -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);
};

View File

@ -0,0 +1,107 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2007 Vincent Richard <vincent@vincent-richard.net>
//
// 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