2
0
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:
Peter Dimov
2006-07-24 19:00:30 +00:00
parent 34bd87cea7
commit acf0f97663

View File

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