[complement-svn] SF.net SVN: complement: [1836] trunk/complement/explore
Status: Pre-Alpha
Brought to you by:
complement
From: <com...@us...> - 2008-03-26 11:45:55
|
Revision: 1836 http://complement.svn.sourceforge.net/complement/?rev=1836&view=rev Author: complement Date: 2008-03-26 04:45:54 -0700 (Wed, 26 Mar 2008) Log Message: ----------- merge -r1833:1834 https://complement.svn.sourceforge.net/svnroot/complement/branches/complement-sockios/explore (fixes and improvements of xmt, C++ 0x) Modified Paths: -------------- trunk/complement/explore/include/mt/condition_variable trunk/complement/explore/include/mt/mutex trunk/complement/explore/include/mt/shm.h trunk/complement/explore/include/mt/thread trunk/complement/explore/lib/janus/ut/Makefile trunk/complement/explore/lib/janus/ut/unit_test.cc trunk/complement/explore/lib/mt/ChangeLog trunk/complement/explore/lib/mt/Makefile.inc trunk/complement/explore/lib/mt/thread.cc trunk/complement/explore/lib/mt/ut/Makefile.inc trunk/complement/explore/lib/mt/ut/mt_test.cc trunk/complement/explore/lib/mt/ut/mt_test.h trunk/complement/explore/lib/mt/ut/mt_test_suite.cc trunk/complement/explore/lib/mt/ut/mt_test_wg21.cc trunk/complement/explore/lib/mt/ut/mt_test_wg21.h Added Paths: ----------- trunk/complement/explore/lib/mt/ut/shm_test.cc trunk/complement/explore/lib/mt/ut/shm_test.h Modified: trunk/complement/explore/include/mt/condition_variable =================================================================== --- trunk/complement/explore/include/mt/condition_variable 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/include/mt/condition_variable 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/03/06 13:23:11 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:18:13 ptr> /* * Copyright (c) 1997-1999, 2002-2008 @@ -768,7 +768,7 @@ }; typedef __barrier<false> barrier; -typedef __barrier<false> barrier_ip; +typedef __barrier<true> barrier_ip; } // namespace tr2 Modified: trunk/complement/explore/include/mt/mutex =================================================================== --- trunk/complement/explore/include/mt/mutex 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/include/mt/mutex 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/03/02 14:43:55 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:20:36 ptr> /* * Copyright (c) 1997-1999, 2002-2008 @@ -831,6 +831,7 @@ typedef __mutex<true,true> recursive_mutex_ip; #ifdef __FIT_RWLOCK typedef __rw_mutex<false> rw_mutex; +typedef __rw_mutex<true> rw_mutex_ip; #endif // __FIT_RWLOCK #ifdef __FIT_PTHREAD_SPINLOCK typedef __spinlock<false,false> spinlock; Modified: trunk/complement/explore/include/mt/shm.h =================================================================== --- trunk/complement/explore/include/mt/shm.h 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/include/mt/shm.h 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,7 +1,7 @@ -// -*- C++ -*- Time-stamp: <07/08/03 09:47:53 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:37:01 ptr> /* - * Copyright (c) 2006, 2007 + * Copyright (c) 2006-2008 * Petr Ovtchenkov * * Licensed under the Academic Free License version 3.0 @@ -25,6 +25,9 @@ #include <mt/xmt.h> +#include <mt/mutex> +#include <mt/condition_variable> + namespace xmt { struct shm_base @@ -94,12 +97,22 @@ __SPEC_FULL(is_ipc_sharable,float,true); __SPEC_FULL(is_ipc_sharable,double,true); __SPEC_FULL(is_ipc_sharable,long double,true); + __SPEC_FULL(is_ipc_sharable,xmt::__condition<true>,true); __SPEC_FULL(is_ipc_sharable,xmt::__semaphore<true>,true); __SPEC_FULL(is_ipc_sharable,xmt::__barrier<true>,true); __SPEC_FULL(is_ipc_sharable,xmt::shared_mutex,true); __SPEC_FULL(is_ipc_sharable,xmt::shared_recursive_mutex,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::condition_variable_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::condition_variable_any_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::semaphore_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::barrier_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::mutex_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::recursive_mutex_ip,true); +__SPEC_FULL(is_ipc_sharable,std::tr2::rw_mutex_ip,true); + + #undef __SPEC_FULL #undef __SPEC_ @@ -307,7 +320,7 @@ template <class T> void named( const T& obj, int name ) { - xmt::basic_lock<__mutex<false,true> > lk( _lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( _lock ); if ( _last == 255 ) { throw std::range_error( "too many named objects" ); } @@ -332,7 +345,7 @@ template <class T> T& named( int name ) { - xmt::basic_lock<__mutex<false,true> > lk( _lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( _lock ); for ( int i = 0; _nm_table[i].name != -1; ++i ) { if ( _nm_table[i].name == name ) { ++_nm_table[i].count; @@ -345,7 +358,7 @@ template <class T> const T& named( int name ) const { - xmt::basic_lock<__mutex<false,true> > lk( _lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( _lock ); for ( int i = 0; _nm_table[i].name != -1; ++i ) { if ( _nm_table[i].name == name ) { ++_nm_table[i].count; @@ -358,7 +371,7 @@ template <class T> void release( int name ) { - xmt::basic_lock<__mutex<false,true> > lk( _lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( _lock ); for ( int i = 0; _nm_table[i].name != -1; ++i ) { if ( _nm_table[i].name == name ) { if ( --_nm_table[i].count == 0 ) { @@ -375,7 +388,7 @@ int count( int name ) const throw() { - xmt::basic_lock<__mutex<false,true> > lk( _lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( _lock ); for ( int i = 0; _nm_table[i].name != -1; ++i ) { if ( _nm_table[i].name == name ) { return _nm_table[i].count; @@ -395,7 +408,7 @@ shm_name_mgr& operator =( const shm_name_mgr& ) { return *this; } - xmt::__mutex<false,true> _lock; + std::tr2::mutex_ip _lock; struct _name_rec { int name; @@ -424,7 +437,7 @@ { uint64_t _magic; size_type _first; - xmt::__mutex<false,true> _lock; + std::tr2::mutex_ip _lock; size_type _nm; }; @@ -466,8 +479,9 @@ pointer p = _seg.address(); if ( p != reinterpret_cast<pointer>(-1) && (force || _seg.count() <= 1) ) { + using namespace std::tr2; _master *m = reinterpret_cast<_master *>( _seg.address() ); - (&m->_lock)->~__mutex<false,true>(); + (&m->_lock)->~mutex_ip(); if ( m->_nm != 0 ) { reinterpret_cast<shm_name_mgr<_Inst> *>(reinterpret_cast<char *>(p) + m->_nm)->~shm_name_mgr<_Inst>(); } @@ -484,7 +498,7 @@ if ( p != reinterpret_cast<pointer>(-1) ) { _master *m = reinterpret_cast<_master *>( p ); if ( m->_nm == 0 ) { - xmt::basic_lock<xmt::__mutex<false,true> > lk( m->_lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( m->_lock ); void *nm = _traverse( &m->_first, sizeof(shm_name_mgr<_Inst>) ); m->_nm = reinterpret_cast<char *>(nm) - reinterpret_cast<char *>(p); return *new ( nm ) shm_name_mgr<_Inst>(); @@ -500,7 +514,7 @@ { _master *m = reinterpret_cast<_master *>( _seg.address() ); if ( m != reinterpret_cast<_master *>(-1) ) { - xmt::basic_lock<xmt::__mutex<false,true> > lk( m->_lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( m->_lock ); return _traverse( &m->_first, n ); } @@ -516,8 +530,8 @@ static void init( _master& m ) { m._magic = MAGIC; - new ( &m._lock ) xmt::__mutex<false,true>(); - xmt::basic_lock<xmt::__mutex<false,true> > lk( m._lock ); + new ( &m._lock ) std::tr2::mutex_ip(); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( m._lock ); m._first = sizeof( _master ); m._nm = 0; _fheader& h = *new ( reinterpret_cast<char *>(&m) + sizeof(_master) ) _fheader(); @@ -539,7 +553,7 @@ n = std::max( n + (__align - n % __align) % __align, sizeof(_fheader) ); _master *m = reinterpret_cast<_master *>( _seg.address() ); if ( m != reinterpret_cast<_master *>(-1) && (reinterpret_cast<char *>(p) - reinterpret_cast<char *>(_seg.address())) < (_seg.max_size() + sizeof(_master) + sizeof(_aheader) ) ) { - xmt::basic_lock<xmt::__mutex<false,true> > lk( m->_lock ); + std::tr2::lock_guard<std::tr2::mutex_ip> lk( m->_lock ); _aheader *a = reinterpret_cast<_aheader *>( reinterpret_cast<char *>(p) - sizeof(_aheader) ); size_type off = reinterpret_cast<char *>(p) - reinterpret_cast<char *>(_seg.address()); if ( m->_first == 0 ) { Modified: trunk/complement/explore/include/mt/thread =================================================================== --- trunk/complement/explore/include/mt/thread 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/include/mt/thread 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/03/02 14:44:16 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 01:58:08 ptr> /* * Copyright (c) 1997-1999, 2002-2008 @@ -78,6 +78,8 @@ }; #endif // !_WIN32 +__FIT_DECLSPEC void fork() throw( fork_in_parent, std::runtime_error ); + class thread_base { public: @@ -135,6 +137,7 @@ friend class thread_base; friend id get_id(void); + // friend __FIT_DECLSPEC void fork() throw( fork_in_parent, std::runtime_error ); }; enum { @@ -161,6 +164,9 @@ Init(); ~Init(); private: + static void __at_fork_prepare(); + static void __at_fork_parent(); + static void __at_fork_child(); static int& _count; }; @@ -203,6 +209,7 @@ std::string _stack_on_create; #endif friend class Init; + friend __FIT_DECLSPEC void fork() throw( fork_in_parent, std::runtime_error ); }; template <unsigned F, size_t S> @@ -605,11 +612,18 @@ // trick to declare thread_base::id get_id() as friend in thread_base::id thread_base::id get_id(); +pid_t getpid(); +pid_t getppid(); + namespace this_thread { - // std::thread_base::id get_id(); - using tr2::get_id; +using tr2::fork; +__FIT_DECLSPEC void become_daemon() throw( fork_in_parent, std::runtime_error ); + +// std::thread_base::id get_id(); +using tr2::get_id; + inline void yield() { #ifdef __FIT_PTHREADS Modified: trunk/complement/explore/lib/janus/ut/Makefile =================================================================== --- trunk/complement/explore/lib/janus/ut/Makefile 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/janus/ut/Makefile 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -# -*- Makefile -*- Time-stamp: <07/08/08 22:18:48 ptr> +# -*- Makefile -*- Time-stamp: <08/02/25 19:21:09 ptr> SRCROOT := ../../.. COMPILER_NAME := gcc @@ -20,7 +20,7 @@ ifeq ($(OSNAME),linux) -release-shared: LDSEARCH += -L${LIBEXAM_DIR}/${OUTPUT_DIR} -L$(LIBXMT_DIR)/${OUTPUT_DIR} -L$(LIBSOCKIOS_DIR)/${OUTPUT_DIR} -L$(LIBSTEM_DIR)/${OUTPUT_DIR} -L$(LIBJANUS_DIR)/${OUTPUT_DIR} -Wl,--rpath=${LIBEXAM_DIR}/${OUTPUT_DIR}:$(LIBXMT_DIR)/${OUTPUT_DIR}:${LIBSOCKIOS_DIR}/${OUTPUT_DIR}:${LIBSTEM_DIR}/${OUTPUT_DIR}:${LIBJANUS_DIR}${OUTPUT_DIR}:${STLPORT_LIB_DIR} +release-shared: LDSEARCH += -L${LIBEXAM_DIR}/${OUTPUT_DIR} -L$(LIBXMT_DIR)/${OUTPUT_DIR} -L$(LIBSOCKIOS_DIR)/${OUTPUT_DIR} -L$(LIBSTEM_DIR)/${OUTPUT_DIR} -L$(LIBJANUS_DIR)/${OUTPUT_DIR} -Wl,--rpath=${LIBEXAM_DIR}/${OUTPUT_DIR}:$(LIBXMT_DIR)/${OUTPUT_DIR}:${LIBSOCKIOS_DIR}/${OUTPUT_DIR}:${LIBSTEM_DIR}/${OUTPUT_DIR}:${LIBJANUS_DIR}/${OUTPUT_DIR}:${STLPORT_LIB_DIR} dbg-shared: LDSEARCH += -L${LIBEXAM_DIR}/${OUTPUT_DIR_DBG} -L$(LIBXMT_DIR)/${OUTPUT_DIR_DBG} -L$(LIBSOCKIOS_DIR)/${OUTPUT_DIR_DBG} -L$(LIBSTEM_DIR)/${OUTPUT_DIR_DBG} -L$(LIBJANUS_DIR)/${OUTPUT_DIR_DBG} -Wl,--rpath=${LIBEXAM_DIR}/${OUTPUT_DIR_DBG}:$(LIBXMT_DIR)/${OUTPUT_DIR_DBG}:${LIBSOCKIOS_DIR}/${OUTPUT_DIR_DBG}:${LIBSTEM_DIR}/${OUTPUT_DIR_DBG}:${LIBJANUS_DIR}/${OUTPUT_DIR_DBG}:${STLPORT_LIB_DIR} Modified: trunk/complement/explore/lib/janus/ut/unit_test.cc =================================================================== --- trunk/complement/explore/lib/janus/ut/unit_test.cc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/janus/ut/unit_test.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <07/08/16 09:04:40 ptr> +// -*- C++ -*- Time-stamp: <08/02/25 22:21:57 ptr> #include "vt_operations.h" @@ -14,6 +14,8 @@ janus::vtime_operations vt_oper; + t.flags( /* exam::base_logger::trace */ exam::base_logger::verbose ); + t.add( &vtime_operations::vt_max, vt_oper, "Max", tc[1] = t.add( &vtime_operations::vt_add, vt_oper, "Additions", tc[0] = t.add( &vtime_operations::vt_compare, vt_oper, "Compare" ) ) ); Modified: trunk/complement/explore/lib/mt/ChangeLog =================================================================== --- trunk/complement/explore/lib/mt/ChangeLog 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ChangeLog 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,3 +1,29 @@ +2008-03-26 Petr Ovtchenkov <pt...@is...> + + * mutex: add rw_mutex_ip typedef; + + * condition_variable: fix wrong typedef for barrier_ip; + + * thread, thread.cc: __at_fork_* handlers moved into Init; + added fork call; on fork down thread's ids to bad id, + except thread that call fork; set __at_fork_* handlers + only once; lock all threads mutexes before fork and + release all ones after---safe fork; + + * shm.h: based on JTC1/SC22/WG21 threads interfaces, but + still in xmt namespace for compatibility; + + * note: implementation of threads interfaces are close + to JTC1/SC22/WG21 C++ 0x working draft, see + http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2008/n2521.pdf + + * ut/mt_test.cc, ut/mt_test.h, ut/shm_test.h, ut/shm_test.cc: + move shared memory test suite into separate file; + + * ut/mt_test_wg21.h, ut/mt_test_wg21.cc: test for fork; + + * libxmt: version 2.0.1. + 2008-03-06 Petr Ovtchenkov <pt...@is...> * condition_variable: const casts for pthread_cond_* calls; Modified: trunk/complement/explore/lib/mt/Makefile.inc =================================================================== --- trunk/complement/explore/lib/mt/Makefile.inc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/Makefile.inc 2008-03-26 11:45:54 UTC (rev 1836) @@ -3,7 +3,7 @@ LIBNAME = xmt MAJOR = 2 MINOR = 0 -PATCH = 0 +PATCH = 1 SRC_CC = xmt.cc thr_mgr.cc time.cc uid.cc shm.cc callstack.cc system_error.cc thread.cc \ date_time.cc SRC_C = fl.c Modified: trunk/complement/explore/lib/mt/thread.cc =================================================================== --- trunk/complement/explore/lib/mt/thread.cc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/thread.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/03/02 14:54:25 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 02:02:03 ptr> /* * Copyright (c) 1997-1999, 2002-2008 @@ -41,17 +41,77 @@ #include <stdio.h> #include <syscall.h> +#ifdef STLPORT +// # include <unordered_map> +# include <unordered_set> +// # include <hash_map> +// # include <hash_set> +// # define __USE_STLPORT_HASH +# define __USE_STLPORT_TR1 +#else +# if defined(__GNUC__) && (__GNUC__ < 4) +// # include <ext/hash_map> +# include <ext/hash_set> +# define __USE_STD_HASH +# else +// # include <tr1/unordered_map> +# include <tr1/unordered_set> +# define __USE_STD_TR1 +# endif +#endif + + #ifdef WIN32 # pragma warning( disable : 4290) // using namespace std; #endif +#if defined(__USE_STLPORT_HASH) || defined(__USE_STLPORT_TR1) || defined(__USE_STD_TR1) +# define __HASH_NAMESPACE std +#endif +#if defined(__USE_STD_HASH) +# define __HASH_NAMESPACE __gnu_cxx +#endif + +namespace __HASH_NAMESPACE { + +#ifdef __USE_STD_TR1 +namespace tr1 { +#endif + +template <> +struct hash<std::tr2::thread_base*> +{ + size_t operator()(const std::tr2::thread_base* __x) const + { return reinterpret_cast<size_t>(__x); } +}; + +#ifdef __USE_STD_TR1 +} +#endif + +} // namespace __HASH_NAMESPACE + + namespace std { namespace tr2 { namespace detail { +#ifdef __USE_STLPORT_HASH +typedef std::hash_set<thread_base*> thread_pool_t; +#endif +#ifdef __USE_STD_HASH +typedef __gnu_cxx::hash_set<thread_base*> thread_pool_t; +#endif +#if defined(__USE_STLPORT_TR1) || defined(__USE_STD_TR1) +typedef std::tr1::unordered_set<thread_base*> thread_pool_t; +#endif + +static mutex thrpool_lock; +static thread_pool_t thread_pool; + int Init_count = 0; // problem: ::getpid() really return cached value, so pid returned may be @@ -141,45 +201,6 @@ return user_words + __idx + 1; } - -void __at_fork_prepare() -{ -#ifdef __FIT_PTHREADS - if ( Init_count > 0 ) { - _uw_save = pthread_getspecific( _mt_key ); - } -#endif -} - -void __at_fork_parent() -{ -} - -void __at_fork_child() -{ -#ifdef __FIT_PTHREADS - if ( Init_count > 0 ) { - // otherwise we do it in Thread::Init::Init() below -# if !(defined(__FreeBSD__) || defined(__OpenBSD__)) - // I am misunderstand this point, Solaris 7 require this (to be restored) - - // pthread_atfork( __at_fork_prepare, __at_fork_parent, __at_fork_child ); - - // while Linux (and other) inherit this setting from parent process? - // At least Linux glibc 2.2.5 try to made lock in recursive - // call of pthread_atfork -# else -// should be fixed... -# endif // !(__FreeBSD__ || __OpenBSD__) - pthread_key_create( &_mt_key, 0 ); // take new key - pthread_setspecific( _mt_key, _uw_save ); // store preserved user words array - _uw_save = 0; - // Note, that only calling thread inherited when we use POSIX: - Init_count = 1; // i.e. only ONE (calling) thread... - } -#endif -} - } // namespace detail } // namespace tr2 } // namespace std @@ -196,6 +217,7 @@ char *Init_buf[32]; int& thread_base::Init::_count( detail::Init_count ); // trick to avoid friend declarations +bool _at_fork_set = false; const std::string msg1( "Can't create thread" ); const std::string msg2( "Can't fork" ); @@ -213,8 +235,11 @@ if ( _count++ == 0 ) { #ifdef __FIT_PTHREADS # if !(defined(__FreeBSD__) || defined(__OpenBSD__)) - if ( pthread_atfork( detail::__at_fork_prepare, detail::__at_fork_parent, detail::__at_fork_child ) ) { - throw std::runtime_error( "Problems with pthread_atfork" ); + if ( !_at_fork_set ) { // call only once + if ( pthread_atfork( __at_fork_prepare, __at_fork_parent, __at_fork_child ) ) { + throw std::runtime_error( "Problems with pthread_atfork" ); + } + _at_fork_set = true; } # endif // !(__FreeBSD__ || __OpenBSD__) pthread_key_create( &detail::_mt_key, 0 ); @@ -253,6 +278,73 @@ # endif // !(__FreeBSD__ || __OpenBSD__) #endif // __FIT_UITHREADS || _PTHREADS +void thread_base::Init::__at_fork_prepare() +{ +#ifdef __FIT_PTHREADS + detail::_F_lock.lock(); + detail::thrpool_lock.lock(); + + if ( detail::Init_count > 0 ) { + detail::_uw_save = pthread_getspecific( detail::_mt_key ); + } + + for ( detail::thread_pool_t::const_iterator i = detail::thread_pool.begin(); i != detail::thread_pool.end(); ++i ) { + if ( (*i)->_id != _bad_thread_id ) { + const_cast<thread_base*>(*i)->_id_lock.lock(); + } + } + +#endif +} + +void thread_base::Init::__at_fork_parent() +{ +#ifdef __FIT_PTHREADS + for ( detail::thread_pool_t::const_iterator i = detail::thread_pool.begin(); i != detail::thread_pool.end(); ++i ) { + if ( (*i)->_id != _bad_thread_id ) { + const_cast<thread_base*>(*i)->_id_lock.unlock(); + } + } + + detail::thrpool_lock.unlock(); + detail::_F_lock.unlock(); +#endif +} + +void thread_base::Init::__at_fork_child() +{ +#ifdef __FIT_PTHREADS + for ( detail::thread_pool_t::const_iterator i = detail::thread_pool.begin(); i != detail::thread_pool.end(); ++i ) { + if ( (*i)->_id != _bad_thread_id ) { + const_cast<thread_base*>(*i)->_id_lock.unlock(); + } + } + + detail::thrpool_lock.unlock(); + + if ( detail::Init_count > 0 ) { + // otherwise we do it in Thread::Init::Init() below +# if !(defined(__FreeBSD__) || defined(__OpenBSD__)) + // I am misunderstand this point, Solaris 7 require this (to be restored) + + // pthread_atfork( __at_fork_prepare, __at_fork_parent, __at_fork_child ); + + // while Linux (and other) inherit this setting from parent process? + // At least Linux glibc 2.2.5 try to made lock in recursive + // call of pthread_atfork +# else +// should be fixed... +# endif // !(__FreeBSD__ || __OpenBSD__) + pthread_key_create( &detail::_mt_key, 0 ); // take new key + pthread_setspecific( detail::_mt_key, detail::_uw_save ); // store preserved user words array + detail::_uw_save = 0; + // Note, that only calling thread inherited when we use POSIX: + detail::Init_count = 1; // i.e. only ONE (calling) thread... + } + detail::_F_lock.unlock(); +#endif +} + thread_base::id::id() : _id( _bad_thread_id ) { } @@ -262,6 +354,9 @@ _id( _bad_thread_id ) { new( Init_buf ) Init(); + + lock_guard<mutex> lk( detail::thrpool_lock ); + detail::thread_pool.insert( this ); } __FIT_DECLSPEC @@ -269,6 +364,9 @@ { if ( joinable() ) { thread_base::join(); + } else { + lock_guard<mutex> lk( detail::thrpool_lock ); + detail::thread_pool.erase( this ); } ((Init *)Init_buf)->~Init(); @@ -294,6 +392,12 @@ #endif // __FIT_WIN32THREADS #ifdef __FIT_PTHREADS pthread_join( _id, 0 ); + + { + lock_guard<mutex> lk(detail::thrpool_lock); + detail::thread_pool.erase( this ); + } + _id = _bad_thread_id; // lock not required here, only one thread #endif // PTHREADS } @@ -306,14 +410,44 @@ if ( pthread_detach( _id ) ) { // throw system_error; } + { + lock_guard<mutex> lk(detail::thrpool_lock); + for ( detail::thread_pool_t::const_iterator i = detail::thread_pool.begin(); i != detail::thread_pool.end(); ++i ) { + if ( (*i)->_id == _id ) { + detail::thread_pool.erase( i ); + break; + } + } + } _id = _bad_thread_id; #endif } +pid_t getpid() +{ + return detail::_pid; +} + +pid_t getppid() +{ + return detail::_ppid; +} + +thread_base::id get_id() +{ +#ifdef __FIT_PTHREADS + return thread_base::id( pthread_self() ); +#endif +#ifdef __FIT_WIN32THREADS + return thread_base::id( GetCurrentThread() ); +#endif +} + +__FIT_DECLSPEC void fork() throw( fork_in_parent, std::runtime_error ) { #ifdef __unix - // MT_REENTRANT( detail::_F_lock, _1 ); + thread_base::id fthr = this_thread::get_id(); fork_in_parent f( ::fork() ); if ( f.pid() > 0 ) { throw f; @@ -323,15 +457,29 @@ } detail::_ppid = detail::_pid; detail::_pid = syscall( SYS_getpid ); + + // lock not required: it in child and only one thread yet + for ( detail::thread_pool_t::const_iterator i = detail::thread_pool.begin(); i != detail::thread_pool.end(); ) { + if ( (*i)->get_id() != fthr ) { + const_cast<thread_base*>(*i)->_id = _bad_thread_id; + detail::thread_pool.erase( i++ ); + } else { + ++i; + } + } + #endif } +namespace this_thread +{ + __FIT_DECLSPEC void become_daemon() throw( fork_in_parent, std::runtime_error ) { #ifdef __unix try { - std::tr2::fork(); + std::tr2::this_thread::fork(); ::chdir( "/var/tmp" ); // for CWD: if not done, process remain with same WD // and don't allow unmount volume, for example @@ -353,29 +501,6 @@ #endif } -pid_t getpid() -{ - return detail::_pid; -} - -pid_t getppid() -{ - return detail::_ppid; -} - -thread_base::id get_id() -{ -#ifdef __FIT_PTHREADS - return thread_base::id( pthread_self() ); -#endif -#ifdef __FIT_WIN32THREADS - return thread_base::id( GetCurrentThread() ); -#endif -} - -namespace this_thread -{ - #if 0 std::thread_base::id get_id() { Modified: trunk/complement/explore/lib/mt/ut/Makefile.inc =================================================================== --- trunk/complement/explore/lib/mt/ut/Makefile.inc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/Makefile.inc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,7 +1,7 @@ -# -*- makefile -*- Time-stamp: <08/02/15 22:36:40 ptr> +# -*- makefile -*- Time-stamp: <08/03/26 10:12:36 ptr> PRGNAME = mt_ut SRC_CC = unit_test.cc timespec.cc \ signal-1.cc signal-3.cc \ - mt_test.cc mt_test_suite.cc \ + mt_test.cc shm_test.cc mt_test_suite.cc \ mt_test_wg21.cc Modified: trunk/complement/explore/lib/mt/ut/mt_test.cc =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test.cc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/mt_test.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <07/09/14 22:10:35 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:09:40 ptr> /* * Copyright (c) 2006, 2007 @@ -516,454 +516,7 @@ return EXAM_RESULT; } -/* ****************************************************** */ - -int EXAM_IMPL(shm_test::shm_segment) -{ - const char fname[] = "/tmp/mt_test.shm"; - try { - xmt::detail::__shm_alloc<0> seg( 5000, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - - EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); - seg.deallocate(); - EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); - - EXAM_REQUIRE( !fs::exists( fname ) ); - - seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); - seg.deallocate(); - EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); - EXAM_CHECK( fs::exists( fname ) ); // well, now I don't remove ref file, because shm segment may be created with another way - - // not exclusive, should pass - seg.allocate( fname, 1024, xmt::shm_base::create, 0660 ); - EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); - try { - // This instance has segment in usage, should throw - seg.allocate( fname, 1024, 0, 0660 ); - EXAM_CHECK( false ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_CHECK( true ); // Ok - } - - /* - - I will treat another instanse (<1>) as interface to another - segment, so this sample not work. - - try { - // But this is another instanse, it's ok: - xmt::detail::__shm_alloc<1> seg1( fname, 1024, 0, 0660 ); - BOOST_CHECK( seg1.address() != reinterpret_cast<void *>(-1) ); - // Don't call seg1.deallocate() here, it destroy - } - catch ( xmt::shm_bad_alloc& err ) { - BOOST_CHECK( false ); // Fail - } - */ - - seg.deallocate(); - EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); - - // ---- - try { - // exclusive, should throw - seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - EXAM_CHECK( false ); // Fail, should throw - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_CHECK( true ); // Ok - } - EXAM_CHECK( fs::exists( fname ) ); - // ---- - - fs::remove( fname ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR( err.what() ); - } - - return EXAM_RESULT; -} - -/* ****************************************************** */ - -int EXAM_IMPL(shm_test::shm_alloc) -{ - const char fname[] = "/tmp/mt_test.shm"; - try { - xmt::shm_alloc<0> seg; - - seg.allocate( fname, 7000, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - - { - xmt::allocator_shm<char,0> shmall; - size_t sz = shmall.max_size(); - // two blocks - char *ch1 = shmall.allocate( 3500 ); - EXAM_CHECK( ch1 != 0 ); - char *ch2 = shmall.allocate( 3500 ); - EXAM_CHECK( ch2 != 0 ); - try { - // try to allocate third block, not enough room - char *ch3 = shmall.allocate( 8 * 1024 - 7000 ); - EXAM_CHECK( false ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_CHECK( true ); - } - // free first blocks - shmall.deallocate( ch1, 3500 ); - ch1 = shmall.allocate( 3500 ); - // allocate [first] block again - EXAM_CHECK( ch1 != 0 ); - // free second block - shmall.deallocate( ch2, 3500 ); - // allocate [second] block again - ch2 = shmall.allocate( 3500 ); - EXAM_CHECK( ch2 != 0 ); - // free both blocks - shmall.deallocate( ch1, 3500 ); - shmall.deallocate( ch2, 3500 ); - // allocate big block, enough for initial memory chunk - ch1 = shmall.allocate( 7000 ); - EXAM_CHECK( ch1 != 0 ); - // free it - shmall.deallocate( ch1, 7000 ); - // allocate block of maximum size - ch1 = shmall.allocate( sz ); - EXAM_CHECK( ch1 != 0 ); - // free it - shmall.deallocate( ch1, sz ); - // allocate block, enough for initial memory chunk - ch1 = shmall.allocate( 7000 ); - EXAM_CHECK( ch1 != 0 ); - // free it - shmall.deallocate( ch1, 7000 ); - ch1 = shmall.allocate( 3000 ); - EXAM_CHECK( ch1 != 0 ); - ch2 = shmall.allocate( 400 ); - EXAM_CHECK( ch2 != 0 ); - char *ch3 = shmall.allocate( 3500 ); - EXAM_CHECK( ch3 != 0 ); - shmall.deallocate( ch1, 3000 ); - shmall.deallocate( ch2, 400 ); - shmall.deallocate( ch3, 3500 ); - ch1 = shmall.allocate( sz ); - EXAM_CHECK( ch1 != 0 ); - shmall.deallocate( ch1, sz ); - } - seg.deallocate(); - fs::remove( fname ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR( err.what() ); - } - - return EXAM_RESULT; -} - - /* ****************************************************** - * This test is similar mt_test::fork() above, but instead plain shm_* - * functions it use allocator based on shared memory segment - */ -int EXAM_IMPL(shm_test::fork_shm) -{ - const char fname[] = "/tmp/mt_test.shm"; - try { - xmt::shm_alloc<0> seg; - - seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - xmt::allocator_shm<char,0> shm; - - xmt::__condition<true>& fcnd = *new( shm.allocate( sizeof(xmt::__condition<true>) ) ) xmt::__condition<true>(); - fcnd.set( false ); - try { - xmt::fork(); - - try { - - // Child code - fcnd.try_wait(); - - } - catch ( ... ) { - } - - exit( 0 ); - } - catch ( xmt::fork_in_parent& child ) { - try { - EXAM_CHECK( child.pid() > 0 ); - - fcnd.set( true ); - - int stat = -1; - EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); - if ( WIFEXITED(stat) ) { - EXAM_CHECK( WEXITSTATUS(stat) == 0 ); - } else { - EXAM_ERROR( "child interrupted" ); - } - } - catch ( ... ) { - } - } - catch ( ... ) { - } - - (&fcnd)->~__condition<true>(); - shm.deallocate( reinterpret_cast<char *>(&fcnd), sizeof(xmt::__condition<true>) ); - seg.deallocate(); - fs::remove( fname ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR( err.what() ); - } - - return EXAM_RESULT; -} - -/* ****************************************************** - * Test: how to take named object in shared memory segment - */ -int EXAM_IMPL(shm_test::shm_named_obj) -{ - const char fname[] = "/tmp/mt_test.shm"; - enum { - test_Condition_Object = 1 - }; - try { - xmt::shm_alloc<0> seg; - - seg.allocate( fname, 4*4096, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - xmt::shm_name_mgr<0>& nm = seg.name_mgr(); - - xmt::allocator_shm<xmt::__condition<true>,0> shm; - - xmt::__condition<true>& fcnd = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); - nm.named( fcnd, test_Condition_Object ); - fcnd.set( false ); - - try { - xmt::fork(); - - int eflag = 0; - - try { - - // Child code - xmt::shm_alloc<0> seg_ch; - - if ( seg_ch.max_size() == 0 ) { // just illustration, if seg and seg_ch - // (really xmt::shm_alloc<0>) - // in totally different address spaces - // in our case xmt::shm_name_mgr<0> instance derived from parent - // process - seg.allocate( fname, 4*4096, 0, 0660 ); - } - - xmt::shm_name_mgr<0>& nm_ch = seg_ch.name_mgr(); - xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( test_Condition_Object ); - fcnd_ch.set( true ); - } - catch ( const xmt::shm_bad_alloc& err ) { - EXAM_ERROR_ASYNC_F( err.what(), eflag ); - } - catch ( const std::invalid_argument& err ) { - EXAM_ERROR_ASYNC_F( err.what(), eflag ); - } - catch ( ... ) { - EXAM_ERROR_ASYNC_F( "Fail in child", eflag ); - } - - exit( eflag ); - } - catch ( xmt::fork_in_parent& child ) { - try { - EXAM_CHECK( child.pid() > 0 ); - - fcnd.try_wait(); - - int stat = -1; - EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); - if ( WIFEXITED(stat) ) { - EXAM_CHECK( WEXITSTATUS(stat) == 0 ); - } else { - EXAM_ERROR( "child interrupted" ); - } - } - catch ( ... ) { - EXAM_ERROR( "Fail in parent" ); - } - } - catch ( ... ) { - EXAM_ERROR( "Fail in fork" ); - } - - (&fcnd)->~__condition<true>(); - shm.deallocate( &fcnd, 1 ); - seg.deallocate(); - fs::remove( fname ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR( err.what() ); - } - - return EXAM_RESULT; -} - -/* ****************************************************** - */ -const char shm_test::fname1[] = "/tmp/mt_test.shm.1"; - -shm_test::shm_test() -{ - try { - seg1.allocate( fname1, 4*4096, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR_ASYNC( err.what() ); - } -} - -/* ****************************************************** - */ -shm_test::~shm_test() -{ - seg1.deallocate(); - fs::remove( fname1 ); -} - -/* ****************************************************** - */ - -int EXAM_IMPL(shm_test::shm_named_obj_more) -{ - enum { - ObjName = 1 - }; - - try { - xmt::shm_name_mgr<1>& nm = seg1.name_mgr(); - - xmt::allocator_shm<xmt::__condition<true>,1> shm; - - xmt::__condition<true>& fcnd = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); - nm.named( fcnd, ObjName ); - fcnd.set( false ); - - try { - xmt::fork(); - - int eflag = 0; - - try { - xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); - xmt::allocator_shm<xmt::__condition<true>,1> shm_ch; - xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( ObjName ); - fcnd_ch.set( true ); - nm_ch.release<xmt::__condition<true> >( ObjName ); - } - catch ( const std::invalid_argument& err ) { - EXAM_ERROR_ASYNC_F( err.what(), eflag ); - } - exit( eflag ); - } - catch ( xmt::fork_in_parent& child ) { - fcnd.try_wait(); - int stat = -1; - EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); - if ( WIFEXITED(stat) ) { - EXAM_CHECK( WEXITSTATUS(stat) == 0 ); - } else { - EXAM_ERROR( "child interrupted" ); - } - } - nm.release<xmt::__condition<true> >( ObjName ); // fcnd should be destroyed here - - xmt::__condition<true>& fcnd1 = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); - nm.named( fcnd1, ObjName ); // ObjName should be free here - fcnd1.set( false ); - - try { - xmt::fork(); - - int eflag = 0; - - try { - xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); - xmt::allocator_shm<xmt::__condition<true>,1> shm_ch; - xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( ObjName ); - fcnd_ch.set( true ); - nm_ch.release<xmt::__condition<true> >( ObjName ); - } - catch ( const std::invalid_argument& err ) { - EXAM_ERROR_ASYNC_F( err.what(), eflag ); - } - - exit( eflag ); - } - catch ( xmt::fork_in_parent& child ) { - fcnd1.try_wait(); - int stat = -1; - EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); - if ( WIFEXITED(stat) ) { - EXAM_CHECK( WEXITSTATUS(stat) == 0 ); - } else { - EXAM_ERROR( "child interrupted" ); - } - } - nm.release<xmt::__condition<true> >( ObjName ); // fcnd should be destroyed here - - xmt::allocator_shm<xmt::__barrier<true>,1> shm_b; - xmt::__barrier<true>& b = *new ( shm_b.allocate( 1 ) ) xmt::__barrier<true>(); - - nm.named( b, ObjName ); // ObjName should be free here - - try { - xmt::fork(); - - int eflag = 0; - try { - xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); - xmt::allocator_shm<xmt::__barrier<true>,1> shm_ch; - xmt::__barrier<true>& b_ch = nm_ch.named<xmt::__barrier<true> >( ObjName ); - b_ch.wait(); - nm_ch.release<xmt::__barrier<true> >( ObjName ); - } - catch ( const std::invalid_argument& err ) { - EXAM_ERROR_ASYNC_F( err.what(), eflag ); - } - - exit( eflag ); - } - catch ( xmt::fork_in_parent& child ) { - b.wait(); - int stat = -1; - EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); - if ( WIFEXITED(stat) ) { - EXAM_CHECK( WEXITSTATUS(stat) == 0 ); - } else { - EXAM_ERROR( "child interrupted" ); - } - } - nm.release<xmt::__barrier<true> >( ObjName ); // barrier should be destroyed here - } - catch ( xmt::shm_bad_alloc& err ) { - EXAM_ERROR( err.what() ); - } - catch ( const std::invalid_argument& err ) { - EXAM_ERROR( err.what() ); - } - - return EXAM_RESULT; -} - -/* ****************************************************** * Thread pool (aka ThreadMgr) test. * * Start 200 threads under ThreadMgr; check that all threads Modified: trunk/complement/explore/lib/mt/ut/mt_test.h =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test.h 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/mt_test.h 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,7 +1,7 @@ -// -*- C++ -*- Time-stamp: <07/09/05 00:02:19 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:08:36 ptr> /* - * Copyright (c) 2006, 2007 + * Copyright (c) 2006-2008 * Petr Ovtchenkov * * Licensed under the Academic Free License Version 3.0 @@ -37,22 +37,4 @@ // static int x; }; -class shm_test -{ - public: - shm_test(); - ~shm_test(); - - int EXAM_DECL(shm_segment); - int EXAM_DECL(shm_alloc); - int EXAM_DECL(fork_shm); - int EXAM_DECL(shm_named_obj); - - int EXAM_DECL(shm_named_obj_more); - - private: - xmt::shm_alloc<1> seg1; - static const char fname1[]; -}; - #endif // __MT_TEST_H Modified: trunk/complement/explore/lib/mt/ut/mt_test_suite.cc =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test_suite.cc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/mt_test_suite.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/02/25 12:17:54 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 10:12:21 ptr> /* * Copyright (c) 2006-2008 @@ -10,6 +10,7 @@ #include "mt_test_suite.h" #include "mt_test.h" +#include "shm_test.h" #include "mt_test_wg21.h" #include <config/feature.h> @@ -41,7 +42,6 @@ exam::test_suite::test_case_type tc[3]; // t.add( &mt_test::callstack, test, "callstack" ); - tc[0] = t.add( &mt_test::barrier, test, "mt_test::barrier" ); tc[1] = t.add( &mt_test::join_test, test, "mt_test::join_test" ); tc[2] = t.add( &mt_test::yield, test, "mt_test::yield", @@ -74,6 +74,7 @@ t.add( &mt_test_wg21::mutex_test, test_wg21, "mt_test_wg21::mutex_test" ); t.add( &mt_test_wg21::barrier, test_wg21, "mt_test_wg21::barrier" ); t.add( &mt_test_wg21::semaphore, test_wg21, "mt_test_wg21::semaphore" ); + t.add( &mt_test_wg21::fork, test_wg21, "mt_test_wg21::fork" ); return t.girdle(); }; Modified: trunk/complement/explore/lib/mt/ut/mt_test_wg21.cc =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test_wg21.cc 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/mt_test_wg21.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <08/02/25 13:01:59 ptr> +// -*- C++ -*- Time-stamp: <08/03/26 01:53:46 ptr> /* * Copyright (c) 2006-2008 @@ -19,6 +19,10 @@ #include <iostream> +#include <sys/wait.h> +#include <sys/ipc.h> +#include <sys/shm.h> + int EXAM_IMPL(mt_test_wg21::date_time) { // using namespace std::tr2; @@ -202,3 +206,111 @@ return EXAM_RESULT; } + +int EXAM_IMPL(mt_test_wg21::fork) +{ + // trivial fork + + int v = 3; + try { + std::tr2::this_thread::fork(); + + try { + + // Child code + EXAM_CHECK_ASYNC( v == 3 ); + + v = 5; + } + catch ( ... ) { + } + + exit( 0 ); + } + catch ( std::tr2::fork_in_parent& child ) { + try { + EXAM_CHECK( child.pid() > 0 ); + + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + EXAM_CHECK( v == 3 ); + } + catch ( ... ) { + } + } + catch ( ... ) { + } + + + // less trivial fork: check interprocess communication via shared memory + + shmid_ds ds; + int id = shmget( 5000, 1024, IPC_CREAT | IPC_EXCL | 0600 ); + EXAM_REQUIRE( id != -1 ); + // if ( id == -1 ) { + // cerr << "Error on shmget" << endl; + // } + EXAM_REQUIRE( shmctl( id, IPC_STAT, &ds ) != -1 ); + // if ( shmctl( id, IPC_STAT, &ds ) == -1 ) { + // cerr << "Error on shmctl" << endl; + // } + void *buf = shmat( id, 0, 0 ); + EXAM_REQUIRE( buf != reinterpret_cast<void *>(-1) ); + // if ( buf == reinterpret_cast<void *>(-1) ) { + // cerr << "Error on shmat" << endl; + // } + + int& x = *new( buf ) int(4); + + EXAM_CHECK( x == 4 ); + + try { + std::tr2::this_thread::fork(); + + try { + + // Child code + EXAM_CHECK_ASYNC( v == 3 ); + + v = 5; + + EXAM_CHECK_ASYNC( x == 4 ); + + x = 6; + } + catch ( ... ) { + } + + exit( 0 ); + } + catch ( std::tr2::fork_in_parent& child ) { + try { + EXAM_CHECK( child.pid() > 0 ); + + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + EXAM_CHECK( v == 3 ); + EXAM_CHECK( x == 6 ); + } + catch ( ... ) { + } + } + catch ( ... ) { + } + + shmdt( buf ); + shmctl( id, IPC_RMID, &ds ); + + return EXAM_RESULT; +} + Modified: trunk/complement/explore/lib/mt/ut/mt_test_wg21.h =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test_wg21.h 2008-03-26 11:10:43 UTC (rev 1835) +++ trunk/complement/explore/lib/mt/ut/mt_test_wg21.h 2008-03-26 11:45:54 UTC (rev 1836) @@ -24,6 +24,7 @@ int EXAM_DECL(mutex_test); int EXAM_DECL(barrier); int EXAM_DECL(semaphore); + int EXAM_DECL(fork); private: // static xmt::Thread::ret_t thread_entry_call( void * ); Copied: trunk/complement/explore/lib/mt/ut/shm_test.cc (from rev 1834, branches/complement-sockios/explore/lib/mt/ut/shm_test.cc) =================================================================== --- trunk/complement/explore/lib/mt/ut/shm_test.cc (rev 0) +++ trunk/complement/explore/lib/mt/ut/shm_test.cc 2008-03-26 11:45:54 UTC (rev 1836) @@ -0,0 +1,474 @@ +// -*- C++ -*- Time-stamp: <08/03/26 10:11:58 ptr> + +/* + * Copyright (c) 2006, 2007 + * Petr Ovtchenkov + * + * Licensed under the Academic Free License Version 3.0 + * + */ + +#include "shm_test.h" + +#include <mt/xmt.h> +#include <mt/shm.h> + + +#include <sys/shm.h> +#include <sys/wait.h> + +#include <signal.h> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> + +#include <iostream> + +using namespace std; +namespace fs = boost::filesystem; + +int EXAM_IMPL(shm_test::shm_segment) +{ + const char fname[] = "/tmp/mt_test.shm"; + try { + xmt::detail::__shm_alloc<0> seg( 5000, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + + EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); + seg.deallocate(); + EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); + + EXAM_REQUIRE( !fs::exists( fname ) ); + + seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); + seg.deallocate(); + EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); + EXAM_CHECK( fs::exists( fname ) ); // well, now I don't remove ref file, because shm segment may be created with another way + + // not exclusive, should pass + seg.allocate( fname, 1024, xmt::shm_base::create, 0660 ); + EXAM_CHECK( seg.address() != reinterpret_cast<void *>(-1) ); + try { + // This instance has segment in usage, should throw + seg.allocate( fname, 1024, 0, 0660 ); + EXAM_CHECK( false ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_CHECK( true ); // Ok + } + + /* + + I will treat another instanse (<1>) as interface to another + segment, so this sample not work. + + try { + // But this is another instanse, it's ok: + xmt::detail::__shm_alloc<1> seg1( fname, 1024, 0, 0660 ); + BOOST_CHECK( seg1.address() != reinterpret_cast<void *>(-1) ); + // Don't call seg1.deallocate() here, it destroy + } + catch ( xmt::shm_bad_alloc& err ) { + BOOST_CHECK( false ); // Fail + } + */ + + seg.deallocate(); + EXAM_CHECK( seg.address() == reinterpret_cast<void *>(-1) ); + + // ---- + try { + // exclusive, should throw + seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + EXAM_CHECK( false ); // Fail, should throw + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_CHECK( true ); // Ok + } + EXAM_CHECK( fs::exists( fname ) ); + // ---- + + fs::remove( fname ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR( err.what() ); + } + + return EXAM_RESULT; +} + +/* ****************************************************** */ + +int EXAM_IMPL(shm_test::shm_alloc) +{ + const char fname[] = "/tmp/mt_test.shm"; + try { + xmt::shm_alloc<0> seg; + + seg.allocate( fname, 7000, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + + { + xmt::allocator_shm<char,0> shmall; + size_t sz = shmall.max_size(); + // two blocks + char *ch1 = shmall.allocate( 3500 ); + EXAM_CHECK( ch1 != 0 ); + char *ch2 = shmall.allocate( 3500 ); + EXAM_CHECK( ch2 != 0 ); + try { + // try to allocate third block, not enough room + char *ch3 = shmall.allocate( 8 * 1024 - 7000 ); + EXAM_CHECK( false ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_CHECK( true ); + } + // free first blocks + shmall.deallocate( ch1, 3500 ); + ch1 = shmall.allocate( 3500 ); + // allocate [first] block again + EXAM_CHECK( ch1 != 0 ); + // free second block + shmall.deallocate( ch2, 3500 ); + // allocate [second] block again + ch2 = shmall.allocate( 3500 ); + EXAM_CHECK( ch2 != 0 ); + // free both blocks + shmall.deallocate( ch1, 3500 ); + shmall.deallocate( ch2, 3500 ); + // allocate big block, enough for initial memory chunk + ch1 = shmall.allocate( 7000 ); + EXAM_CHECK( ch1 != 0 ); + // free it + shmall.deallocate( ch1, 7000 ); + // allocate block of maximum size + ch1 = shmall.allocate( sz ); + EXAM_CHECK( ch1 != 0 ); + // free it + shmall.deallocate( ch1, sz ); + // allocate block, enough for initial memory chunk + ch1 = shmall.allocate( 7000 ); + EXAM_CHECK( ch1 != 0 ); + // free it + shmall.deallocate( ch1, 7000 ); + ch1 = shmall.allocate( 3000 ); + EXAM_CHECK( ch1 != 0 ); + ch2 = shmall.allocate( 400 ); + EXAM_CHECK( ch2 != 0 ); + char *ch3 = shmall.allocate( 3500 ); + EXAM_CHECK( ch3 != 0 ); + shmall.deallocate( ch1, 3000 ); + shmall.deallocate( ch2, 400 ); + shmall.deallocate( ch3, 3500 ); + ch1 = shmall.allocate( sz ); + EXAM_CHECK( ch1 != 0 ); + shmall.deallocate( ch1, sz ); + } + seg.deallocate(); + fs::remove( fname ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR( err.what() ); + } + + return EXAM_RESULT; +} + + +/* ****************************************************** + * This test is similar mt_test::fork() above, but instead plain shm_* + * functions it use allocator based on shared memory segment + */ +int EXAM_IMPL(shm_test::fork_shm) +{ + const char fname[] = "/tmp/mt_test.shm"; + try { + xmt::shm_alloc<0> seg; + + seg.allocate( fname, 1024, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + xmt::allocator_shm<char,0> shm; + + xmt::__condition<true>& fcnd = *new( shm.allocate( sizeof(xmt::__condition<true>) ) ) xmt::__condition<true>(); + fcnd.set( false ); + try { + xmt::fork(); + + try { + + // Child code + fcnd.try_wait(); + + } + catch ( ... ) { + } + + exit( 0 ); + } + catch ( xmt::fork_in_parent& child ) { + try { + EXAM_CHECK( child.pid() > 0 ); + + fcnd.set( true ); + + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + } + catch ( ... ) { + } + } + catch ( ... ) { + } + + (&fcnd)->~__condition<true>(); + shm.deallocate( reinterpret_cast<char *>(&fcnd), sizeof(xmt::__condition<true>) ); + seg.deallocate(); + fs::remove( fname ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR( err.what() ); + } + + return EXAM_RESULT; +} + +/* ****************************************************** + * Test: how to take named object in shared memory segment + */ +int EXAM_IMPL(shm_test::shm_named_obj) +{ + const char fname[] = "/tmp/mt_test.shm"; + enum { + test_Condition_Object = 1 + }; + try { + xmt::shm_alloc<0> seg; + + seg.allocate( fname, 4*4096, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + xmt::shm_name_mgr<0>& nm = seg.name_mgr(); + + xmt::allocator_shm<xmt::__condition<true>,0> shm; + + xmt::__condition<true>& fcnd = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); + nm.named( fcnd, test_Condition_Object ); + fcnd.set( false ); + + try { + xmt::fork(); + + int eflag = 0; + + try { + + // Child code + xmt::shm_alloc<0> seg_ch; + + if ( seg_ch.max_size() == 0 ) { // just illustration, if seg and seg_ch + // (really xmt::shm_alloc<0>) + // in totally different address spaces + // in our case xmt::shm_name_mgr<0> instance derived from parent + // process + seg.allocate( fname, 4*4096, 0, 0660 ); + } + + xmt::shm_name_mgr<0>& nm_ch = seg_ch.name_mgr(); + xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( test_Condition_Object ); + fcnd_ch.set( true ); + } + catch ( const xmt::shm_bad_alloc& err ) { + EXAM_ERROR_ASYNC_F( err.what(), eflag ); + } + catch ( const std::invalid_argument& err ) { + EXAM_ERROR_ASYNC_F( err.what(), eflag ); + } + catch ( ... ) { + EXAM_ERROR_ASYNC_F( "Fail in child", eflag ); + } + + exit( eflag ); + } + catch ( xmt::fork_in_parent& child ) { + try { + EXAM_CHECK( child.pid() > 0 ); + + fcnd.try_wait(); + + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + } + catch ( ... ) { + EXAM_ERROR( "Fail in parent" ); + } + } + catch ( ... ) { + EXAM_ERROR( "Fail in fork" ); + } + + (&fcnd)->~__condition<true>(); + shm.deallocate( &fcnd, 1 ); + seg.deallocate(); + fs::remove( fname ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR( err.what() ); + } + + return EXAM_RESULT; +} + +/* ****************************************************** + */ +const char shm_test::fname1[] = "/tmp/mt_test.shm.1"; + +shm_test::shm_test() +{ + try { + seg1.allocate( fname1, 4*4096, xmt::shm_base::create | xmt::shm_base::exclusive, 0660 ); + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR_ASYNC( err.what() ); + } +} + +/* ****************************************************** + */ +shm_test::~shm_test() +{ + seg1.deallocate(); + fs::remove( fname1 ); +} + +/* ****************************************************** + */ + +int EXAM_IMPL(shm_test::shm_named_obj_more) +{ + enum { + ObjName = 1 + }; + + try { + xmt::shm_name_mgr<1>& nm = seg1.name_mgr(); + + xmt::allocator_shm<xmt::__condition<true>,1> shm; + + xmt::__condition<true>& fcnd = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); + nm.named( fcnd, ObjName ); + fcnd.set( false ); + + try { + xmt::fork(); + + int eflag = 0; + + try { + xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); + xmt::allocator_shm<xmt::__condition<true>,1> shm_ch; + xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( ObjName ); + fcnd_ch.set( true ); + nm_ch.release<xmt::__condition<true> >( ObjName ); + } + catch ( const std::invalid_argument& err ) { + EXAM_ERROR_ASYNC_F( err.what(), eflag ); + } + exit( eflag ); + } + catch ( xmt::fork_in_parent& child ) { + fcnd.try_wait(); + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + } + nm.release<xmt::__condition<true> >( ObjName ); // fcnd should be destroyed here + + xmt::__condition<true>& fcnd1 = *new ( shm.allocate( 1 ) ) xmt::__condition<true>(); + nm.named( fcnd1, ObjName ); // ObjName should be free here + fcnd1.set( false ); + + try { + xmt::fork(); + + int eflag = 0; + + try { + xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); + xmt::allocator_shm<xmt::__condition<true>,1> shm_ch; + xmt::__condition<true>& fcnd_ch = nm_ch.named<xmt::__condition<true> >( ObjName ); + fcnd_ch.set( true ); + nm_ch.release<xmt::__condition<true> >( ObjName ); + } + catch ( const std::invalid_argument& err ) { + EXAM_ERROR_ASYNC_F( err.what(), eflag ); + } + + exit( eflag ); + } + catch ( xmt::fork_in_parent& child ) { + fcnd1.try_wait(); + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + } + nm.release<xmt::__condition<true> >( ObjName ); // fcnd should be destroyed here + + xmt::allocator_shm<xmt::__barrier<true>,1> shm_b; + xmt::__barrier<true>& b = *new ( shm_b.allocate( 1 ) ) xmt::__barrier<true>(); + + nm.named( b, ObjName ); // ObjName should be free here + + try { + xmt::fork(); + + int eflag = 0; + try { + xmt::shm_name_mgr<1>& nm_ch = seg1.name_mgr(); + xmt::allocator_shm<xmt::__barrier<true>,1> shm_ch; + xmt::__barrier<true>& b_ch = nm_ch.named<xmt::__barrier<true> >( ObjName ); + b_ch.wait(); + nm_ch.release<xmt::__barrier<true> >( ObjName ); + } + catch ( const std::invalid_argument& err ) { + EXAM_ERROR_ASYNC_F( err.what(), eflag ); + } + + exit( eflag ); + } + catch ( xmt::fork_in_parent& child ) { + b.wait(); + int stat = -1; + EXAM_CHECK( waitpid( child.pid(), &stat, 0 ) == child.pid() ); + if ( WIFEXITED(stat) ) { + EXAM_CHECK( WEXITSTATUS(stat) == 0 ); + } else { + EXAM_ERROR( "child interrupted" ); + } + } + nm.release<xmt::__barrier<true> >( ObjName ); // barrier should be destroyed here + } + catch ( xmt::shm_bad_alloc& err ) { + EXAM_ERROR( err.what() ); + } + catch ( const std::invalid_argument& err ) { + EXAM_ERROR( err.what() ); + } + + return EXAM_RESULT; +} + Copied: trunk/complement/explore/lib/mt/ut/shm_test.h (from rev 1834, branches/complement-sockios/explore/lib/mt/ut/shm_test.h) =================================================================== --- trunk/complement/explore/lib/mt/ut/shm_test.h (rev 0) +++ trunk/complement/explore/lib/mt/ut/shm_test.h 2008-03-26 11:45:54 UTC (rev 1836) @@ -0,0 +1,37 @@ +// -*- C++ -*- Time-stamp: <08/03/26 10:10:18 ptr> + +/* + * Copyright (c) 2006, 2007 + * Petr Ovtchenkov + * + * Licensed under the Academic Free License Version 3.0 + * + */ + +#ifndef __SHM_TEST_H +#define __SHM_TEST_H + +#define FIT_EXAM + +#include <exam/suite.h> +#include <mt/shm.h> + +class shm_test +{ + public: + shm_test(); + ~shm_test(); + + int EXAM_DECL(shm_segment); + int EXAM_DECL(shm_alloc); + int EXAM_DECL(fork_shm); + int EXAM_DECL(shm_named_obj); + + int EXAM_DECL(shm_named_obj_more); + + private: + xmt::shm_alloc<1> seg1; + static const char fname1[]; +}; + +#endif // __SHM_TEST_H This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |