mirror of
https://github.com/boostorg/asio.git
synced 2026-01-27 18:42:07 +00:00
Merge from trunk.
........ r49155 | nmusatti | 2008-10-07 08:46:14 +1100 (Tue, 07 Oct 2008) | 1 line Patch from Ticket #2372 ........ r49195 | chris_kohlhoff | 2008-10-09 17:22:58 +1100 (Thu, 09 Oct 2008) | 2 lines Add missing bounds checks as specified in TR2 proposal. ........ r49197 | chris_kohlhoff | 2008-10-09 17:28:39 +1100 (Thu, 09 Oct 2008) | 2 lines Merge codegear changes from non-boost version of asio. ........ r49198 | chris_kohlhoff | 2008-10-09 17:30:16 +1100 (Thu, 09 Oct 2008) | 4 lines Ensure the streambuf's egptr() is kept in sync the pptr(). Use std::memmove rather than std::rotate to minimise data copying. Avoid unnecessary resizes of the underlying vector. ........ r49199 | chris_kohlhoff | 2008-10-09 17:31:01 +1100 (Thu, 09 Oct 2008) | 3 lines Fix basic_socket_streambuf to work with Protocol objects that don't provide a resolver. ........ r49200 | chris_kohlhoff | 2008-10-09 17:32:00 +1100 (Thu, 09 Oct 2008) | 2 lines Add example showing use of local::stream_protocol::iostream. ........ r49201 | chris_kohlhoff | 2008-10-09 17:33:34 +1100 (Thu, 09 Oct 2008) | 4 lines Only use TerminateThread when explicitly requested by the user by calling asio::detail::thread::set_terminate_threads(true). This fixes a memory leak that may occur with internally created threads. ........ r49202 | chris_kohlhoff | 2008-10-09 17:34:48 +1100 (Thu, 09 Oct 2008) | 3 lines Make the service_registry's usage of typeid work when the default gcc linker visibility is set to hidden. ........ r49203 | chris_kohlhoff | 2008-10-09 17:39:05 +1100 (Thu, 09 Oct 2008) | 2 lines Reduce memory usage by doing lazy initialisation of the io_service's reactor. ........ [SVN r49221]
This commit is contained in:
@@ -33,6 +33,18 @@ exe connect_pair
|
||||
$(SOCKET_LIBS)
|
||||
;
|
||||
|
||||
exe iostream_client
|
||||
: <lib>@boost/libs/system/build/boost_system
|
||||
iostream_client.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
<include>../../../..
|
||||
<define>BOOST_ALL_NO_LIB=1
|
||||
<threading>multi
|
||||
<mingw><*><find-library>ws2_32
|
||||
<mingw><*><find-library>mswsock
|
||||
$(SOCKET_LIBS)
|
||||
;
|
||||
|
||||
exe stream_client
|
||||
: <lib>@boost/libs/system/build/boost_system
|
||||
stream_client.cpp
|
||||
|
||||
@@ -38,6 +38,21 @@ exe connect_pair
|
||||
<os>HPUX:<library>ipv6
|
||||
;
|
||||
|
||||
exe iostream_client
|
||||
: iostream_client.cpp
|
||||
/boost/system//boost_system
|
||||
: <define>BOOST_ALL_NO_LIB=1
|
||||
<threading>multi
|
||||
<os>SOLARIS:<library>socket
|
||||
<os>SOLARIS:<library>nsl
|
||||
<os>NT:<define>_WIN32_WINNT=0x0501
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>mswsock
|
||||
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
||||
<os>HPUX:<library>ipv6
|
||||
;
|
||||
|
||||
exe stream_client
|
||||
: stream_client.cpp
|
||||
/boost/system//boost_system
|
||||
|
||||
59
example/local/iostream_client.cpp
Normal file
59
example/local/iostream_client.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// stream_client.cpp
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
|
||||
|
||||
using boost::asio::local::stream_protocol;
|
||||
|
||||
enum { max_length = 1024 };
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: iostream_client <file>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
stream_protocol::endpoint ep(argv[1]);
|
||||
stream_protocol::iostream s(ep);
|
||||
|
||||
using namespace std; // For strlen.
|
||||
std::cout << "Enter message: ";
|
||||
char request[max_length];
|
||||
std::cin.getline(request, max_length);
|
||||
size_t length = strlen(request);
|
||||
s << request;
|
||||
|
||||
char reply[max_length];
|
||||
s.read(reply, length);
|
||||
std::cout << "Reply is: ";
|
||||
std::cout.write(reply, length);
|
||||
std::cout << "\n";
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
|
||||
# error Local sockets not available on this platform.
|
||||
#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
|
||||
@@ -248,7 +248,8 @@ private:
|
||||
setp(put_buffer_.begin(), put_buffer_.end());
|
||||
}
|
||||
|
||||
void resolve_and_connect(const typename Protocol::resolver_query& query,
|
||||
template <typename ResolverQuery>
|
||||
void resolve_and_connect(const ResolverQuery& query,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
typedef typename Protocol::resolver resolver_type;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@@ -96,6 +97,7 @@ public:
|
||||
if (pptr() + n > epptr())
|
||||
n = epptr() - pptr();
|
||||
pbump(static_cast<int>(n));
|
||||
setg(eback(), gptr(), pptr());
|
||||
}
|
||||
|
||||
/// Move the start of the get area by the specified number of characters.
|
||||
@@ -151,7 +153,6 @@ protected:
|
||||
{
|
||||
// Get current stream positions as offsets.
|
||||
std::size_t gnext = gptr() - &buffer_[0];
|
||||
std::size_t gend = egptr() - &buffer_[0];
|
||||
std::size_t pnext = pptr() - &buffer_[0];
|
||||
std::size_t pend = epptr() - &buffer_[0];
|
||||
|
||||
@@ -164,9 +165,8 @@ protected:
|
||||
// Shift existing contents of get area to start of buffer.
|
||||
if (gnext > 0)
|
||||
{
|
||||
std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
|
||||
gend -= gnext;
|
||||
pnext -= gnext;
|
||||
std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
|
||||
}
|
||||
|
||||
// Ensure buffer is large enough to hold at least the specified size.
|
||||
@@ -174,7 +174,8 @@ protected:
|
||||
{
|
||||
if (n <= max_size_ && pnext <= max_size_ - n)
|
||||
{
|
||||
buffer_.resize((std::max<std::size_t>)(pnext + n, 1));
|
||||
pend = pnext + n;
|
||||
buffer_.resize((std::max<std::size_t>)(pend, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,8 +184,8 @@ protected:
|
||||
}
|
||||
|
||||
// Update stream positions.
|
||||
setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend);
|
||||
setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n);
|
||||
setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
|
||||
setp(&buffer_[0] + pnext, &buffer_[0] + pend);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
|
||||
scheduler_(boost::asio::use_service<Timer_Scheduler>(io_service))
|
||||
{
|
||||
scheduler_.init_task();
|
||||
scheduler_.add_timer_queue(timer_queue_);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,17 @@ public:
|
||||
timer_queues_.clear();
|
||||
}
|
||||
|
||||
// Initialise the task, but only if the reactor is not in its own thread.
|
||||
void init_task()
|
||||
{
|
||||
if (!Own_Thread)
|
||||
{
|
||||
typedef task_io_service<dev_poll_reactor<Own_Thread> >
|
||||
task_io_service_type;
|
||||
use_service<task_io_service_type>(this->get_io_service()).init_task();
|
||||
}
|
||||
}
|
||||
|
||||
// Register a socket with the reactor. Returns 0 on success, system error
|
||||
// code on failure.
|
||||
int register_descriptor(socket_type, per_descriptor_data&)
|
||||
|
||||
@@ -124,6 +124,16 @@ public:
|
||||
timer_queues_.clear();
|
||||
}
|
||||
|
||||
// Initialise the task, but only if the reactor is not in its own thread.
|
||||
void init_task()
|
||||
{
|
||||
if (!Own_Thread)
|
||||
{
|
||||
typedef task_io_service<epoll_reactor<Own_Thread> > task_io_service_type;
|
||||
use_service<task_io_service_type>(this->get_io_service()).init_task();
|
||||
}
|
||||
}
|
||||
|
||||
// Register a socket with the reactor. Returns 0 on success, system error
|
||||
// code on failure.
|
||||
int register_descriptor(socket_type descriptor,
|
||||
|
||||
@@ -132,6 +132,16 @@ public:
|
||||
timer_queues_.clear();
|
||||
}
|
||||
|
||||
// Initialise the task, but only if the reactor is not in its own thread.
|
||||
void init_task()
|
||||
{
|
||||
if (!Own_Thread)
|
||||
{
|
||||
typedef task_io_service<kqueue_reactor<Own_Thread> > task_io_service_type;
|
||||
use_service<task_io_service_type>(this->get_io_service()).init_task();
|
||||
}
|
||||
}
|
||||
|
||||
// Register a socket with the reactor. Returns 0 on success, system error
|
||||
// code on failure.
|
||||
int register_descriptor(socket_type, per_descriptor_data& descriptor_data)
|
||||
|
||||
@@ -39,12 +39,9 @@ class null_thread
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
// The purpose of the thread.
|
||||
enum purpose { internal, external };
|
||||
|
||||
// Constructor.
|
||||
template <typename Function>
|
||||
null_thread(Function f, purpose = internal)
|
||||
null_thread(Function f)
|
||||
{
|
||||
boost::system::system_error e(
|
||||
boost::asio::error::operation_not_supported, "thread");
|
||||
|
||||
@@ -43,12 +43,9 @@ class posix_thread
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
// The purpose of the thread.
|
||||
enum purpose { internal, external };
|
||||
|
||||
// Constructor.
|
||||
template <typename Function>
|
||||
posix_thread(Function f, purpose = internal)
|
||||
posix_thread(Function f)
|
||||
: joined_(false)
|
||||
{
|
||||
std::auto_ptr<func_base> arg(new func<Function>(f));
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
reactive_descriptor_service<Reactor> >(io_service),
|
||||
reactor_(boost::asio::use_service<Reactor>(io_service))
|
||||
{
|
||||
reactor_.init_task();
|
||||
}
|
||||
|
||||
// Destroy all user-defined handler objects owned by the service.
|
||||
|
||||
@@ -110,6 +110,7 @@ public:
|
||||
reactive_socket_service<Protocol, Reactor> >(io_service),
|
||||
reactor_(boost::asio::use_service<Reactor>(io_service))
|
||||
{
|
||||
reactor_.init_task();
|
||||
}
|
||||
|
||||
// Destroy all user-defined handler objects owned by the service.
|
||||
|
||||
@@ -111,6 +111,16 @@ public:
|
||||
timer_queues_.clear();
|
||||
}
|
||||
|
||||
// Initialise the task, but only if the reactor is not in its own thread.
|
||||
void init_task()
|
||||
{
|
||||
if (!Own_Thread)
|
||||
{
|
||||
typedef task_io_service<select_reactor<Own_Thread> > task_io_service_type;
|
||||
use_service<task_io_service_type>(this->get_io_service()).init_task();
|
||||
}
|
||||
}
|
||||
|
||||
// Register a socket with the reactor. Returns 0 on success, system error
|
||||
// code on failure.
|
||||
int register_descriptor(socket_type, per_descriptor_data&)
|
||||
|
||||
@@ -37,6 +37,21 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
# pragma GCC visibility push (default)
|
||||
# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
#endif // defined(__GNUC__)
|
||||
|
||||
template <typename T>
|
||||
class typeid_wrapper {};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
# pragma GCC visibility pop
|
||||
# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
#endif // defined(__GNUC__)
|
||||
|
||||
class service_registry
|
||||
: private noncopyable
|
||||
{
|
||||
@@ -169,7 +184,7 @@ private:
|
||||
void init_service_id(boost::asio::io_service::service& service,
|
||||
const boost::asio::detail::service_id<Service>& /*id*/)
|
||||
{
|
||||
service.type_info_ = &typeid(Service);
|
||||
service.type_info_ = &typeid(typeid_wrapper<Service>);
|
||||
service.id_ = 0;
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_TYPEID)
|
||||
@@ -189,7 +204,8 @@ private:
|
||||
const boost::asio::io_service::service& service,
|
||||
const boost::asio::detail::service_id<Service>& /*id*/)
|
||||
{
|
||||
return service.type_info_ != 0 && *service.type_info_ == typeid(Service);
|
||||
return service.type_info_ != 0
|
||||
&& *service.type_info_ == typeid(typeid_wrapper<Service>);
|
||||
}
|
||||
#endif // !defined(BOOST_ASIO_NO_TYPEID)
|
||||
|
||||
|
||||
@@ -44,14 +44,13 @@ public:
|
||||
task_io_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::detail::service_base<task_io_service<Task> >(io_service),
|
||||
mutex_(),
|
||||
task_(use_service<Task>(io_service)),
|
||||
task_(0),
|
||||
task_interrupted_(true),
|
||||
outstanding_work_(0),
|
||||
stopped_(false),
|
||||
shutdown_(false),
|
||||
first_idle_thread_(0)
|
||||
{
|
||||
handler_queue_.push(&task_handler_);
|
||||
}
|
||||
|
||||
void init(size_t /*concurrency_hint*/)
|
||||
@@ -74,8 +73,20 @@ public:
|
||||
h->destroy();
|
||||
}
|
||||
|
||||
// Reset handler queue to initial state.
|
||||
handler_queue_.push(&task_handler_);
|
||||
// Reset to initial state.
|
||||
task_ = 0;
|
||||
}
|
||||
|
||||
// Initialise the task, if required.
|
||||
void init_task()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
if (!shutdown_ && !task_)
|
||||
{
|
||||
task_ = &use_service<Task>(this->get_io_service());
|
||||
handler_queue_.push(&task_handler_);
|
||||
interrupt_one_idle_thread(lock);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the event loop until interrupted or no more work.
|
||||
@@ -194,10 +205,10 @@ public:
|
||||
// Wake up a thread to execute the handler.
|
||||
if (!interrupt_one_idle_thread(lock))
|
||||
{
|
||||
if (!task_interrupted_)
|
||||
if (!task_interrupted_ && task_)
|
||||
{
|
||||
task_interrupted_ = true;
|
||||
task_.interrupt();
|
||||
task_->interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,7 +257,7 @@ private:
|
||||
// Run the task. May throw an exception. Only block if the handler
|
||||
// queue is empty and we have an idle_thread_info object, otherwise
|
||||
// we want to return as soon as possible.
|
||||
task_.run(!more_handlers && !polling);
|
||||
task_->run(!more_handlers && !polling);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -285,10 +296,10 @@ private:
|
||||
{
|
||||
stopped_ = true;
|
||||
interrupt_all_idle_threads(lock);
|
||||
if (!task_interrupted_)
|
||||
if (!task_interrupted_ && task_)
|
||||
{
|
||||
task_interrupted_ = true;
|
||||
task_.interrupt();
|
||||
task_->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +387,7 @@ private:
|
||||
boost::asio::detail::mutex mutex_;
|
||||
|
||||
// The task to be run by this service.
|
||||
Task& task_;
|
||||
Task* task_;
|
||||
|
||||
// Handler object to represent the position of the task in the queue.
|
||||
class task_handler
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
: boost::asio::detail::service_base<task_io_service<Task> >(io_service),
|
||||
front_mutex_(),
|
||||
back_mutex_(),
|
||||
task_(use_service<Task>(io_service)),
|
||||
task_(&use_service<Task>(io_service)),
|
||||
outstanding_work_(0),
|
||||
front_stopped_(false),
|
||||
back_stopped_(false),
|
||||
@@ -58,7 +58,6 @@ public:
|
||||
back_first_idle_thread_(0),
|
||||
back_task_thread_(0)
|
||||
{
|
||||
handler_queue_.push(&task_handler_);
|
||||
}
|
||||
|
||||
void init(size_t /*concurrency_hint*/)
|
||||
@@ -77,8 +76,20 @@ public:
|
||||
if (h != &task_handler_)
|
||||
h->destroy();
|
||||
|
||||
// Reset handler queue to initial state.
|
||||
handler_queue_.push(&task_handler_);
|
||||
// Reset to initial state.
|
||||
task_ = 0;
|
||||
}
|
||||
|
||||
// Initialise the task, if required.
|
||||
void init_task()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
|
||||
if (!back_shutdown_ && !task_)
|
||||
{
|
||||
task_ = &use_service<Task>(this->get_io_service());
|
||||
handler_queue_.push(&task_handler_);
|
||||
interrupt_one_idle_thread(back_lock);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the event loop until interrupted or no more work.
|
||||
@@ -287,7 +298,7 @@ private:
|
||||
// queue is empty and we're not polling, otherwise we want to return
|
||||
// as soon as possible.
|
||||
task_has_run = true;
|
||||
task_.run(!more_handlers && !polling);
|
||||
task_->run(!more_handlers && !polling);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -342,10 +353,10 @@ private:
|
||||
idle_thread->next = 0;
|
||||
idle_thread->wakeup_event.signal(back_lock);
|
||||
}
|
||||
else if (back_task_thread_)
|
||||
else if (back_task_thread_ && task_)
|
||||
{
|
||||
back_task_thread_ = 0;
|
||||
task_.interrupt();
|
||||
task_->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,10 +372,10 @@ private:
|
||||
idle_thread->wakeup_event.signal(back_lock);
|
||||
}
|
||||
|
||||
if (back_task_thread_)
|
||||
if (back_task_thread_ && task_)
|
||||
{
|
||||
back_task_thread_ = 0;
|
||||
task_.interrupt();
|
||||
task_->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +426,7 @@ private:
|
||||
boost::asio::detail::mutex back_mutex_;
|
||||
|
||||
// The task to be run by this service.
|
||||
Task& task_;
|
||||
Task* task_;
|
||||
|
||||
// Handler object to represent the position of the task in the queue.
|
||||
class task_handler
|
||||
|
||||
@@ -149,6 +149,11 @@ public:
|
||||
timer_queues_.clear();
|
||||
}
|
||||
|
||||
// Initialise the task. Nothing to do here.
|
||||
void init_task()
|
||||
{
|
||||
}
|
||||
|
||||
// Register a handle with the IO completion port.
|
||||
boost::system::error_code register_handle(
|
||||
HANDLE handle, boost::system::error_code& ec)
|
||||
|
||||
@@ -40,50 +40,67 @@ namespace detail {
|
||||
|
||||
unsigned int __stdcall win_thread_function(void* arg);
|
||||
|
||||
class win_thread
|
||||
: private noncopyable
|
||||
#if (WINVER < 0x0500)
|
||||
void __stdcall apc_function(ULONG data);
|
||||
#else
|
||||
void __stdcall apc_function(ULONG_PTR data);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class win_thread_base
|
||||
{
|
||||
public:
|
||||
// The purpose of the thread.
|
||||
enum purpose { internal, external };
|
||||
static bool terminate_threads()
|
||||
{
|
||||
return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;
|
||||
}
|
||||
|
||||
static void set_terminate_threads(bool b)
|
||||
{
|
||||
::InterlockedExchange(&terminate_threads_, b ? 1 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
static long terminate_threads_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
long win_thread_base<T>::terminate_threads_ = 0;
|
||||
|
||||
class win_thread
|
||||
: private noncopyable,
|
||||
public win_thread_base<win_thread>
|
||||
{
|
||||
public:
|
||||
// Constructor.
|
||||
template <typename Function>
|
||||
win_thread(Function f, purpose p = internal)
|
||||
win_thread(Function f)
|
||||
: exit_event_(0)
|
||||
{
|
||||
std::auto_ptr<func_base> arg(new func<Function>(f));
|
||||
|
||||
::HANDLE entry_event = 0;
|
||||
if (p == internal)
|
||||
arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
|
||||
if (!entry_event)
|
||||
{
|
||||
arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
|
||||
if (!entry_event)
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
boost::system::system_error e(
|
||||
boost::system::error_code(last_error,
|
||||
boost::asio::error::get_system_category()),
|
||||
"thread.entry_event");
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
|
||||
arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
|
||||
if (!exit_event_)
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
::CloseHandle(entry_event);
|
||||
boost::system::system_error e(
|
||||
boost::system::error_code(last_error,
|
||||
boost::asio::error::get_system_category()),
|
||||
"thread.exit_event");
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
DWORD last_error = ::GetLastError();
|
||||
boost::system::system_error e(
|
||||
boost::system::error_code(last_error,
|
||||
boost::asio::error::get_system_category()),
|
||||
"thread.entry_event");
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
else
|
||||
|
||||
arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
|
||||
if (!exit_event_)
|
||||
{
|
||||
arg->entry_event_ = 0;
|
||||
arg->exit_event_ = 0;
|
||||
DWORD last_error = ::GetLastError();
|
||||
::CloseHandle(entry_event);
|
||||
boost::system::system_error e(
|
||||
boost::system::error_code(last_error,
|
||||
boost::asio::error::get_system_category()),
|
||||
"thread.exit_event");
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
|
||||
unsigned int thread_id = 0;
|
||||
@@ -123,14 +140,15 @@ public:
|
||||
// Wait for the thread to exit.
|
||||
void join()
|
||||
{
|
||||
if (exit_event_)
|
||||
::WaitForSingleObject(exit_event_, INFINITE);
|
||||
::CloseHandle(exit_event_);
|
||||
if (terminate_threads())
|
||||
{
|
||||
::WaitForSingleObject(exit_event_, INFINITE);
|
||||
::CloseHandle(exit_event_);
|
||||
::TerminateThread(thread_, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
::QueueUserAPC(apc_function, thread_, 0);
|
||||
::WaitForSingleObject(thread_, INFINITE);
|
||||
}
|
||||
}
|
||||
@@ -138,6 +156,12 @@ public:
|
||||
private:
|
||||
friend unsigned int __stdcall win_thread_function(void* arg);
|
||||
|
||||
#if (WINVER < 0x0500)
|
||||
friend void __stdcall apc_function(ULONG);
|
||||
#else
|
||||
friend void __stdcall apc_function(ULONG_PTR);
|
||||
#endif
|
||||
|
||||
class func_base
|
||||
{
|
||||
public:
|
||||
@@ -175,21 +199,30 @@ inline unsigned int __stdcall win_thread_function(void* arg)
|
||||
std::auto_ptr<win_thread::func_base> func(
|
||||
static_cast<win_thread::func_base*>(arg));
|
||||
|
||||
if (func->entry_event_)
|
||||
::SetEvent(func->entry_event_);
|
||||
::SetEvent(func->entry_event_);
|
||||
|
||||
func->run();
|
||||
|
||||
if (HANDLE exit_event = func->exit_event_)
|
||||
{
|
||||
func.reset();
|
||||
::SetEvent(exit_event);
|
||||
::Sleep(INFINITE);
|
||||
}
|
||||
// Signal that the thread has finished its work, but rather than returning go
|
||||
// to sleep to put the thread into a well known state. If the thread is being
|
||||
// joined during global object destruction then it may be killed using
|
||||
// TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
|
||||
// call will be interrupted using QueueUserAPC and the thread will shut down
|
||||
// cleanly.
|
||||
HANDLE exit_event = func->exit_event_;
|
||||
func.reset();
|
||||
::SetEvent(exit_event);
|
||||
::SleepEx(INFINITE, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (WINVER < 0x0500)
|
||||
inline void __stdcall apc_function(ULONG) {}
|
||||
#else
|
||||
inline void __stdcall apc_function(ULONG_PTR) {}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
@@ -43,12 +43,9 @@ class wince_thread
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
// The purpose of the thread.
|
||||
enum purpose { internal, external };
|
||||
|
||||
// Constructor.
|
||||
template <typename Function>
|
||||
wince_thread(Function f, purpose = internal)
|
||||
wince_thread(Function f)
|
||||
{
|
||||
std::auto_ptr<func_base> arg(new func<Function>(f));
|
||||
DWORD thread_id = 0;
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
@@ -56,6 +58,15 @@ public:
|
||||
/// Construct an address from raw bytes.
|
||||
explicit address_v4(const bytes_type& bytes)
|
||||
{
|
||||
#if UCHAR_MAX > 0xFF
|
||||
if (bytes[0] > 0xFF || bytes[1] > 0xFF
|
||||
|| bytes[2] > 0xFF || bytes[3] > 0xFF)
|
||||
{
|
||||
std::out_of_range ex("address_v4 from bytes_type");
|
||||
boost::throw_exception(ex);
|
||||
}
|
||||
#endif // UCHAR_MAX > 0xFF
|
||||
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(&addr_.s_addr, bytes.elems, 4);
|
||||
}
|
||||
@@ -63,6 +74,14 @@ public:
|
||||
/// Construct an address from a unsigned long in host byte order.
|
||||
explicit address_v4(unsigned long addr)
|
||||
{
|
||||
#if ULONG_MAX > 0xFFFFFFFF
|
||||
if (addr > 0xFFFFFFFF)
|
||||
{
|
||||
std::out_of_range ex("address_v4 from unsigned long");
|
||||
boost::throw_exception(ex);
|
||||
}
|
||||
#endif // ULONG_MAX > 0xFFFFFFFF
|
||||
|
||||
addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,17 @@ public:
|
||||
explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
|
||||
: scope_id_(scope_id)
|
||||
{
|
||||
#if UCHAR_MAX > 0xFF
|
||||
for (std::size_t i = 0; i < bytes.size(); ++i)
|
||||
{
|
||||
if (bytes[i] > 0xFF)
|
||||
{
|
||||
std::out_of_range ex("address_v6 from bytes_type");
|
||||
boost::throw_exception(ex);
|
||||
}
|
||||
}
|
||||
#endif // UCHAR_MAX > 0xFF
|
||||
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(addr_.s6_addr, bytes.elems, 16);
|
||||
}
|
||||
@@ -166,7 +177,11 @@ public:
|
||||
address_v4 to_v4() const
|
||||
{
|
||||
if (!is_v4_mapped() && !is_v4_compatible())
|
||||
throw std::bad_cast();
|
||||
{
|
||||
std::bad_cast ex;
|
||||
boost::throw_exception(ex);
|
||||
}
|
||||
|
||||
address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
|
||||
addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
|
||||
return address_v4(v4_bytes);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <string>
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
@@ -35,6 +36,20 @@ namespace asio {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
|
||||
template <typename T>
|
||||
struct has_result_type
|
||||
{
|
||||
template <typename U> struct inner
|
||||
{
|
||||
struct big { char a[100]; };
|
||||
static big helper(U, ...);
|
||||
static char helper(U, typename U::result_type* = 0);
|
||||
};
|
||||
static const T& ref();
|
||||
enum { value = (sizeof((inner<const T&>::helper)((ref)())) == 1) };
|
||||
};
|
||||
#else // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
|
||||
template <typename T>
|
||||
struct has_result_type
|
||||
{
|
||||
@@ -44,6 +59,7 @@ namespace detail
|
||||
static const T& ref();
|
||||
enum { value = (sizeof((helper)((ref)())) == 1) };
|
||||
};
|
||||
#endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
|
||||
} // namespace detail
|
||||
|
||||
/// Type trait used to determine whether a type can be used as a match condition
|
||||
|
||||
Reference in New Issue
Block a user