mirror of
https://github.com/boostorg/thread.git
synced 2026-01-27 19:32:11 +00:00
Simplification, avoids a false leak report
[SVN r34706]
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Copyright (c) 2006 Peter Dimov
|
||||
//
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,178 +9,148 @@
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <list>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
namespace
|
||||
namespace
|
||||
{
|
||||
|
||||
typedef std::list<thread_exit_handler> thread_exit_handlers;
|
||||
|
||||
const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
|
||||
DWORD tls_key = invalid_tls_key;
|
||||
|
||||
boost::once_flag once_init_tls_key = BOOST_ONCE_INIT;
|
||||
|
||||
void init_tls_key()
|
||||
{
|
||||
tls_key = TlsAlloc();
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int at_thread_exit( thread_exit_handler exit_handler )
|
||||
{
|
||||
boost::call_once( init_tls_key, once_init_tls_key );
|
||||
|
||||
if( tls_key == invalid_tls_key )
|
||||
{
|
||||
typedef std::list<thread_exit_handler> thread_exit_handlers;
|
||||
|
||||
boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
|
||||
boost::mutex* threadmon_mutex;
|
||||
void init_threadmon_mutex(void)
|
||||
{
|
||||
threadmon_mutex = new boost::mutex;
|
||||
if (!threadmon_mutex)
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
|
||||
const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
|
||||
DWORD tls_key = invalid_tls_key;
|
||||
|
||||
unsigned long attached_thread_count = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Calls to DllMain() and tls_callback() are serialized by the OS;
|
||||
however, calls to at_thread_exit are not, so it must be protected
|
||||
by a mutex. Since we already need a mutex for at_thread_exit(),
|
||||
and since there is no guarantee that on_process_enter(),
|
||||
on_process_exit(), on_thread_enter(), and on_thread_exit()
|
||||
will be called only from DllMain() or tls_callback(), it makes
|
||||
sense to protect those, too.
|
||||
*/
|
||||
// Get the exit handlers list for the current thread from tls.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int at_thread_exit(
|
||||
thread_exit_handler exit_handler
|
||||
)
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
|
||||
|
||||
if( exit_handlers == 0 )
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
|
||||
//Allocate a tls slot if necessary.
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
tls_key = TlsAlloc();
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
return -1;
|
||||
|
||||
//Get the exit handlers list for the current thread from tls.
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
|
||||
|
||||
if (!exit_handlers)
|
||||
{
|
||||
//No exit handlers list was created yet.
|
||||
|
||||
try
|
||||
{
|
||||
//Attempt to create a new exit handlers list.
|
||||
|
||||
exit_handlers = new thread_exit_handlers;
|
||||
if (!exit_handlers)
|
||||
return -1;
|
||||
|
||||
//Attempt to store the list pointer in tls.
|
||||
|
||||
if (TlsSetValue(tls_key, exit_handlers))
|
||||
++attached_thread_count;
|
||||
else
|
||||
{
|
||||
delete exit_handlers;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Like the C runtime library atexit() function,
|
||||
//functions should be called in the reverse of
|
||||
//the order they are added, so push them on the
|
||||
//front of the list.
|
||||
// No exit handlers list was created yet.
|
||||
|
||||
try
|
||||
{
|
||||
exit_handlers->push_front(exit_handler);
|
||||
// Attempt to create a new exit handlers list.
|
||||
|
||||
exit_handlers = new thread_exit_handlers;
|
||||
|
||||
if( exit_handlers == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Attempt to store the list pointer in tls.
|
||||
|
||||
if( !TlsSetValue( tls_key, exit_handlers ) )
|
||||
{
|
||||
delete exit_handlers;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
catch( ... )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Like the atexit() function, a result of zero
|
||||
//indicates success.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
// Like the C runtime library atexit() function,
|
||||
// functions should be called in the reverse of
|
||||
// the order they are added, so push them on the
|
||||
// front of the list.
|
||||
|
||||
BOOST_ASSERT(attached_thread_count == 0);
|
||||
try
|
||||
{
|
||||
exit_handlers->push_front( exit_handler );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
|
||||
// Like the atexit() function, a result of zero
|
||||
// indicates success.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
||||
{
|
||||
// Initializing tls_key here ensures its proper visibility
|
||||
boost::call_once( init_tls_key, once_init_tls_key );
|
||||
|
||||
// Get the exit handlers list for the current thread from tls.
|
||||
|
||||
if( tls_key == invalid_tls_key )
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(attached_thread_count == 0);
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
|
||||
|
||||
//Free the tls slot if one was allocated.
|
||||
// If a handlers list was found, invoke its handlers.
|
||||
|
||||
if (tls_key != invalid_tls_key)
|
||||
if( exit_handlers != 0 )
|
||||
{
|
||||
// Call each handler and remove it from the list
|
||||
|
||||
while( !exit_handlers->empty() )
|
||||
{
|
||||
TlsFree(tls_key);
|
||||
tls_key = invalid_tls_key;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
|
||||
{
|
||||
//boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
//boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
|
||||
{
|
||||
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
|
||||
//Get the exit handlers list for the current thread from tls.
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
return;
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
|
||||
|
||||
//If a handlers list was found, use it.
|
||||
|
||||
if (exit_handlers && TlsSetValue(tls_key, 0))
|
||||
{
|
||||
BOOST_ASSERT(attached_thread_count > 0);
|
||||
--attached_thread_count;
|
||||
|
||||
lock.unlock();
|
||||
|
||||
//Call each handler and remove it from the list
|
||||
|
||||
while (!exit_handlers->empty())
|
||||
if( thread_exit_handler exit_handler = *exit_handlers->begin() )
|
||||
{
|
||||
if (thread_exit_handler exit_handler = *exit_handlers->begin())
|
||||
(*exit_handler)();
|
||||
exit_handlers->pop_front();
|
||||
(*exit_handler)();
|
||||
}
|
||||
|
||||
exit_handlers->pop_front();
|
||||
}
|
||||
|
||||
// If TlsSetValue fails, we can't delete the list,
|
||||
// since a second call to on_thread_exit will try
|
||||
// to access it.
|
||||
|
||||
if( TlsSetValue( tls_key, 0 ) )
|
||||
{
|
||||
delete exit_handlers;
|
||||
exit_handlers = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
Reference in New Issue
Block a user