Skip to content

Commit

Permalink
Adding hpx::lcos::local::call_once
Browse files Browse the repository at this point in the history
(cherry picked from commit b55da9330d14ae62642077c910b7851439427529)
  • Loading branch information
hkaiser committed Jan 5, 2013
1 parent 4374df1 commit 3e4992c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 155 deletions.
1 change: 1 addition & 0 deletions hpx/hpx_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <hpx/config.hpp>
#include <hpx/config/function.hpp>
#include <hpx/traits.hpp>
#include <hpx/lcos/local/once_fwd.hpp>
#include <hpx/util/unused.hpp>
#include <hpx/util/coroutine/coroutine.hpp>
#include <hpx/runtime/threads/detail/tagged_thread_state.hpp>
Expand Down
183 changes: 28 additions & 155 deletions hpx/lcos/local/once.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,115 +11,30 @@
#define HPX_LCOS_LOCAL_ONCE_JAN_03_2013_0810PM

#include <hpx/hpx_fwd.hpp>

#include <cstring>
#include <cstddef>
#include <hpx/lcos/local/event.hpp>
#include <hpx/lcos/local/once_fwd.hpp>

#include <boost/assert.hpp>
#include <boost/atomic.hpp>

// #include <boost/detail/interlocked.hpp>
// #include <boost/thread/win32/thread_primitives.hpp>
// #include <boost/thread/win32/interlocked_read.hpp>
// #include <boost/detail/no_exceptions_support.hpp>
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>

namespace hpx { namespace lcos { namespace local
{
struct once_flag : boost::noncopyable
{
BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
: status(0), count(0), event_(0)
: status_(0)
{}

private:
boost::atomic<long> status;
boost::atomic<long> count;
local::event event_;
boost::atomic<long> status_;
lcos::local::event event_;

template <typename Function>
friend void call_once(once_flag& flag, Function f);
};

#define HPX_ONCE_INIT once_flag()

// namespace detail
// {
// #ifdef BOOST_NO_ANSI_APIS
// typedef wchar_t once_char_type;
// #else
// typedef char once_char_type;
// #endif
// unsigned const once_mutex_name_fixed_length=54;
// unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
// sizeof(void*)*2+sizeof(unsigned long)*2+1;
//
// template <class I>
// void int_to_string(I p, once_char_type* buf)
// {
// for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
// {
// #ifdef BOOST_NO_ANSI_APIS
// once_char_type const a=L'A';
// #else
// once_char_type const a='A';
// #endif
// *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
// }
// *buf = 0;
// }
//
// inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
// {
// #ifdef BOOST_NO_ANSI_APIS
// static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
// #else
// static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
// #endif
// BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
// (sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
//
// std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
// detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
// mutex_name + once_mutex_name_fixed_length);
// detail::int_to_string(win32::GetCurrentProcessId(),
// mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
// }
//
// inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
// {
// if(!*mutex_name)
// {
// name_once_mutex(mutex_name,flag_address);
// }
//
// #ifdef BOOST_NO_ANSI_APIS
// return ::boost::detail::win32::OpenEventW(
// #else
// return ::boost::detail::win32::OpenEventA(
// #endif
// ::boost::detail::win32::synchronize |
// ::boost::detail::win32::event_modify_state,
// false,
// mutex_name);
// }
//
// inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
// {
// if(!*mutex_name)
// {
// name_once_mutex(mutex_name,flag_address);
// }
// #ifdef BOOST_NO_ANSI_APIS
// return ::boost::detail::win32::CreateEventW(
// #else
// return ::boost::detail::win32::CreateEventA(
// #endif
// 0,::boost::detail::win32::manual_reset_event,
// ::boost::detail::win32::event_initially_reset,
// mutex_name);
// }
// }

///////////////////////////////////////////////////////////////////////////
template <typename Function>
void call_once(once_flag& flag, Function f)
Expand All @@ -128,84 +43,42 @@ namespace hpx { namespace lcos { namespace local
// just skip through:
long const function_complete_flag_value = 0xc15730e2;
long const running_value = 0x7f0725e3;
long status;
bool counted = false;

// detail::win32::handle_manager event_handle;
// detail::once_char_type mutex_name[detail::once_mutex_name_length];
// mutex_name[0] = 0;

while (flag.status.load(boost::memory_order_acquire) !=
while (flag.status_.load(boost::memory_order_acquire) !=
function_complete_flag_value)
{
status = 0;
if (flag.status.compare_exchange_strong(status, running_value))
long status = 0;
if (flag.status_.compare_exchange_strong(status, running_value))
{
try {
if (!event_handle)
{
event_handle=detail::open_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::ResetEvent(event_handle);
}
// reset event to ensure its usability in case the
// wrapped function was throwing an exception before
flag.event_.reset();

f();

if (!counted)
{
++flag.count;
counted.store(true);
}
BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
if(!event_handle &&
(::boost::detail::interlocked_read_acquire(&flag.count)>1))
{
event_handle=detail::create_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::SetEvent(event_handle);
}
// set status to done, release waiting threads
flag.status_.store(function_complete_flag_value);
flag.event_.set();
break;
}
catch (...) {
flag.status.exchange(0);
if(!event_handle)
{
event_handle=detail::open_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::SetEvent(event_handle);
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
// reset status to initial, release waiting threads
flag.status_.store(0);
flag.event_.set();

if(!counted)
{
BOOST_INTERLOCKED_INCREMENT(&flag.count);
counted=true;
status=::boost::detail::interlocked_read_acquire(&flag.status);
if(status==function_complete_flag_value)
{
break;
}
if(!event_handle)
{
event_handle=detail::create_once_event(mutex_name,&flag);
continue;
throw;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
event_handle,::boost::detail::win32::infinite));

// we're done if function was called
if (status == function_complete_flag_value)
break;

// wait for the function finish executing
flag.event_.wait();
}
}
}

#include <boost/config/abi_suffix.hpp>
}}}

#endif
18 changes: 18 additions & 0 deletions hpx/lcos/local/once_fwd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2013 Hartmut Kaiser
//
// Distributed under 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)

#if !defined(HPX_LCOS_LOCAL_ONCE_FWD_JAN_05_2013_0427PM)
#define HPX_LCOS_LOCAL_ONCE_FWD_JAN_05_2013_0427PM

namespace hpx { namespace lcos { namespace local
{
// call_once support
struct once_flag;
}}}

#define HPX_ONCE_INIT hpx::lcos::local::once_flag()

#endif

0 comments on commit 3e4992c

Please sign in to comment.