2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

Merge branch 'master' into trac684

This commit is contained in:
chenzhengzhang
2011-05-17 11:45:12 +08:00
541 changed files with 35521 additions and 15384 deletions

134
ChangeLog
View File

@@ -1,4 +1,126 @@
222. [bug] jerry
238. [func] zhang likun
Implement the simplest forwarder, which pass everything throught
except QID, port number. The response will not be cached.
(Trac #598_new, git 8e28187a582820857ef2dae9b13637a3881f13ba)
237. [bug] naokikambe
Resolved that the stats module wasn't configurable in bindctl in
spite of its having configuration items. The configuration part
was removed from the original spec file "stats.spec" and was
placed in a new spec file "stats-schema.spec". Because it means
definitions of statistics items. The command part is still
there. Thus stats module currently has no its own configuration,
and the items in "stats-schema.spec" are neither visible nor
configurable through bindctl. "stats-schema.spec" is shared with
stats module and stats-httpd module, and maybe with other
statistical modules in future. "stats.spec" has own configuration
and commands of stats module, if it requires.
(Trac#719, git a234b20dc6617392deb8a1e00eb0eed0ff353c0a)
236. [func] jelte
C++ client side of configuration now uses BIND10 logging system.
It also has improved error handling when communicating with the
rest of the system.
(Trac #743, git 86632c12308c3ed099d75eb828f740c526dd7ec0)
235. [func] jinmei
libdns++: added support for TSIG signing and verification. It can
be done using a newly introduced TSIGContext class.
Note: we temporarily disabled support for truncated signature
and modified some part of the code introduced in #226 accordingly.
We plan to fix this pretty soon.
(Trac #812, git ebe0c4b1e66d359227bdd1bd47395fee7b957f14)
(Trac #871, git 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8)
(Trac #813, git ffa2f0672084c1f16e5784cdcdd55822f119feaa)
(Trac #893, git 5aaa6c0f628ed7c2093ecdbac93a2c8cf6c94349)
234. [func] jerry
src/bin/xfrin: update xfrin to use TSIG. Currently it only supports
sending a signed TSIG request or SOA request.
(Trac #815, git a892818fb13a1839c82104523cb6cb359c970e88)
233. [func] stephen
Added new-style logging statements to the NSAS code.
(Trac #745, git ceef68cd1223ae14d8412adbe18af2812ade8c2d)
232. [func] stephen
To facilitate the writing of extended descriptions in
message files, altered the message file format. The message
is now flagged with a "%" as the first non-blank character
in the line and the lines in the extended description are
no longer preceded by a "+".
(Trac #900, git b395258c708b49a5da8d0cffcb48d83294354ba3)
231. [func]* vorner
The logging interface changed slightly. We use
logger.foo(MESSAGE_ID).arg(bar); instead of logger.foo(MESSAGE_ID,
bar); internally. The message definitions use '%1,%2,...'
instead of '%s,%d', which allows us to cope better with
mismatched placeholders and allows reordering of them in
case of translation.
(Trac901, git 4903410e45670b30d7283f5d69dc28c2069237d6)
230. [bug] naokikambe
Removed too repeated verbose messages in two cases of:
- when auth sends statistics data to stats
- when stats receives statistics data from other modules
(Trac#620, git 0ecb807011196eac01f281d40bc7c9d44565b364)
229. [doc] jreed
Add manual page for b10-host.
(git a437d4e26b81bb07181ff35a625c540703eee845)
228. [func]* jreed
The host tool is renamed to b10-host. While the utility is
a work in progress, it is expected to now be shipped with
tarballs. Its initial goal was to be a host(1) clone,
rewritten in C++ from scratch and using BIND 10's libdns++.
It now supports the -a (any), -c class, -d (verbose) switches
and has improved output.
(Trac #872, git d846851699d5c76937533adf9ff9d948dfd593ca)
227. [build] jreed
Add missing libdns++ rdata files for the distribution (this
fixes distcheck error). Change three generated libdns++
headers to "nodist" so they aren't included in the distribution
(they were mistakenly included in last tarball).
226. [func]* jelte
Introduced an API for cryptographic operations. Currently it only
supports HMAC, intended for use with TSIG. The current
implementation uses Botan as the backend library.
This introduces a new dependency, on Botan. Currently only Botan
1.8.x works; older or newer versions don't.
(Trac #781, git 9df42279a47eb617f586144dce8cce680598558a)
225. [func] naokikambe
Added the HTTP/XML interface(b10-stats-httpd) to the
statistics feature in BIND 10. b10-stats-httpd is a standalone
HTTP server and it requests statistics data to the stats
daemon(b10-stats) and sends it to HTTP clients in XML
format. Items of the data collected via b10-stats-httpd
are almost equivalent to ones which are collected via
bindctl. Since it also can send XSL(Extensible Stylessheet
Language) document and XSD(XML Schema definition) document,
XML document is human-friendly to view through web browsers
and its data types are strictly defined.
(Trac #547, git 1cbd51919237a6e65983be46e4f5a63d1877b1d3)
224. [bug] jinmei
b10-auth, src/lib/datasrc: inconsistency between the hot spot
cache and actual data source could cause a crash while query
processing. The crash could happen, e.g., when an sqlite3 DB file
is being updated after a zone transfer while b10-auth handles a
query using the corresponding sqlite3 data source.
(Trac #851, git 2463b96680bb3e9a76e50c38a4d7f1d38d810643)
223. [bug] feng
If ip address or port isn't usable for name server, name
server process won't exist and give end user chance to
reconfigure them.
(Trac #775, git 572ac2cf62e18f7eb69d670b890e2a3443bfd6e7)
222. [bug] jerry
src/lib/zonemgr: Fix a bug that xfrin not checking for new copy of
zone on startup. Imposes some random jitters to avoid many zones
need to do refresh at the same time.
@@ -13,7 +135,7 @@
(potentially) bad packets to a nameserver and prints the responses.
(Trac #703, git 1b666838b6c0fe265522b30971e878d9f0d21fde)
219. [func] ocean
219. [func] ocean
src/lib: move some dns related code out of asiolink library to
asiodns library
(Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c)
@@ -23,9 +145,9 @@
(Trac #806, git 4e47d5f6b692c63c907af6681a75024450884a88)
217. [bug] jerry
src/lib/dns/python: Use a signed version of larger size of integer and
perform more strict range checks with PyArg_ParseTuple() in case of
overflows.
src/lib/dns/python: Use a signed version of larger size of
integer and perform more strict range checks with
PyArg_ParseTuple() in case of overflows.
(Trac #363, git ce281e646be9f0f273229d94ccd75bf7e08d17cf)
216. [func] vorner
@@ -1047,7 +1169,7 @@ bind10-devel-20100701 released on July 1, 2010
55. [bug] shane
bin/xfrout: xfrout exception on Ctrl-C now no longer generates
exception for 'Interrupted system call'
(Track #136, svn r2147)
(Trac #136, svn r2147)
54. [bug] zhanglikun
bin/xfrout: Enable b10-xfrout can be launched in source

View File

@@ -84,214 +84,310 @@ systest:
#### include external sources in the distributed tarball:
EXTRA_DIST = ext/asio/README
EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
EXTRA_DIST += ext/asio/asio/impl/write.ipp
EXTRA_DIST += ext/asio/asio/impl/read.ipp
EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
EXTRA_DIST += ext/asio/asio/detail/event.hpp
EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
EXTRA_DIST += ext/asio/README
EXTRA_DIST += ext/asio/asio.hpp
EXTRA_DIST += ext/asio/asio/basic_socket.hpp
EXTRA_DIST += ext/asio/asio/streambuf.hpp
EXTRA_DIST += ext/asio/asio/thread.hpp
EXTRA_DIST += ext/asio/asio/detail/wait_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/resolve_op.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_hppa_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/null_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service_operation.hpp
EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/local_free_on_block_exit.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
EXTRA_DIST += ext/asio/asio/detail/operation.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_holder.hpp
EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/select_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_op_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/buffer_sequence_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
EXTRA_DIST += ext/asio/asio/detail/thread.hpp
EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
EXTRA_DIST += ext/asio/asio/detail/null_event.hpp
EXTRA_DIST += ext/asio/asio/detail/service_id.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
EXTRA_DIST += ext/asio/asio/detail/throw_error.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
EXTRA_DIST += ext/asio/asio/detail/wrapped_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/win_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_base.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service_operation.hpp
EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_write_op.hpp
EXTRA_DIST += ext/asio/asio/detail/thread.hpp
EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/event.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_op.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recv_op.hpp
EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/local_free_on_block_exit.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
EXTRA_DIST += ext/asio/asio/detail/signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/resolver_service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_holder.hpp
EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/select_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_arm_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_op_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
EXTRA_DIST += ext/asio/asio/detail/buffer_sequence_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_send_op.hpp
EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/operation.hpp
EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/shared_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/null_event.hpp
EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_sync_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_null_buffers_op.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
EXTRA_DIST += ext/asio/asio/detail/weak_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_accept_op.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_recvfrom_op.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
EXTRA_DIST += ext/asio/asio/detail/service_id.hpp
EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/regex_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_sendto_op.hpp
EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/throw_error.hpp
EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_accept_op.hpp
EXTRA_DIST += ext/asio/asio/detail/wrapped_handler.hpp
EXTRA_DIST += ext/asio/asio/detail/object_pool.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/resolve_endpoint_op.hpp
EXTRA_DIST += ext/asio/asio/detail/array_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/config.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/win_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_send_op.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_null_buffers_op.hpp
EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service_base.hpp
EXTRA_DIST += ext/asio/asio/detail/descriptor_read_op.hpp
EXTRA_DIST += ext/asio/asio/detail/reactive_socket_connect_op.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue_base.hpp
EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_recv_op.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
EXTRA_DIST += ext/asio/asio/detail/descriptor_write_op.hpp
EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/reactive_socket_service_base.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_mutex.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/posix_event.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/posix_tss_ptr.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/select_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/eventfd_select_interrupter.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/winsock_init.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/pipe_select_interrupter.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_serial_port_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/dev_poll_reactor.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/strand_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_socket_service_base.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/posix_mutex.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/reactive_serial_port_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/socket_ops.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/socket_select_interrupter.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/posix_thread.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/reactive_descriptor_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/kqueue_reactor.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_event.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/timer_queue_set.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_tss_ptr.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_iocp_handle_service.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/resolver_service_base.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/win_thread.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/task_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/throw_error.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/epoll_reactor.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.hpp
EXTRA_DIST += ext/asio/asio/detail/impl/descriptor_ops.ipp
EXTRA_DIST += ext/asio/asio/detail/impl/service_registry.ipp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
EXTRA_DIST += ext/asio/asio/detail/timer_queue.hpp
EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_read_op.hpp
EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
EXTRA_DIST += ext/asio/asio/ssl/context_base.hpp
EXTRA_DIST += ext/asio/asio/ssl/context.hpp
EXTRA_DIST += ext/asio/asio/ssl/context_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
EXTRA_DIST += ext/asio/asio/ssl/basic_context.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
EXTRA_DIST += ext/asio/asio/ssl/stream_base.hpp
EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
EXTRA_DIST += ext/asio/asio/error.hpp
EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
EXTRA_DIST += ext/asio/asio/placeholders.hpp
EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
EXTRA_DIST += ext/asio/asio/local/detail/impl/endpoint.ipp
EXTRA_DIST += ext/asio/asio/local/detail/endpoint.hpp
EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
EXTRA_DIST += ext/asio/asio/socket_base.hpp
EXTRA_DIST += ext/asio/asio/io_service.hpp
EXTRA_DIST += ext/asio/asio/ssl.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
EXTRA_DIST += ext/asio/asio/error_code.hpp
EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
EXTRA_DIST += ext/asio/asio/read_until.hpp
EXTRA_DIST += ext/asio/asio/basic_streambuf_fwd.hpp
EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
EXTRA_DIST += ext/asio/asio/time_traits.hpp
EXTRA_DIST += ext/asio/asio/completion_condition.hpp
EXTRA_DIST += ext/asio/asio/posix/basic_stream_descriptor.hpp
EXTRA_DIST += ext/asio/asio/posix/basic_descriptor.hpp
EXTRA_DIST += ext/asio/asio/posix/descriptor_base.hpp
EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
EXTRA_DIST += ext/asio/asio/write.hpp
EXTRA_DIST += ext/asio/asio/write_at.hpp
EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
EXTRA_DIST += ext/asio/asio/serial_port.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
EXTRA_DIST += ext/asio/asio/read.hpp
EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
EXTRA_DIST += ext/asio/asio/buffer.hpp
EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
EXTRA_DIST += ext/asio/asio/impl/serial_port_base.hpp
EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
EXTRA_DIST += ext/asio/asio/impl/read.ipp
EXTRA_DIST += ext/asio/asio/impl/error.ipp
EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
EXTRA_DIST += ext/asio/asio/impl/io_service.hpp
EXTRA_DIST += ext/asio/asio/impl/src.hpp
EXTRA_DIST += ext/asio/asio/impl/src.cpp
EXTRA_DIST += ext/asio/asio/impl/read_until.hpp
EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
EXTRA_DIST += ext/asio/asio/impl/write.hpp
EXTRA_DIST += ext/asio/asio/impl/write_at.hpp
EXTRA_DIST += ext/asio/asio/impl/write.ipp
EXTRA_DIST += ext/asio/asio/impl/read.hpp
EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
EXTRA_DIST += ext/asio/asio/impl/read_at.hpp
EXTRA_DIST += ext/asio/asio/strand.hpp
EXTRA_DIST += ext/asio/asio/version.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
EXTRA_DIST += ext/asio/asio/ip/address.hpp
EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
EXTRA_DIST += ext/asio/asio/ip/detail/socket_option.hpp
EXTRA_DIST += ext/asio/asio/ip/detail/impl/endpoint.ipp
EXTRA_DIST += ext/asio/asio/ip/detail/endpoint.hpp
EXTRA_DIST += ext/asio/asio/ip/udp.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
EXTRA_DIST += ext/asio/asio/ip/v6_only.hpp
EXTRA_DIST += ext/asio/asio/ip/address_v4.hpp
EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
EXTRA_DIST += ext/asio/asio/ip/multicast.hpp
EXTRA_DIST += ext/asio/asio/ip/unicast.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/ip/resolver_service.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
EXTRA_DIST += ext/asio/asio/ip/address.hpp
EXTRA_DIST += ext/asio/asio/ip/multicast.hpp
EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
EXTRA_DIST += ext/asio/asio/ip/udp.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
EXTRA_DIST += ext/asio/asio/ip/unicast.hpp
EXTRA_DIST += ext/asio/asio/ip/resolver_service.hpp
EXTRA_DIST += ext/asio/asio/ip/icmp.hpp
EXTRA_DIST += ext/asio/asio/error.hpp
EXTRA_DIST += ext/asio/asio/basic_socket.hpp
EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
EXTRA_DIST += ext/asio/asio/system_error.hpp
EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
EXTRA_DIST += ext/asio/asio/read_at.hpp
EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
EXTRA_DIST += ext/asio/asio/placeholders.hpp
EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
EXTRA_DIST += ext/asio/asio/thread.hpp
EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
EXTRA_DIST += ext/asio/asio/ip/impl/address.hpp
EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.hpp
EXTRA_DIST += ext/asio/asio/ip/impl/address_v4.ipp
EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.hpp
EXTRA_DIST += ext/asio/asio/ip/impl/address.ipp
EXTRA_DIST += ext/asio/asio/ip/impl/host_name.ipp
EXTRA_DIST += ext/asio/asio/ip/impl/basic_endpoint.hpp
EXTRA_DIST += ext/asio/asio/ip/impl/address_v6.ipp
EXTRA_DIST += ext/asio/asio/handler_invoke_hook.hpp
EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
EXTRA_DIST += ext/asio/asio/buffer.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
EXTRA_DIST += ext/asio/asio/write_at.hpp
EXTRA_DIST += ext/asio/asio/completion_condition.hpp
EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
EXTRA_DIST += ext/asio/asio/socket_base.hpp
EXTRA_DIST += ext/asio/asio/serial_port.hpp
EXTRA_DIST += ext/asio/asio/error_code.hpp
EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
EXTRA_DIST += ext/asio/asio/version.hpp
EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
EXTRA_DIST += ext/asio/asio/io_service.hpp
EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
EXTRA_DIST += ext/asio/asio/streambuf.hpp
EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
EXTRA_DIST += ext/asio/asio/write.hpp
EXTRA_DIST += ext/asio/asio/strand.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
EXTRA_DIST += ext/asio/asio/ssl.hpp
EXTRA_DIST += ext/asio/asio/deadline_timer.hpp
EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
EXTRA_DIST += ext/asio/asio/read.hpp
EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
EXTRA_DIST += ext/asio/asio/stream_socket_service.hpp
EXTRA_DIST += ext/asio/asio/time_traits.hpp
EXTRA_DIST += ext/asio/asio/read_until.hpp
EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
EXTRA_DIST += ext/asio/asio/read_at.hpp
EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
EXTRA_DIST += ext/asio/asio.hpp
EXTRA_DIST += ext/asio/asio/system_error.hpp
EXTRA_DIST += ext/asio/asio/deadline_timer.hpp
EXTRA_DIST += ext/asio/asio/stream_socket_service.hpp
EXTRA_DIST += ext/coroutine/coroutine.h

View File

@@ -374,6 +374,79 @@ if test "$lcov" != "no"; then
fi
AC_SUBST(USE_LCOV)
# Check for Botan
botan_path="yes"
AC_ARG_WITH([botan],
AC_HELP_STRING([--with-botan=PATH],
[specify exact directory of Botan library]),
[botan_path="$withval"])
if test "${botan_path}" == "no" ; then
AC_MSG_ERROR([Need botan for libcryptolink])
fi
if test "${botan_path}" != "yes" ; then
if test -x "${botan_path}/bin/botan-config" ; then
BOTAN_CONFIG="${botan_path}/bin/botan-config"
else
AC_MSG_ERROR([${botan_path}/bin/botan-config not found])
fi
else
AC_PATH_PROG([BOTAN_CONFIG], [botan-config])
fi
if test -x "${BOTAN_CONFIG}" ; then
BOTAN_LDFLAGS=`${BOTAN_CONFIG} --libs`
# We expect botan-config --libs to contain -L<path_to_libbotan>, but
# this is not always the case. As a heuristics workaround we add
# -L`botan-config --prefix/lib` in this case. Same for BOTAN_INCLUDES
# (but using include instead of lib) below.
echo ${BOTAN_LDFLAGS} | grep -- -L > /dev/null || \
BOTAN_LDFLAGS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LDFLAGS}"
BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
# See python_rpath for some info on why we do this
if test $rpath_available = yes; then
BOTAN_RPATH=
for flag in ${BOTAN_LDFLAGS}; do
BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne 's/^\(\-L\)/-R/p'`"
done
AC_SUBST(BOTAN_RPATH)
# According to the libtool manual, it should be sufficient if we
# specify the "-R libdir" in our wrapper library of botan (no other
# programs will need libbotan directly); "libdir" should be added to
# the program's binary image. But we've seen in our build environments
# that (some versions of?) libtool doesn't propagate -R as documented,
# and it caused a linker error at run time. To work around this, we
# also add the rpath to the global LDFLAGS.
LDFLAGS="$BOTAN_RPATH $LDFLAGS"
fi
AC_SUBST(BOTAN_LDFLAGS)
AC_SUBST(BOTAN_INCLUDES)
fi
CPPFLAGS_SAVED=$CPPFLAGS
CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS"
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$BOTAN_LDFLAGS $LDFLAGS"
AC_CHECK_HEADERS([botan/botan.h],,AC_MSG_ERROR([Missing required header files.]))
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <botan/botan.h>
#include <botan/hash.h>
],
[using namespace Botan;
LibraryInitializer::initialize();
HashFunction *h = get_hash("MD5");
])],
[AC_MSG_RESULT([checking for Botan library... yes])],
[AC_MSG_RESULT([checking for Botan library... no])
AC_MSG_ERROR([Needs Botan library 1.8 or higher])]
)
CPPFLAGS=$CPPFLAGS_SAVED
LDFLAGS=$LDFLAGS_SAVED
#
# Configure Boost header path
#
@@ -613,6 +686,7 @@ AC_CONFIG_FILES([Makefile
src/bin/bindctl/tests/Makefile
src/bin/cfgmgr/Makefile
src/bin/cfgmgr/plugins/Makefile
src/bin/cfgmgr/plugins/tests/Makefile
src/bin/cfgmgr/tests/Makefile
src/bin/host/Makefile
src/bin/loadzone/Makefile
@@ -640,6 +714,7 @@ AC_CONFIG_FILES([Makefile
src/bin/stats/tests/isc/config/Makefile
src/bin/stats/tests/isc/util/Makefile
src/bin/stats/tests/testdata/Makefile
src/bin/stats/tests/http/Makefile
src/bin/usermgr/Makefile
src/bin/tests/Makefile
src/lib/Makefile
@@ -672,11 +747,8 @@ AC_CONFIG_FILES([Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/io/tests/Makefile
src/lib/util/unittests/Makefile
src/lib/util/tests/Makefile
src/lib/cryptolink/Makefile
src/lib/cryptolink/tests/Makefile
src/lib/dns/Makefile
src/lib/dns/tests/Makefile
src/lib/dns/tests/testdata/Makefile
@@ -701,6 +773,11 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/io/tests/Makefile
src/lib/util/unittests/Makefile
src/lib/util/tests/Makefile
tests/Makefile
tests/system/Makefile
tests/tools/Makefile
@@ -729,11 +806,13 @@ AC_OUTPUT([doc/version.ent
src/bin/zonemgr/tests/zonemgr_test
src/bin/zonemgr/run_b10-zonemgr.sh
src/bin/stats/stats.py
src/bin/stats/stats_stub.py
src/bin/stats/stats.spec.pre
src/bin/stats/run_b10-stats.sh
src/bin/stats/run_b10-stats_stub.sh
src/bin/stats/tests/stats_test
src/bin/stats/stats_httpd.py
src/bin/stats/stats.spec
src/bin/stats/stats-schema.spec
src/bin/stats/stats-httpd.spec
src/bin/stats/stats-httpd-xml.tpl
src/bin/stats/stats-httpd-xsd.tpl
src/bin/stats/stats-httpd-xsl.tpl
src/bin/bind10/bind10.py
src/bin/bind10/run_bind10.sh
src/bin/bind10/tests/bind10_test.py
@@ -763,6 +842,7 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/run_time_init_test.sh
src/lib/util/python/mkpywrapper.py
tests/system/conf.sh
tests/system/glue/setup.sh
tests/system/glue/nsx1/b10-config.db
@@ -772,9 +852,6 @@ AC_OUTPUT([doc/version.ent
chmod +x src/bin/xfrin/run_b10-xfrin.sh
chmod +x src/bin/xfrout/run_b10-xfrout.sh
chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
chmod +x src/bin/stats/tests/stats_test
chmod +x src/bin/stats/run_b10-stats.sh
chmod +x src/bin/stats/run_b10-stats_stub.sh
chmod +x src/bin/bind10/run_bind10.sh
chmod +x src/bin/cmdctl/tests/cmdctl_test
chmod +x src/bin/xfrin/tests/xfrin_test
@@ -791,6 +868,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
chmod +x src/lib/log/tests/run_time_init_test.sh
chmod +x src/lib/util/python/mkpywrapper.py
chmod +x tests/system/conf.sh
])
AC_OUTPUT
@@ -813,12 +891,15 @@ Flags:
DEFS: $DEFS
CPPFLAGS: $CPPFLAGS
CXXFLAGS: $CXXFLAGS
LDFLAGS: $LDFLAGS
B10_CXXFLAGS: $B10_CXXFLAGS
dnl includes too
Python: ${PYTHON_INCLUDES}
${PYTHON_LDFLAGS}
${PYTHON_LIB}
Boost: ${BOOST_INCLUDES}
Botan: ${BOTAN_INCLUDES}
${BOTAN_LDFLAGS}
SQLite: $SQLITE_CFLAGS
$SQLITE_LIBS

View File

@@ -568,11 +568,13 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns \
../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth \
../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ \
../src/lib/nsas ../src/lib/testutils ../src/lib/cache \
../src/lib/server_common/ ../src/bin/sockcreator/ ../src/lib/util/
INPUT = ../src/lib/cc ../src/lib/config \
../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
../src/bin/auth ../src/bin/resolver ../src/lib/bench \
../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
../src/bin/sockcreator/ ../src/lib/util/
../src/lib/resolve
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -1163,7 +1165,7 @@ XML_DTD =
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
XML_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output

View File

@@ -1,5 +1,10 @@
ASIO library header files
Version 1.4.5 (2010-05-12)
Version 1.4.8 (2011-04-19)
Downloaded from http://sourceforge.net/projects/asio/files
Project page: http://think-async.com/Asio
No local modifications.
Local modifications:
Added ASIO_DECL to a number of function definitions
git commit c32718be9f5409b6f72d98ddcd0b1ccd4c5c2293
See also the bug report at:
http://sourceforge.net/tracker/?func=detail&aid=3291113&group_id=122478&atid=694037

View File

@@ -2,7 +2,7 @@
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)

View File

@@ -2,7 +2,7 @@
// basic_datagram_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_raw_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/raw_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/raw_socket_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,22 +16,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <string>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/basic_io_object.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides serial port functionality.
@@ -614,9 +612,9 @@ public:
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SERIAL_PORT_HPP

View File

@@ -2,7 +2,7 @@
// basic_socket.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,16 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_socket_acceptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,14 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,22 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
#include "asio/detail/push_options.hpp"
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/stream_socket_service.hpp"
@@ -79,6 +72,8 @@
} \
/**/
#include "asio/detail/push_options.hpp"
namespace asio {
/// Iostream interface for a socket.
@@ -146,11 +141,11 @@ public:
} // namespace asio
#include "asio/detail/pop_options.hpp"
#undef ASIO_PRIVATE_CTR_DEF
#undef ASIO_PRIVATE_CONNECT_DEF
#endif // defined(BOOST_NO_IOSTREAM)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@@ -2,7 +2,7 @@
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,15 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
#include "asio/detail/push_options.hpp"
#include <streambuf>
#include <boost/array.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
@@ -31,12 +26,10 @@
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/io_service.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
#if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
#define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
@@ -74,6 +67,8 @@
} \
/**/
#include "asio/detail/push_options.hpp"
namespace asio {
/// Iostream streambuf for a socket.
@@ -286,10 +281,10 @@ private:
} // namespace asio
#include "asio/detail/pop_options.hpp"
#undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(BOOST_NO_IOSTREAM)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@@ -2,7 +2,7 @@
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,17 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,28 +15,23 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include <boost/limits.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_streambuf_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
@@ -107,7 +102,11 @@ namespace asio {
* is >> s;
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char> >
#else
template <typename Allocator>
#endif
class basic_streambuf
: public std::streambuf,
private noncopyable
@@ -337,8 +336,27 @@ protected:
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
// Helper function to get the preferred size for reading data.
friend std::size_t read_size_helper(
basic_streambuf& sb, std::size_t max_size)
{
return std::min<std::size_t>(
std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
}
};
// Helper function to get the preferred size for reading data. Used for any
// user-provided specialisations of basic_streambuf.
template <typename Allocator>
inline std::size_t read_size_helper(
basic_streambuf<Allocator>& sb, std::size_t max_size)
{
return std::min<std::size_t>(512,
std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
}
} // namespace asio
#include "asio/detail/pop_options.hpp"

View File

@@ -0,0 +1,33 @@
//
// basic_streambuf_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_BASIC_STREAMBUF_FWD_HPP
#define ASIO_BASIC_STREAMBUF_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(BOOST_NO_IOSTREAM)
#include <memory>
namespace asio {
template <typename Allocator = std::allocator<char> >
class basic_streambuf;
} // namespace asio
#endif // !defined(BOOST_NO_IOSTREAM)
#endif // ASIO_BASIC_STREAMBUF_FWD_HPP

View File

@@ -2,7 +2,7 @@
// buffer.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,16 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/array.hpp>
#include <boost/type_traits/is_const.hpp>
#include <string>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include <boost/detail/workaround.hpp>
#include "asio/detail/array_fwd.hpp"
#if defined(BOOST_MSVC)
# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
@@ -43,11 +39,17 @@
#endif // defined(__GNUC__)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp"
# include <boost/function.hpp>
# include "asio/detail/pop_options.hpp"
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
|| BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
# include <boost/type_traits/is_const.hpp>
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
#include "asio/detail/push_options.hpp"
namespace asio {
class mutable_buffer;

View File

@@ -2,7 +2,7 @@
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,23 +15,20 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_resize_guard.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_read_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP

View File

@@ -2,7 +2,7 @@
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,19 +15,16 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_FWD_HPP

View File

@@ -2,7 +2,7 @@
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,24 +15,21 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/write.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/write.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,8 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
@@ -24,6 +22,4 @@ class buffered_write_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP

View File

@@ -2,7 +2,7 @@
// buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,20 +15,17 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/iterator.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/add_const.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
@@ -210,6 +207,15 @@ public:
return tmp;
}
/// Addition operator.
friend buffers_iterator operator+(std::ptrdiff_t difference,
const buffers_iterator& iter)
{
buffers_iterator tmp(iter);
tmp.advance(difference);
return tmp;
}
/// Subtraction operator.
friend buffers_iterator operator-(const buffers_iterator& iter,
std::ptrdiff_t difference)

View File

@@ -2,7 +2,7 @@
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {

View File

@@ -2,7 +2,7 @@
// datagram_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,16 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/service_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
@@ -32,6 +26,8 @@
# include "asio/detail/reactive_socket_service.hpp"
#endif
#include "asio/detail/push_options.hpp"
namespace asio {
/// Default service implementation for a datagram socket.

View File

@@ -2,7 +2,7 @@
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,16 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/basic_deadline_timer.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_deadline_timer.hpp"
namespace asio {
/// Typedef for the typical usage of timer. Uses a UTC clock.
@@ -32,6 +30,4 @@ typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DEADLINE_TIMER_HPP

View File

@@ -2,7 +2,7 @@
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,17 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/io_service.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {

View File

@@ -0,0 +1,25 @@
//
// detail/array_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_ARRAY_FWD_HPP
#define ASIO_DETAIL_ARRAY_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace boost {
template<class T, std::size_t N>
class array;
} // namespace boost
#endif // ASIO_DETAIL_ARRAY_FWD_HPP

View File

@@ -1,8 +1,8 @@
//
// base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,10 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/completion_condition.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -31,7 +32,8 @@ protected:
{
}
std::size_t check(const asio::error_code& ec,
std::size_t check_for_completion(
const asio::error_code& ec,
std::size_t total_transferred)
{
return detail::adapt_completion_condition_result(
@@ -50,7 +52,8 @@ protected:
{
}
static std::size_t check(const asio::error_code& ec,
static std::size_t check_for_completion(
const asio::error_code& ec,
std::size_t total_transferred)
{
return transfer_all_t()(ec, total_transferred);

View File

@@ -1,8 +1,8 @@
//
// bind_handler.hpp
// ~~~~~~~~~~~~~~~~
// detail/bind_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -35,7 +36,7 @@ public:
void operator()()
{
handler_(arg1_);
handler_(static_cast<const Arg1&>(arg1_));
}
void operator()() const
@@ -92,7 +93,8 @@ public:
void operator()()
{
handler_(arg1_, arg2_);
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_));
}
void operator()() const
@@ -152,7 +154,9 @@ public:
void operator()()
{
handler_(arg1_, arg2_, arg3_);
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_));
}
void operator()() const
@@ -216,7 +220,10 @@ public:
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_);
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_));
}
void operator()() const
@@ -287,7 +294,11 @@ public:
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_),
static_cast<const Arg5&>(arg5_));
}
void operator()() const

View File

@@ -1,8 +1,8 @@
//
// buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
// detail/buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,12 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <boost/limits.hpp>
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {

View File

@@ -1,8 +1,8 @@
//
// buffer_sequence_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/buffer_sequence_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,9 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -32,14 +34,14 @@ protected:
const asio::mutable_buffer& buffer)
{
buf.buf = asio::buffer_cast<char*>(buffer);
buf.len = asio::buffer_size(buffer);
buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
}
static void init_native_buffer(WSABUF& buf,
const asio::const_buffer& buffer)
{
buf.buf = const_cast<char*>(asio::buffer_cast<const char*>(buffer));
buf.len = asio::buffer_size(buffer);
buf.len = static_cast<ULONG>(asio::buffer_size(buffer));
}
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef iovec native_buffer_type;
@@ -158,7 +160,7 @@ public:
explicit buffer_sequence_adapter(
const asio::mutable_buffers_1& buffers)
{
init_native_buffer(buffer_, buffers);
init_native_buffer(buffer_, Buffer(buffers));
total_buffer_size_ = asio::buffer_size(buffers);
}
@@ -205,7 +207,7 @@ public:
explicit buffer_sequence_adapter(
const asio::const_buffers_1& buffers)
{
init_native_buffer(buffer_, buffers);
init_native_buffer(buffer_, Buffer(buffers));
total_buffer_size_ = asio::buffer_size(buffers);
}

View File

@@ -1,8 +1,8 @@
//
// buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/config.hpp"
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {

View File

@@ -1,8 +1,8 @@
//
// call_stack.hpp
// ~~~~~~~~~~~~~~
// detail/call_stack.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,11 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/tss_ptr.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {

View File

@@ -1,8 +1,8 @@
//
// completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
// detail/completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,13 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/operation.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -29,6 +30,8 @@ template <typename Handler>
class completion_handler : public operation
{
public:
ASIO_DEFINE_HANDLER_PTR(completion_handler);
completion_handler(Handler h)
: operation(&completion_handler::do_complete),
handler_(h)
@@ -40,20 +43,21 @@ public:
{
// Take ownership of the handler object.
completion_handler* h(static_cast<completion_handler*>(base));
typedef handler_alloc_traits<Handler, completion_handler> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
ptr p = { boost::addressof(h->handler_), h, h };
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
Handler handler(h->handler_);
p.h = boost::addressof(handler);
p.reset();
// Make the upcall if required.
if (owner)
{
// Make a copy of the handler so that the memory can be deallocated
// before the upcall is made. Even if we're not about to make an
// upcall, a sub-object of the handler may be the true owner of the
// memory associated with the handler. Consequently, a local copy of
// the handler is required to ensure that any owning sub-object remains
// valid until after we have deallocated the memory here.
Handler handler(h->handler_);
ptr.reset();
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
}

View File

@@ -0,0 +1,205 @@
//
// detail/config.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_CONFIG_HPP
#define ASIO_DETAIL_CONFIG_HPP
#include <boost/config.hpp>
// Default to a header-only implementation. The user must specifically request
// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
#if !defined(ASIO_HEADER_ONLY)
# if !defined(ASIO_SEPARATE_COMPILATION)
# if !defined(ASIO_DYN_LINK)
# define ASIO_HEADER_ONLY
# endif // !defined(ASIO_DYN_LINK)
# endif // !defined(ASIO_SEPARATE_COMPILATION)
#endif // !defined(ASIO_HEADER_ONLY)
#if defined(ASIO_HEADER_ONLY)
# define ASIO_DECL inline
#else // defined(ASIO_HEADER_ONLY)
# if defined(BOOST_HAS_DECLSPEC)
// We need to import/export our code only if the user has specifically asked
// for it by defining ASIO_DYN_LINK.
# if defined(ASIO_DYN_LINK)
// Export if this is our own source, otherwise import.
# if defined(ASIO_SOURCE)
# define ASIO_DECL __declspec(dllexport)
# else // defined(ASIO_SOURCE)
# define ASIO_DECL __declspec(dllimport)
# endif // defined(ASIO_SOURCE)
# endif // defined(ASIO_DYN_LINK)
# endif // defined(BOOST_HAS_DECLSPEC)
#endif // defined(ASIO_HEADER_ONLY)
// If ASIO_DECL isn't defined yet define it now.
#if !defined(ASIO_DECL)
# define ASIO_DECL
#endif // !defined(ASIO_DECL)
// Windows: target OS version.
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
# pragma message( \
"Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
"- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
"- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
"Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
# else // defined(_MSC_VER) || defined(__BORLANDC__)
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0501
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER)
# if defined(_WIN32) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(_WIN32) && !defined(WIN32)
# endif // defined(_MSC_VER)
# if defined(__BORLANDC__)
# if defined(__WIN32__) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(__WIN32__) && !defined(WIN32)
# endif // defined(__BORLANDC__)
# if defined(__CYGWIN__)
# if !defined(__USE_W32_SOCKETS)
# error You must add -D__USE_W32_SOCKETS to your compiler options.
# endif // !defined(__USE_W32_SOCKETS)
# endif // defined(__CYGWIN__)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Windows: minimise header inclusion.
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif // !defined(WIN32_LEAN_AND_MEAN)
# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Windows: suppress definition of "min" and "max" macros.
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if !defined(ASIO_NO_NOMINMAX)
# if !defined(NOMINMAX)
# define NOMINMAX 1
# endif // !defined(NOMINMAX)
# endif // !defined(ASIO_NO_NOMINMAX)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Windows: IO Completion Ports.
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
# if !defined(UNDER_CE)
# if !defined(ASIO_DISABLE_IOCP)
# define ASIO_HAS_IOCP 1
# endif // !defined(ASIO_DISABLE_IOCP)
# endif // !defined(UNDER_CE)
# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Linux: epoll, eventfd and timerfd.
#if defined(__linux__)
# include <linux/version.h>
# if !defined(ASIO_DISABLE_EPOLL)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
# define ASIO_HAS_EPOLL 1
# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
# endif // !defined(ASIO_DISABLE_EVENTFD)
# if !defined(ASIO_DISABLE_EVENTFD)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
# define ASIO_HAS_EVENTFD 1
# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
# endif // !defined(ASIO_DISABLE_EVENTFD)
# if defined(ASIO_HAS_EPOLL)
# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
# define ASIO_HAS_TIMERFD 1
# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
# endif // defined(ASIO_HAS_EPOLL)
#endif // defined(__linux__)
// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue.
#if (defined(__MACH__) && defined(__APPLE__)) \
|| defined(__FreeBSD__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
# if !defined(ASIO_DISABLE_KQUEUE)
# define ASIO_HAS_KQUEUE 1
# endif // !defined(ASIO_DISABLE_KQUEUE)
#endif // (defined(__MACH__) && defined(__APPLE__))
// || defined(__FreeBSD__)
// || defined(__NetBSD__)
// || defined(__OpenBSD__)
// Solaris: /dev/poll.
#if defined(__sun)
# if !defined(ASIO_DISABLE_DEV_POLL)
# define ASIO_HAS_DEV_POLL 1
# endif // !defined(ASIO_DISABLE_DEV_POLL)
#endif // defined(__sun)
// Serial ports.
#if defined(ASIO_HAS_IOCP) \
|| !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# if !defined(__SYMBIAN32__)
# if !defined(ASIO_DISABLE_SERIAL_PORT)
# define ASIO_HAS_SERIAL_PORT 1
# endif // !defined(ASIO_DISABLE_SERIAL_PORT)
# endif // !defined(__SYMBIAN32__)
#endif // defined(ASIO_HAS_IOCP)
// || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
// Windows: stream handles.
#if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
# if defined(ASIO_HAS_IOCP)
# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
// Windows: random access handles.
#if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
# if defined(ASIO_HAS_IOCP)
# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
// Windows: OVERLAPPED wrapper.
#if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
# if defined(ASIO_HAS_IOCP)
# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
# endif // defined(ASIO_HAS_IOCP)
#endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
// POSIX: stream-oriented file descriptors.
#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
// UNIX domain sockets.
#if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# define ASIO_HAS_LOCAL_SOCKETS 1
# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
#endif // ASIO_DETAIL_CONFIG_HPP

View File

@@ -1,8 +1,8 @@
//
// consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~
// detail/consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,18 +15,14 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/iterator.hpp>
#include <boost/limits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -156,12 +152,14 @@ public:
consuming_buffers(const Buffers& buffers)
: buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()),
first_(*buffers_.begin()),
begin_remainder_(buffers_.begin()),
max_size_((std::numeric_limits<std::size_t>::max)())
{
if (!at_end_)
{
first_ = *buffers_.begin();
++begin_remainder_;
}
}
// Copy constructor.

View File

@@ -1,8 +1,8 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,14 +15,8 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
@@ -33,6 +27,13 @@
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue.hpp"
#include "asio/detail/timer_scheduler.hpp"
#include "asio/detail/wait_handler.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -54,6 +55,7 @@ public:
{
time_type expiry;
bool might_have_pending_waits;
typename timer_queue<Time_Traits>::per_timer_data timer_data;
};
// Constructor.
@@ -97,7 +99,7 @@ public:
ec = asio::error_code();
return 0;
}
std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
@@ -151,59 +153,21 @@ public:
ec = asio::error_code();
}
template <typename Handler>
class wait_handler : public timer_op
{
public:
wait_handler(Handler handler)
: timer_op(&wait_handler::do_complete),
handler_(handler)
{
}
static void do_complete(io_service_impl* owner, operation* base,
asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
wait_handler* h(static_cast<wait_handler*>(base));
typedef handler_alloc_traits<Handler, wait_handler> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
// Make the upcall if required.
if (owner)
{
// Make a copy of the handler so that the memory can be deallocated
// before the upcall is made. Even if we're not about to make an
// upcall, a sub-object of the handler may be the true owner of the
// memory associated with the handler. Consequently, a local copy of
// the handler is required to ensure that any owning sub-object remains
// valid until after we have deallocated the memory here.
detail::binder1<Handler, asio::error_code>
handler(h->handler_, h->ec_);
ptr.reset();
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
}
}
private:
Handler handler_;
};
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
typedef wait_handler<Handler> op;
typename op::ptr p = { boost::addressof(handler),
asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(handler);
impl.might_have_pending_waits = true;
scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl);
ptr.release();
scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
p.v = p.p = 0;
}
private:

View File

@@ -1,8 +1,8 @@
//
// descriptor_ops.hpp
// ~~~~~~~~~~~~~~~~~~
// detail/descriptor_ops.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,27 +15,34 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <cerrno>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include <cstddef>
#include "asio/error_code.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
namespace descriptor_ops {
inline void clear_error(asio::error_code& ec)
// Descriptor state bits.
enum
{
errno = 0;
ec = asio::error_code();
}
// The user wants a non-blocking descriptor.
user_set_non_blocking = 1,
// The descriptor has been set non-blocking.
internal_non_blocking = 2,
// Helper "state" used to determine whether the descriptor is non-blocking.
non_blocking = user_set_non_blocking | internal_non_blocking
};
typedef unsigned char state_type;
template <typename ReturnType>
inline ReturnType error_wrapper(ReturnType return_value,
@@ -46,131 +53,53 @@ inline ReturnType error_wrapper(ReturnType return_value,
return return_value;
}
inline int open(const char* path, int flags, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::open(path, flags), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL int open(const char* path, int flags,
asio::error_code& ec);
inline int close(int d, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::close(d), ec);
if (result == 0)
clear_error(ec);
return result;
}
ASIO_DECL int close(int d, state_type& state,
asio::error_code& ec);
inline void init_buf_iov_base(void*& base, void* addr)
{
base = addr;
}
template <typename T>
inline void init_buf_iov_base(T& base, void* addr)
{
base = static_cast<T>(addr);
}
ASIO_DECL bool set_internal_non_blocking(int d,
state_type& state, asio::error_code& ec);
typedef iovec buf;
inline void init_buf(buf& b, void* data, size_t size)
{
init_buf_iov_base(b.iov_base, data);
b.iov_len = size;
}
ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
std::size_t count, bool all_empty, asio::error_code& ec);
inline void init_buf(buf& b, const void* data, size_t size)
{
init_buf_iov_base(b.iov_base, const_cast<void*>(data));
b.iov_len = size;
}
ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred);
inline int scatter_read(int d, buf* bufs, size_t count,
asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL std::size_t sync_write(int d, state_type state,
const buf* bufs, std::size_t count, bool all_empty,
asio::error_code& ec);
inline int gather_write(int d, const buf* bufs, size_t count,
asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL bool non_blocking_write(int d,
const buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred);
inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::ioctl(d, cmd, arg), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, asio::error_code& ec);
inline int fcntl(int d, long cmd, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::fcntl(d, cmd), ec);
if (result != -1)
clear_error(ec);
return result;
}
ASIO_DECL int fcntl(int d, long cmd, asio::error_code& ec);
inline int fcntl(int d, long cmd, long arg, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::fcntl(d, cmd, arg), ec);
if (result != -1)
clear_error(ec);
return result;
}
ASIO_DECL int fcntl(int d, long cmd,
long arg, asio::error_code& ec);
inline int poll_read(int d, asio::error_code& ec)
{
clear_error(ec);
pollfd fds;
fds.fd = d;
fds.events = POLLIN;
fds.revents = 0;
clear_error(ec);
int result = error_wrapper(::poll(&fds, 1, -1), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL int poll_read(int d, asio::error_code& ec);
inline int poll_write(int d, asio::error_code& ec)
{
clear_error(ec);
pollfd fds;
fds.fd = d;
fds.events = POLLOUT;
fds.revents = 0;
clear_error(ec);
int result = error_wrapper(::poll(&fds, 1, -1), ec);
if (result >= 0)
clear_error(ec);
return result;
}
ASIO_DECL int poll_write(int d, asio::error_code& ec);
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/detail/impl/descriptor_ops.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP

View File

@@ -0,0 +1,114 @@
//
// detail/descriptor_read_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include <boost/utility/addressof.hpp>
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/descriptor_ops.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename MutableBufferSequence>
class descriptor_read_op_base : public reactor_op
{
public:
descriptor_read_op_base(int descriptor,
const MutableBufferSequence& buffers, func_type complete_func)
: reactor_op(&descriptor_read_op_base::do_perform, complete_func),
descriptor_(descriptor),
buffers_(buffers)
{
}
static bool do_perform(reactor_op* base)
{
descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_);
return descriptor_ops::non_blocking_read(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
}
private:
int descriptor_;
MutableBufferSequence buffers_;
};
template <typename MutableBufferSequence, typename Handler>
class descriptor_read_op
: public descriptor_read_op_base<MutableBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
descriptor_read_op(int descriptor,
const MutableBufferSequence& buffers, Handler handler)
: descriptor_read_op_base<MutableBufferSequence>(
descriptor, buffers, &descriptor_read_op::do_complete),
handler_(handler)
{
}
static void do_complete(io_service_impl* owner, operation* base,
asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { boost::addressof(o->handler_), o, o };
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, asio::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = boost::addressof(handler.handler_);
p.reset();
// Make the upcall if required.
if (owner)
{
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler.handler_);
}
}
private:
Handler handler_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP

View File

@@ -0,0 +1,114 @@
//
// detail/descriptor_write_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include <boost/utility/addressof.hpp>
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/descriptor_ops.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename ConstBufferSequence>
class descriptor_write_op_base : public reactor_op
{
public:
descriptor_write_op_base(int descriptor,
const ConstBufferSequence& buffers, func_type complete_func)
: reactor_op(&descriptor_write_op_base::do_perform, complete_func),
descriptor_(descriptor),
buffers_(buffers)
{
}
static bool do_perform(reactor_op* base)
{
descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_);
return descriptor_ops::non_blocking_write(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
}
private:
int descriptor_;
ConstBufferSequence buffers_;
};
template <typename ConstBufferSequence, typename Handler>
class descriptor_write_op
: public descriptor_write_op_base<ConstBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
descriptor_write_op(int descriptor,
const ConstBufferSequence& buffers, Handler handler)
: descriptor_write_op_base<ConstBufferSequence>(
descriptor, buffers, &descriptor_write_op::do_complete),
handler_(handler)
{
}
static void do_complete(io_service_impl* owner, operation* base,
asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { boost::addressof(o->handler_), o, o };
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, asio::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = boost::addressof(handler.handler_);
p.reset();
// Make the upcall if required.
if (owner)
{
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler.handler_);
}
}
private:
Handler handler_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP

View File

@@ -1,8 +1,8 @@
//
// dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~
// detail/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,36 +15,28 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/dev_poll_reactor_fwd.hpp"
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include <sys/devpoll.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/dev_poll_reactor_fwd.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -62,358 +54,93 @@ public:
};
// Constructor.
dev_poll_reactor(asio::io_service& io_service)
: asio::detail::service_base<dev_poll_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
dev_poll_fd_(do_dev_poll_create()),
interrupter_(),
shutdown_(false)
{
// Add the interrupter's descriptor to /dev/poll.
::pollfd ev = { 0 };
ev.fd = interrupter_.read_descriptor();
ev.events = POLLIN | POLLERR;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
ASIO_DECL dev_poll_reactor(asio::io_service& io_service);
// Destructor.
~dev_poll_reactor()
{
shutdown_service();
::close(dev_poll_fd_);
}
ASIO_DECL ~dev_poll_reactor();
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
op_queue_[i].get_all_operations(ops);
timer_queues_.get_all_timers(ops);
}
ASIO_DECL void shutdown_service();
// Initialise the task.
void init_task()
{
io_service_.init_task();
}
ASIO_DECL void 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&)
ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op)
{
return 0;
io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
per_descriptor_data&, reactor_op* op, bool allow_speculative)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (allow_speculative)
{
if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
{
if (!op_queue_[op_type].has_operation(descriptor))
{
if (op->perform())
{
lock.unlock();
io_service_.post_immediate_completion(op);
return;
}
}
}
}
bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
io_service_.work_started();
if (first)
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLERR | POLLHUP;
if (op_type == read_op
|| op_queue_[read_op].has_operation(descriptor))
ev.events |= POLLIN;
if (op_type == write_op
|| op_queue_[write_op].has_operation(descriptor))
ev.events |= POLLOUT;
if (op_type == except_op
|| op_queue_[except_op].has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data&, reactor_op* op, bool allow_speculative);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from /dev/poll.
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLREMOVE;
interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
ASIO_DECL void close_descriptor(
socket_type descriptor, per_descriptor_data&);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&timer_queue);
}
void add_timer_queue(timer_queue<Time_Traits>& queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&timer_queue);
}
void remove_timer_queue(timer_queue<Time_Traits>& queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
{
bool earliest = timer_queue.enqueue_timer(time, op, token);
io_service_.work_started();
if (earliest)
interrupter_.interrupt();
}
}
void schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = timer_queue.cancel_timer(token, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run /dev/poll once until interrupted or events are ready to be dispatched.
void run(bool block, op_queue<operation>& ops)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
&& op_queue_[except_op].empty() && timer_queues_.all_empty())
return;
// Write the pending event registration changes to the /dev/poll descriptor.
std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
if (events_size > 0)
{
errno = 0;
int result = ::write(dev_poll_fd_,
&pending_event_changes_[0], events_size);
if (result != static_cast<int>(events_size))
{
asio::error_code ec = asio::error_code(
errno, asio::error::get_system_category());
for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
{
int descriptor = pending_event_changes_[i].fd;
for (int j = 0; j < max_ops; ++j)
op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
pending_event_changes_.clear();
pending_event_change_index_.clear();
}
int timeout = block ? get_timeout() : 0;
lock.unlock();
// Block on the /dev/poll descriptor.
::pollfd events[128] = { { 0 } };
::dvpoll dp = { 0 };
dp.dp_fds = events;
dp.dp_nfds = 128;
dp.dp_timeout = timeout;
int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
lock.lock();
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
more_except =
op_queue_[except_op].perform_operations(descriptor, ops);
else
more_except = op_queue_[except_op].has_operation(descriptor);
if (events[i].events & (POLLIN | POLLERR | POLLHUP))
more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
else
more_reads = op_queue_[read_op].has_operation(descriptor);
if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
else
more_writes = op_queue_[write_op].has_operation(descriptor);
if ((events[i].events & (POLLERR | POLLHUP)) != 0
&& !more_except && !more_reads && !more_writes)
{
// If we have an event and no operations associated with the
// descriptor then we need to delete the descriptor from /dev/poll.
// The poll operation can produce POLLHUP or POLLERR events when there
// is no operation pending, so if we do not remove the descriptor we
// can end up in a tight polling loop.
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLREMOVE;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
else
{
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLERR | POLLHUP;
if (more_reads)
ev.events |= POLLIN;
if (more_writes)
ev.events |= POLLOUT;
if (more_except)
ev.events |= POLLPRI;
ev.revents = 0;
int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
if (result != sizeof(ev))
{
asio::error_code ec(errno,
asio::error::get_system_category());
for (int j = 0; j < max_ops; ++j)
op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
}
}
timer_queues_.get_ready_timers(ops);
}
ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
ASIO_DECL void interrupt();
private:
// Create the /dev/poll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_dev_poll_create()
{
int fd = ::open("/dev/poll", O_RDWR);
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"/dev/poll"));
}
return fd;
}
ASIO_DECL static int do_dev_poll_create();
// Helper function to add a new timer queue.
ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
// Helper function to remove a timer queue.
ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the /dev/poll DP_POLL operation. The timeout
// value is returned as a number of milliseconds. A return value of -1
// indicates that the poll should block indefinitely.
int get_timeout()
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
ASIO_DECL int get_timeout();
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the dev_poll_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor,
const asio::error_code& ec)
{
bool need_interrupt = false;
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
need_interrupt = op_queue_[i].cancel_operations(
descriptor, ops, ec) || need_interrupt;
io_service_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
const asio::error_code& ec);
// Add a pending event entry for the given descriptor.
::pollfd& add_pending_event_change(int descriptor)
{
hash_map<int, std::size_t>::iterator iter
= pending_event_change_index_.find(descriptor);
if (iter == pending_event_change_index_.end())
{
std::size_t index = pending_event_changes_.size();
pending_event_changes_.reserve(pending_event_changes_.size() + 1);
pending_event_change_index_.insert(std::make_pair(descriptor, index));
pending_event_changes_.push_back(::pollfd());
pending_event_changes_[index].fd = descriptor;
pending_event_changes_[index].revents = 0;
return pending_event_changes_[index];
}
else
{
return pending_event_changes_[iter->second];
}
}
ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
// The io_service implementation used to post completions.
io_service_impl& io_service_;
@@ -446,8 +173,13 @@ private:
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#include "asio/detail/impl/dev_poll_reactor.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/detail/impl/dev_poll_reactor.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // defined(ASIO_HAS_DEV_POLL)
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP

View File

@@ -1,8 +1,8 @@
//
// dev_poll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
// detail/dev_poll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,13 +15,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(ASIO_DISABLE_DEV_POLL)
#if defined(__sun) // This service is only supported on Solaris.
// Define this to indicate that /dev/poll is supported on the target platform.
#define ASIO_HAS_DEV_POLL 1
#if defined(ASIO_HAS_DEV_POLL)
namespace asio {
namespace detail {
@@ -31,9 +27,6 @@ class dev_poll_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__sun)
#endif // !defined(ASIO_DISABLE_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_DEV_POLL)
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP

View File

@@ -1,8 +1,8 @@
//
// epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~
// detail/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,43 +15,24 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/epoll_reactor_fwd.hpp"
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EPOLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <sys/epoll.h>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/epoll_reactor_fwd.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/object_pool.hpp"
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_op.hpp"
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_fwd.hpp"
#include "asio/detail/timer_queue_set.hpp"
#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
# define ASIO_HAS_TIMERFD 1
#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
#if defined(ASIO_HAS_TIMERFD)
# include "asio/detail/push_options.hpp"
# include <sys/timerfd.h>
# include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_TIMERFD)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -64,357 +45,86 @@ public:
connect_op = 1, except_op = 2, max_ops = 3 };
// Per-descriptor queues.
struct descriptor_state
class descriptor_state
{
descriptor_state() {}
descriptor_state(const descriptor_state&) {}
void operator=(const descriptor_state&) {}
friend class epoll_reactor;
friend class object_pool_access;
mutex mutex_;
op_queue<reactor_op> op_queue_[max_ops];
bool shutdown_;
descriptor_state* next_;
descriptor_state* prev_;
};
// Per-descriptor data.
typedef descriptor_state* per_descriptor_data;
// Constructor.
epoll_reactor(asio::io_service& io_service)
: asio::detail::service_base<epoll_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
epoll_fd_(do_epoll_create()),
#if defined(ASIO_HAS_TIMERFD)
timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
#else // defined(ASIO_HAS_TIMERFD)
timer_fd_(-1),
#endif // defined(ASIO_HAS_TIMERFD)
interrupter_(),
shutdown_(false)
{
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLET;
ev.data.ptr = &interrupter_;
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
interrupter_.interrupt();
// Add the timer descriptor to epoll.
if (timer_fd_ != -1)
{
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = &timer_fd_;
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
}
}
ASIO_DECL epoll_reactor(asio::io_service& io_service);
// Destructor.
~epoll_reactor()
{
close(epoll_fd_);
if (timer_fd_ != -1)
close(timer_fd_);
}
ASIO_DECL ~epoll_reactor();
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
descriptor_map::iterator iter = registered_descriptors_.begin();
descriptor_map::iterator end = registered_descriptors_.end();
while (iter != end)
{
for (int i = 0; i < max_ops; ++i)
ops.push(iter->second.op_queue_[i]);
iter->second.shutdown_ = true;
++iter;
}
timer_queues_.get_all_timers(ops);
}
ASIO_DECL void shutdown_service();
// Initialise the task.
void init_task()
{
io_service_.init_task();
}
ASIO_DECL void init_task();
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data)
ASIO_DECL int register_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data);
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op)
{
mutex::scoped_lock lock(registered_descriptors_mutex_);
descriptor_map::iterator new_entry = registered_descriptors_.insert(
std::make_pair(descriptor, descriptor_state())).first;
descriptor_data = &new_entry->second;
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
ev.data.ptr = descriptor_data;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
return errno;
descriptor_data->shutdown_ = false;
return 0;
io_service_.post_immediate_completion(op);
}
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data,
reactor_op* op, bool allow_speculative)
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
if (descriptor_data->shutdown_)
return;
if (descriptor_data->op_queue_[op_type].empty())
{
if (allow_speculative
&& (op_type != read_op
|| descriptor_data->op_queue_[except_op].empty()))
{
if (op->perform())
{
descriptor_lock.unlock();
io_service_.post_immediate_completion(op);
return;
}
}
else
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
| EPOLLOUT | EPOLLPRI | EPOLLET;
ev.data.ptr = descriptor_data;
epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
}
}
descriptor_data->op_queue_[op_type].push(op);
io_service_.work_started();
}
reactor_op* op, bool allow_speculative);
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type, per_descriptor_data& descriptor_data)
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_lock.unlock();
io_service_.post_deferred_completions(ops);
}
ASIO_DECL void cancel_ops(socket_type descriptor,
per_descriptor_data& descriptor_data);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data)
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
// Remove the descriptor from the set of known descriptors. The descriptor
// will be automatically removed from the epoll set when it is closed.
descriptor_data->shutdown_ = true;
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_lock.unlock();
registered_descriptors_.erase(descriptor);
descriptors_lock.unlock();
io_service_.post_deferred_completions(ops);
}
ASIO_DECL void close_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data);
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&timer_queue);
}
void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&timer_queue);
}
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
// Schedule a new operation in the given timer queue to expire at the
// specified absolute time.
template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
mutex::scoped_lock lock(mutex_);
if (!shutdown_)
{
bool earliest = timer_queue.enqueue_timer(time, op, token);
io_service_.work_started();
if (earliest)
{
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ != -1)
{
itimerspec new_timeout;
itimerspec old_timeout;
int flags = get_timeout(new_timeout);
timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
return;
}
#endif // defined(ASIO_HAS_TIMERFD)
interrupter_.interrupt();
}
}
}
void schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op);
// Cancel the timer operations associated with the given token. Returns the
// number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = timer_queue.cancel_timer(token, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer);
// Run epoll once until interrupted or events are ready to be dispatched.
void run(bool block, op_queue<operation>& ops)
{
// Calculate a timeout only if timerfd is not used.
int timeout;
if (timer_fd_ != -1)
timeout = block ? -1 : 0;
else
{
mutex::scoped_lock lock(mutex_);
timeout = block ? get_timeout() : 0;
}
// Block on the epoll descriptor.
epoll_event events[128];
int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
#if defined(ASIO_HAS_TIMERFD)
bool check_timers = (timer_fd_ == -1);
#else // defined(ASIO_HAS_TIMERFD)
bool check_timers = true;
#endif // defined(ASIO_HAS_TIMERFD)
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
void* ptr = events[i].data.ptr;
if (ptr == &interrupter_)
{
// No need to reset the interrupter since we're leaving the descriptor
// in a ready-to-read state and relying on edge-triggered notifications
// to make it so that we only get woken up when the descriptor's epoll
// registration is updated.
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ == -1)
check_timers = true;
#else // defined(ASIO_HAS_TIMERFD)
check_timers = true;
#endif // defined(ASIO_HAS_TIMERFD)
}
#if defined(ASIO_HAS_TIMERFD)
else if (ptr == &timer_fd_)
{
check_timers = true;
}
#endif // defined(ASIO_HAS_TIMERFD)
else
{
descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
for (int j = max_ops - 1; j >= 0; --j)
{
if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
{
while (reactor_op* op = descriptor_data->op_queue_[j].front())
{
if (op->perform())
{
descriptor_data->op_queue_[j].pop();
ops.push(op);
}
else
break;
}
}
}
}
}
if (check_timers)
{
mutex::scoped_lock common_lock(mutex_);
timer_queues_.get_ready_timers(ops);
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ != -1)
{
itimerspec new_timeout;
itimerspec old_timeout;
int flags = get_timeout(new_timeout);
timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
}
#endif // defined(ASIO_HAS_TIMERFD)
}
}
ASIO_DECL void run(bool block, op_queue<operation>& ops);
// Interrupt the select loop.
void interrupt()
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLET;
ev.data.ptr = &interrupter_;
epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
}
ASIO_DECL void interrupt();
private:
// The hint to pass to epoll_create to size its data structures.
@@ -422,44 +132,26 @@ private:
// Create the epoll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_epoll_create()
{
int fd = epoll_create(epoll_size);
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"epoll"));
}
return fd;
}
ASIO_DECL static int do_epoll_create();
// Helper function to add a new timer queue.
ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
// Helper function to remove a timer queue.
ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Called to recalculate and update the timeout.
ASIO_DECL void update_timeout();
// Get the timeout value for the epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait should block indefinitely.
int get_timeout()
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
ASIO_DECL int get_timeout();
#if defined(ASIO_HAS_TIMERFD)
// Get the timeout value for the timer descriptor. The return value is the
// flag argument to be used when calling timerfd_settime.
int get_timeout(itimerspec& ts)
{
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
ts.it_value.tv_sec = usec / 1000000;
ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
return usec ? 0 : TFD_TIMER_ABSTIME;
}
ASIO_DECL int get_timeout(itimerspec& ts);
#endif // defined(ASIO_HAS_TIMERFD)
// The io_service implementation used to post completions.
@@ -486,22 +178,20 @@ private:
// Mutex to protect access to the registered descriptors.
mutex registered_descriptors_mutex_;
// Keep track of all registered descriptors. This code relies on the fact that
// the hash_map implementation pools deleted nodes, meaning that we can assume
// our descriptor_state pointer remains valid even after the entry is removed.
// Technically this is not true for C++98, as that standard says that spliced
// elements in a list are invalidated. However, C++0x fixes this shortcoming
// so we'll just assume that C++98 std::list implementations will do the right
// thing anyway.
typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
descriptor_map registered_descriptors_;
// Keep track of all registered descriptors.
object_pool<descriptor_state> registered_descriptors_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_EPOLL)
#include "asio/detail/pop_options.hpp"
#include "asio/detail/impl/epoll_reactor.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/detail/impl/epoll_reactor.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // defined(ASIO_HAS_EPOLL)
#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP

View File

@@ -1,8 +1,8 @@
//
// epoll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~
// detail/epoll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,19 +15,9 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(ASIO_DISABLE_EPOLL)
#if defined(__linux__) // This service is only supported on Linux.
#include "asio/detail/push_options.hpp"
#include <linux/version.h>
#include "asio/detail/pop_options.hpp"
#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_EPOLL 1
#if defined(ASIO_HAS_EPOLL)
namespace asio {
namespace detail {
@@ -37,10 +27,6 @@ class epoll_reactor;
} // namespace detail
} // namespace asio
#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
#endif // defined(__linux__)
#endif // !defined(ASIO_DISABLE_EPOLL)
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_EPOLL)
#endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP

View File

@@ -1,8 +1,8 @@
//
// event.hpp
// ~~~~~~~~~
// detail/event.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,11 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
# include "asio/detail/null_event.hpp"
@@ -45,6 +41,4 @@ typedef posix_event event;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EVENT_HPP

View File

@@ -1,8 +1,8 @@
//
// eventfd_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/eventfd_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -16,36 +16,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(__linux__)
# if !defined(ASIO_DISABLE_EVENTFD)
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
# define ASIO_HAS_EVENTFD
# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
# endif // !defined(ASIO_DISABLE_EVENTFD)
#endif // defined(__linux__)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EVENTFD)
#include "asio/detail/push_options.hpp"
#include <fcntl.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
# include <asm/unistd.h>
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
# include <sys/eventfd.h>
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
@@ -54,87 +29,16 @@ class eventfd_select_interrupter
{
public:
// Constructor.
eventfd_select_interrupter()
{
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
int pipe_fds[2];
if (pipe(pipe_fds) == 0)
{
read_descriptor_ = pipe_fds[0];
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::system_error e(ec, "eventfd_select_interrupter");
boost::throw_exception(e);
}
}
}
ASIO_DECL eventfd_select_interrupter();
// Destructor.
~eventfd_select_interrupter()
{
if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
::close(write_descriptor_);
if (read_descriptor_ != -1)
::close(read_descriptor_);
}
ASIO_DECL ~eventfd_select_interrupter();
// Interrupt the select call.
void interrupt()
{
uint64_t counter(1UL);
int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
(void)result;
}
ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted.
bool reset()
{
if (write_descriptor_ == read_descriptor_)
{
for (;;)
{
// Only perform one read. The kernel maintains an atomic counter.
uint64_t counter(0);
errno = 0;
int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
return was_interrupted;
}
}
else
{
for (;;)
{
// Clear all data from the pipe.
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
}
}
}
ASIO_DECL bool reset();
// Get the read descriptor to be passed to select.
int read_descriptor() const
@@ -159,8 +63,12 @@ private:
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_EVENTFD)
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/detail/impl/eventfd_select_interrupter.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // defined(ASIO_HAS_EVENTFD)
#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP

View File

@@ -1,8 +1,8 @@
//
// fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~
// detail/fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,12 +15,7 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/posix_fd_set_adapter.hpp"
#include "asio/detail/win_fd_set_adapter.hpp"
@@ -36,6 +31,4 @@ typedef posix_fd_set_adapter fd_set_adapter;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP

View File

@@ -1,8 +1,8 @@
//
// fenced_block.hpp
// ~~~~~~~~~~~~~~~~
// detail/fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,23 +15,25 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
#if !defined(BOOST_HAS_THREADS) \
|| defined(ASIO_DISABLE_THREADS) \
|| defined(ASIO_DISABLE_FENCED_BLOCK)
# include "asio/detail/null_fenced_block.hpp"
#elif defined(__MACH__) && defined(__APPLE__)
# include "asio/detail/macos_fenced_block.hpp"
#elif defined(__sun)
# include "asio/detail/solaris_fenced_block.hpp"
#elif defined(__GNUC__) && defined(__arm__)
# include "asio/detail/gcc_arm_fenced_block.hpp"
#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
# include "asio/detail/gcc_hppa_fenced_block.hpp"
#elif defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
# include "asio/detail/gcc_fenced_block.hpp"
# include "asio/detail/gcc_sync_fenced_block.hpp"
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
# include "asio/detail/gcc_x86_fenced_block.hpp"
#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -43,17 +45,23 @@
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS)
#if !defined(BOOST_HAS_THREADS) \
|| defined(ASIO_DISABLE_THREADS) \
|| defined(ASIO_DISABLE_FENCED_BLOCK)
typedef null_fenced_block fenced_block;
#elif defined(__MACH__) && defined(__APPLE__)
typedef macos_fenced_block fenced_block;
#elif defined(__sun)
typedef solaris_fenced_block fenced_block;
#elif defined(__GNUC__) && defined(__arm__)
typedef gcc_arm_fenced_block fenced_block;
#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
typedef gcc_hppa_fenced_block fenced_block;
#elif defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
typedef gcc_fenced_block fenced_block;
typedef gcc_sync_fenced_block fenced_block;
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
typedef gcc_x86_fenced_block fenced_block;
#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
@@ -65,6 +73,4 @@ typedef null_fenced_block fenced_block;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_FENCED_BLOCK_HPP

View File

@@ -0,0 +1,76 @@
//
// detail/gcc_arm_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(__GNUC__) && defined(__arm__)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class gcc_arm_fenced_block
: private noncopyable
{
public:
// Constructor.
gcc_arm_fenced_block()
{
barrier();
}
// Destructor.
~gcc_arm_fenced_block()
{
barrier();
}
private:
static void barrier()
{
#if defined(__ARM_ARCH_4__) \
|| defined(__ARM_ARCH_4T__) \
|| defined(__ARM_ARCH_5__) \
|| defined(__ARM_ARCH_5E__) \
|| defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__) \
|| defined(__ARM_ARCH_6__) \
|| defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) \
|| defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) \
|| defined(__ARM_ARCH_6T2__)
int a = 0, b = 0;
__asm__ __volatile__ ("swp %0, %1, [%2]"
: "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");
#else
// ARMv7 and later.
__asm__ __volatile__ ("dmb" : : : "memory");
#endif
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(__GNUC__) && defined(__arm__)
#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP

View File

@@ -0,0 +1,58 @@
//
// detail/gcc_hppa_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class gcc_hppa_fenced_block
: private noncopyable
{
public:
// Constructor.
gcc_hppa_fenced_block()
{
barrier();
}
// Destructor.
~gcc_hppa_fenced_block()
{
barrier();
}
private:
static void barrier()
{
// This is just a placeholder and almost certainly not sufficient.
__asm__ __volatile__ ("" : : : "memory");
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP

View File

@@ -0,0 +1,61 @@
//
// detail/gcc_sync_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class gcc_sync_fenced_block
: private noncopyable
{
public:
// Constructor.
gcc_sync_fenced_block()
: value_(0)
{
__sync_lock_test_and_set(&value_, 1);
}
// Destructor.
~gcc_sync_fenced_block()
{
__sync_lock_release(&value_);
}
private:
int value_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(__GNUC__)
// && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
// && !defined(__INTEL_COMPILER) && !defined(__ICL)
// && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP

View File

@@ -1,8 +1,8 @@
//
// gcc_x86_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
// detail/gcc_x86_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,14 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/config.hpp"
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
@@ -54,8 +52,8 @@ private:
} // namespace detail
} // namespace asio
#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#include "asio/detail/pop_options.hpp"
#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP

View File

@@ -1,8 +1,8 @@
//
// handler_alloc_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/handler_alloc_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
#include <boost/utility/addressof.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/detail/push_options.hpp"
// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
// a namespace that does not contain any overloads of these functions. The
@@ -56,203 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
} // namespace asio_handler_alloc_helpers
namespace asio {
namespace detail {
// Traits for handler allocation.
template <typename Handler, typename Object>
struct handler_alloc_traits
{
typedef Handler handler_type;
typedef Object value_type;
typedef Object* pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
};
template <typename Alloc_Traits>
class handler_ptr;
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class raw_handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
// Constructor allocates the memory.
raw_handler_ptr(handler_type& handler)
: handler_(handler),
pointer_(static_cast<pointer_type>(
asio_handler_alloc_helpers::allocate(value_size, handler_)))
{
}
// Destructor automatically deallocates memory, unless it has been stolen by
// a handler_ptr object.
~raw_handler_ptr()
{
if (pointer_)
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, handler_);
}
private:
friend class handler_ptr<Alloc_Traits>;
handler_type& handler_;
pointer_type pointer_;
};
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
// Take ownership of existing memory.
handler_ptr(handler_type& handler, pointer_type pointer)
: handler_(handler),
pointer_(pointer)
{
}
// Construct object in raw memory and take ownership if construction succeeds.
handler_ptr(raw_ptr_type& raw_ptr)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type)
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7, typename Arg8>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(
a1, a2, a3, a4, a5, a6, a7, a8))
{
raw_ptr.pointer_ = 0;
}
// Destructor automatically deallocates memory, unless it has been released.
~handler_ptr()
{
reset();
}
// Get the memory.
pointer_type get() const
{
return pointer_;
}
// Release ownership of the memory.
pointer_type release()
{
pointer_type tmp = pointer_;
pointer_ = 0;
return tmp;
}
// Explicitly destroy and deallocate the memory.
void reset()
{
if (pointer_)
{
pointer_->value_type::~value_type();
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, handler_);
pointer_ = 0;
}
}
private:
handler_type& handler_;
pointer_type pointer_;
};
} // namespace detail
} // namespace asio
#define ASIO_DEFINE_HANDLER_PTR(op) \
struct ptr \
{ \
Handler* h; \
void* v; \
op* p; \
~ptr() \
{ \
reset(); \
} \
void reset() \
{ \
if (p) \
{ \
p->~op(); \
p = 0; \
} \
if (v) \
{ \
asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \
v = 0; \
} \
} \
} \
/**/
#include "asio/detail/pop_options.hpp"

View File

@@ -1,8 +1,8 @@
//
// handler_invoke_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/handler_invoke_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <boost/detail/workaround.hpp>
#include <boost/utility/addressof.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/detail/push_options.hpp"
// Calls to asio_handler_invoke must be made from a namespace that does not
// contain overloads of this function. The asio_handler_invoke_helpers
// namespace is defined here for that purpose.

View File

@@ -1,8 +1,8 @@
//
// hash_map.hpp
// ~~~~~~~~~~~~
// detail/hash_map.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,33 +15,38 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cassert>
#include <list>
#include <utility>
#include <boost/functional/hash.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# include "asio/detail/socket_types.hpp"
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename T>
inline std::size_t calculate_hash_value(const T& t)
inline std::size_t calculate_hash_value(int i)
{
return boost::hash_value(t);
return static_cast<std::size_t>(i);
}
#if defined(_WIN64)
inline std::size_t calculate_hash_value(void* p)
{
return reinterpret_cast<std::size_t>(p)
+ (reinterpret_cast<std::size_t>(p) >> 3);
}
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
inline std::size_t calculate_hash_value(SOCKET s)
{
return static_cast<std::size_t>(s);
}
#endif // defined(_WIN64)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Note: assumes K and V are POD types.
template <typename K, typename V>

View File

@@ -0,0 +1,382 @@
//
// detail/impl/descriptor_ops.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cerrno>
#include "asio/detail/descriptor_ops.hpp"
#include "asio/error.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
namespace descriptor_ops {
ASIO_DECL
int open(const char* path, int flags, asio::error_code& ec)
{
errno = 0;
int result = error_wrapper(::open(path, flags), ec);
if (result >= 0)
ec = asio::error_code();
return result;
}
ASIO_DECL
int close(int d, state_type& state, asio::error_code& ec)
{
int result = 0;
if (d != -1)
{
if (state & internal_non_blocking)
{
#if defined(__SYMBIAN32__)
int flags = ::fcntl(d, F_GETFL, 0);
if (flags >= 0)
::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
#else // defined(__SYMBIAN32__)
ioctl_arg_type arg = 0;
::ioctl(d, FIONBIO, &arg);
#endif // defined(__SYMBIAN32__)
state &= ~internal_non_blocking;
}
errno = 0;
result = error_wrapper(::close(d), ec);
}
if (result == 0)
ec = asio::error_code();
return result;
}
ASIO_DECL
bool set_internal_non_blocking(int d,
state_type& state, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return false;
}
errno = 0;
#if defined(__SYMBIAN32__)
int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
if (result >= 0)
{
errno = 0;
result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec);
}
#else // defined(__SYMBIAN32__)
ioctl_arg_type arg = 1;
int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
#endif // defined(__SYMBIAN32__)
if (result >= 0)
{
ec = asio::error_code();
state |= internal_non_blocking;
return true;
}
return false;
}
ASIO_DECL
std::size_t sync_read(int d, state_type state, buf* bufs,
std::size_t count, bool all_empty, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (all_empty)
{
ec = asio::error_code();
return 0;
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
errno = 0;
int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Check for EOF.
if (bytes == 0)
{
ec = asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != asio::error::would_block
&& ec != asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_read(d, ec) < 0)
return 0;
}
}
ASIO_DECL
bool non_blocking_read(int d, buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Read some data.
errno = 0;
int bytes = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
// Check for end of stream.
if (bytes == 0)
{
ec = asio::error::eof;
return true;
}
// Retry operation if interrupted by signal.
if (ec == asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == asio::error::would_block
|| ec == asio::error::try_again)
return false;
// Operation is complete.
if (bytes > 0)
{
ec = asio::error_code();
bytes_transferred = bytes;
}
else
bytes_transferred = 0;
return true;
}
}
ASIO_DECL
std::size_t sync_write(int d, state_type state, const buf* bufs,
std::size_t count, bool all_empty, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (all_empty)
{
ec = asio::error_code();
return 0;
}
// Write some data.
for (;;)
{
// Try to complete the operation without blocking.
errno = 0;
int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != asio::error::would_block
&& ec != asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_write(d, ec) < 0)
return 0;
}
}
ASIO_DECL
bool non_blocking_write(int d, const buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Write some data.
errno = 0;
int bytes = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
// Retry operation if interrupted by signal.
if (ec == asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == asio::error::would_block
|| ec == asio::error::try_again)
return false;
// Operation is complete.
if (bytes >= 0)
{
ec = asio::error_code();
bytes_transferred = bytes;
}
else
bytes_transferred = 0;
return true;
}
}
ASIO_DECL
int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return -1;
}
errno = 0;
int result = error_wrapper(::ioctl(d, cmd, arg), ec);
if (result >= 0)
{
ec = asio::error_code();
// When updating the non-blocking mode we always perform the ioctl syscall,
// even if the flags would otherwise indicate that the descriptor is
// already in the correct state. This ensures that the underlying
// descriptor is put into the state that has been requested by the user. If
// the ioctl syscall was successful then we need to update the flags to
// match.
if (cmd == static_cast<long>(FIONBIO))
{
if (*arg)
{
state |= user_set_non_blocking;
}
else
{
// Clearing the non-blocking mode always overrides any internally-set
// non-blocking flag. Any subsequent asynchronous operations will need
// to re-enable non-blocking I/O.
state &= ~(user_set_non_blocking | internal_non_blocking);
}
}
}
return result;
}
ASIO_DECL
int fcntl(int d, long cmd, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd), ec);
if (result != -1)
ec = asio::error_code();
return result;
}
ASIO_DECL
int fcntl(int d, long cmd, long arg, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd, arg), ec);
if (result != -1)
ec = asio::error_code();
return result;
}
ASIO_DECL
int poll_read(int d, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return -1;
}
pollfd fds;
fds.fd = d;
fds.events = POLLIN;
fds.revents = 0;
errno = 0;
int result = error_wrapper(::poll(&fds, 1, -1), ec);
if (result >= 0)
ec = asio::error_code();
return result;
}
ASIO_DECL
int poll_write(int d, asio::error_code& ec)
{
if (d == -1)
{
ec = asio::error::bad_descriptor;
return -1;
}
pollfd fds;
fds.fd = d;
fds.events = POLLOUT;
fds.revents = 0;
errno = 0;
int result = error_wrapper(::poll(&fds, 1, -1), ec);
if (result >= 0)
ec = asio::error_code();
return result;
}
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP

View File

@@ -0,0 +1,77 @@
//
// detail/impl/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
template <typename Time_Traits>
void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
io_service_.post_immediate_completion(op);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
io_service_.work_started();
if (earliest)
interrupter_.interrupt();
}
template <typename Time_Traits>
std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer)
{
asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_DEV_POLL)
#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP

View File

@@ -0,0 +1,338 @@
//
// detail/impl/dev_poll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/dev_poll_reactor.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
dev_poll_reactor::dev_poll_reactor(asio::io_service& io_service)
: asio::detail::service_base<dev_poll_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
dev_poll_fd_(do_dev_poll_create()),
interrupter_(),
shutdown_(false)
{
// Add the interrupter's descriptor to /dev/poll.
::pollfd ev = { 0 };
ev.fd = interrupter_.read_descriptor();
ev.events = POLLIN | POLLERR;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
dev_poll_reactor::~dev_poll_reactor()
{
shutdown_service();
::close(dev_poll_fd_);
}
void dev_poll_reactor::shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
op_queue_[i].get_all_operations(ops);
timer_queues_.get_all_timers(ops);
}
void dev_poll_reactor::init_task()
{
io_service_.init_task();
}
int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
{
return 0;
}
void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
dev_poll_reactor::per_descriptor_data&,
reactor_op* op, bool allow_speculative)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op);
return;
}
if (allow_speculative)
{
if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
{
if (!op_queue_[op_type].has_operation(descriptor))
{
if (op->perform())
{
lock.unlock();
io_service_.post_immediate_completion(op);
return;
}
}
}
}
bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
io_service_.work_started();
if (first)
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLERR | POLLHUP;
if (op_type == read_op
|| op_queue_[read_op].has_operation(descriptor))
ev.events |= POLLIN;
if (op_type == write_op
|| op_queue_[write_op].has_operation(descriptor))
ev.events |= POLLOUT;
if (op_type == except_op
|| op_queue_[except_op].has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
void dev_poll_reactor::cancel_ops(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
void dev_poll_reactor::close_descriptor(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from /dev/poll.
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLREMOVE;
interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
&& op_queue_[except_op].empty() && timer_queues_.all_empty())
return;
// Write the pending event registration changes to the /dev/poll descriptor.
std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
if (events_size > 0)
{
errno = 0;
int result = ::write(dev_poll_fd_,
&pending_event_changes_[0], events_size);
if (result != static_cast<int>(events_size))
{
asio::error_code ec = asio::error_code(
errno, asio::error::get_system_category());
for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
{
int descriptor = pending_event_changes_[i].fd;
for (int j = 0; j < max_ops; ++j)
op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
pending_event_changes_.clear();
pending_event_change_index_.clear();
}
int timeout = block ? get_timeout() : 0;
lock.unlock();
// Block on the /dev/poll descriptor.
::pollfd events[128] = { { 0 } };
::dvpoll dp = { 0 };
dp.dp_fds = events;
dp.dp_nfds = 128;
dp.dp_timeout = timeout;
int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
lock.lock();
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
more_except =
op_queue_[except_op].perform_operations(descriptor, ops);
else
more_except = op_queue_[except_op].has_operation(descriptor);
if (events[i].events & (POLLIN | POLLERR | POLLHUP))
more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
else
more_reads = op_queue_[read_op].has_operation(descriptor);
if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
else
more_writes = op_queue_[write_op].has_operation(descriptor);
if ((events[i].events & (POLLERR | POLLHUP)) != 0
&& !more_except && !more_reads && !more_writes)
{
// If we have an event and no operations associated with the
// descriptor then we need to delete the descriptor from /dev/poll.
// The poll operation can produce POLLHUP or POLLERR events when there
// is no operation pending, so if we do not remove the descriptor we
// can end up in a tight polling loop.
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLREMOVE;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
else
{
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLERR | POLLHUP;
if (more_reads)
ev.events |= POLLIN;
if (more_writes)
ev.events |= POLLOUT;
if (more_except)
ev.events |= POLLPRI;
ev.revents = 0;
int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
if (result != sizeof(ev))
{
asio::error_code ec(errno,
asio::error::get_system_category());
for (int j = 0; j < max_ops; ++j)
op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
}
}
timer_queues_.get_ready_timers(ops);
}
void dev_poll_reactor::interrupt()
{
interrupter_.interrupt();
}
int dev_poll_reactor::do_dev_poll_create()
{
int fd = ::open("/dev/poll", O_RDWR);
if (fd == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::detail::throw_error(ec, "/dev/poll");
}
return fd;
}
void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
int dev_poll_reactor::get_timeout()
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
const asio::error_code& ec)
{
bool need_interrupt = false;
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
need_interrupt = op_queue_[i].cancel_operations(
descriptor, ops, ec) || need_interrupt;
io_service_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)
{
hash_map<int, std::size_t>::iterator iter
= pending_event_change_index_.find(descriptor);
if (iter == pending_event_change_index_.end())
{
std::size_t index = pending_event_changes_.size();
pending_event_changes_.reserve(pending_event_changes_.size() + 1);
pending_event_change_index_.insert(std::make_pair(descriptor, index));
pending_event_changes_.push_back(::pollfd());
pending_event_changes_[index].fd = descriptor;
pending_event_changes_[index].revents = 0;
return pending_event_changes_[index];
}
else
{
return pending_event_changes_[iter->second];
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_DEV_POLL)
#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP

View File

@@ -0,0 +1,75 @@
//
// detail/impl/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#if defined(ASIO_HAS_EPOLL)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
template <typename Time_Traits>
void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
{
mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
io_service_.post_immediate_completion(op);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
io_service_.work_started();
if (earliest)
update_timeout();
}
template <typename Time_Traits>
std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_EPOLL)
#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP

View File

@@ -0,0 +1,390 @@
//
// detail/impl/epoll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EPOLL)
#include <cstddef>
#include <sys/epoll.h>
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#if defined(ASIO_HAS_TIMERFD)
# include <sys/timerfd.h>
#endif // defined(ASIO_HAS_TIMERFD)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
epoll_reactor::epoll_reactor(asio::io_service& io_service)
: asio::detail::service_base<epoll_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
epoll_fd_(do_epoll_create()),
#if defined(ASIO_HAS_TIMERFD)
timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
#else // defined(ASIO_HAS_TIMERFD)
timer_fd_(-1),
#endif // defined(ASIO_HAS_TIMERFD)
interrupter_(),
shutdown_(false)
{
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLET;
ev.data.ptr = &interrupter_;
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
interrupter_.interrupt();
// Add the timer descriptor to epoll.
if (timer_fd_ != -1)
{
ev.events = EPOLLIN | EPOLLERR;
ev.data.ptr = &timer_fd_;
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
}
}
epoll_reactor::~epoll_reactor()
{
close(epoll_fd_);
if (timer_fd_ != -1)
close(timer_fd_);
}
void epoll_reactor::shutdown_service()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
while (descriptor_state* state = registered_descriptors_.first())
{
for (int i = 0; i < max_ops; ++i)
ops.push(state->op_queue_[i]);
state->shutdown_ = true;
registered_descriptors_.free(state);
}
timer_queues_.get_all_timers(ops);
}
void epoll_reactor::init_task()
{
io_service_.init_task();
}
int epoll_reactor::register_descriptor(socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data)
{
mutex::scoped_lock lock(registered_descriptors_mutex_);
descriptor_data = registered_descriptors_.alloc();
descriptor_data->shutdown_ = false;
lock.unlock();
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
ev.data.ptr = descriptor_data;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
return errno;
return 0;
}
void epoll_reactor::start_op(int op_type, socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data,
reactor_op* op, bool allow_speculative)
{
if (!descriptor_data)
{
op->ec_ = asio::error::bad_descriptor;
post_immediate_completion(op);
return;
}
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
if (descriptor_data->shutdown_)
{
post_immediate_completion(op);
return;
}
if (descriptor_data->op_queue_[op_type].empty())
{
if (allow_speculative
&& (op_type != read_op
|| descriptor_data->op_queue_[except_op].empty()))
{
if (op->perform())
{
descriptor_lock.unlock();
io_service_.post_immediate_completion(op);
return;
}
}
else
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
| EPOLLOUT | EPOLLPRI | EPOLLET;
ev.data.ptr = descriptor_data;
epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
}
}
descriptor_data->op_queue_[op_type].push(op);
io_service_.work_started();
}
void epoll_reactor::cancel_ops(socket_type,
epoll_reactor::per_descriptor_data& descriptor_data)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_lock.unlock();
io_service_.post_deferred_completions(ops);
}
void epoll_reactor::close_descriptor(socket_type,
epoll_reactor::per_descriptor_data& descriptor_data)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
if (!descriptor_data->shutdown_)
{
// Remove the descriptor from the set of known descriptors. The descriptor
// will be automatically removed from the epoll set when it is closed.
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_data->shutdown_ = true;
descriptor_lock.unlock();
registered_descriptors_.free(descriptor_data);
descriptor_data = 0;
descriptors_lock.unlock();
io_service_.post_deferred_completions(ops);
}
}
void epoll_reactor::run(bool block, op_queue<operation>& ops)
{
// Calculate a timeout only if timerfd is not used.
int timeout;
if (timer_fd_ != -1)
timeout = block ? -1 : 0;
else
{
mutex::scoped_lock lock(mutex_);
timeout = block ? get_timeout() : 0;
}
// Block on the epoll descriptor.
epoll_event events[128];
int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
#if defined(ASIO_HAS_TIMERFD)
bool check_timers = (timer_fd_ == -1);
#else // defined(ASIO_HAS_TIMERFD)
bool check_timers = true;
#endif // defined(ASIO_HAS_TIMERFD)
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
void* ptr = events[i].data.ptr;
if (ptr == &interrupter_)
{
// No need to reset the interrupter since we're leaving the descriptor
// in a ready-to-read state and relying on edge-triggered notifications
// to make it so that we only get woken up when the descriptor's epoll
// registration is updated.
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ == -1)
check_timers = true;
#else // defined(ASIO_HAS_TIMERFD)
check_timers = true;
#endif // defined(ASIO_HAS_TIMERFD)
}
#if defined(ASIO_HAS_TIMERFD)
else if (ptr == &timer_fd_)
{
check_timers = true;
}
#endif // defined(ASIO_HAS_TIMERFD)
else
{
descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
for (int j = max_ops - 1; j >= 0; --j)
{
if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
{
while (reactor_op* op = descriptor_data->op_queue_[j].front())
{
if (op->perform())
{
descriptor_data->op_queue_[j].pop();
ops.push(op);
}
else
break;
}
}
}
}
}
if (check_timers)
{
mutex::scoped_lock common_lock(mutex_);
timer_queues_.get_ready_timers(ops);
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ != -1)
{
itimerspec new_timeout;
itimerspec old_timeout;
int flags = get_timeout(new_timeout);
timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
}
#endif // defined(ASIO_HAS_TIMERFD)
}
}
void epoll_reactor::interrupt()
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLET;
ev.data.ptr = &interrupter_;
epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
}
int epoll_reactor::do_epoll_create()
{
int fd = epoll_create(epoll_size);
if (fd == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::detail::throw_error(ec, "epoll");
}
return fd;
}
void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
void epoll_reactor::update_timeout()
{
#if defined(ASIO_HAS_TIMERFD)
if (timer_fd_ != -1)
{
itimerspec new_timeout;
itimerspec old_timeout;
int flags = get_timeout(new_timeout);
timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
return;
}
#endif // defined(ASIO_HAS_TIMERFD)
interrupt();
}
int epoll_reactor::get_timeout()
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
#if defined(ASIO_HAS_TIMERFD)
int epoll_reactor::get_timeout(itimerspec& ts)
{
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
ts.it_value.tv_sec = usec / 1000000;
ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
return usec ? 0 : TFD_TIMER_ABSTIME;
}
#endif // defined(ASIO_HAS_TIMERFD)
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_EPOLL)
#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP

View File

@@ -0,0 +1,125 @@
//
// detail/impl/eventfd_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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)
//
#ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_EVENTFD)
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
# include <asm/unistd.h>
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
# include <sys/eventfd.h>
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#include "asio/detail/eventfd_select_interrupter.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
eventfd_select_interrupter::eventfd_select_interrupter()
{
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
int pipe_fds[2];
if (pipe(pipe_fds) == 0)
{
read_descriptor_ = pipe_fds[0];
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::detail::throw_error(ec, "eventfd_select_interrupter");
}
}
}
eventfd_select_interrupter::~eventfd_select_interrupter()
{
if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
::close(write_descriptor_);
if (read_descriptor_ != -1)
::close(read_descriptor_);
}
void eventfd_select_interrupter::interrupt()
{
uint64_t counter(1UL);
int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
(void)result;
}
bool eventfd_select_interrupter::reset()
{
if (write_descriptor_ == read_descriptor_)
{
for (;;)
{
// Only perform one read. The kernel maintains an atomic counter.
uint64_t counter(0);
errno = 0;
int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
return was_interrupted;
}
}
else
{
for (;;)
{
// Clear all data from the pipe.
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
}
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_EVENTFD)
#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP

View File

@@ -0,0 +1,79 @@
//
// detail/impl/kqueue_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze 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)
//
#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_KQUEUE)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
io_service_.post_immediate_completion(op);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
io_service_.work_started();
if (earliest)
interrupt();
}
template <typename Time_Traits>
std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer)
{
asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_KQUEUE)
#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP

View File

@@ -0,0 +1,385 @@
//
// detail/impl/kqueue_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze 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)
//
#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_KQUEUE)
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
#if defined(__NetBSD__)
# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
EV_SET(ev, ident, filt, flags, fflags, \
data, reinterpret_cast<intptr_t>(udata))
#else
# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
EV_SET(ev, ident, filt, flags, fflags, data, udata)
#endif
namespace asio {
namespace detail {
kqueue_reactor::kqueue_reactor(asio::io_service& io_service)
: asio::detail::service_base<kqueue_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
kqueue_fd_(do_kqueue_create()),
interrupter_(),
shutdown_(false)
{
// The interrupter is put into a permanently readable state. Whenever we
// want to interrupt the blocked kevent call we register a one-shot read
// operation against the descriptor.
interrupter_.interrupt();
}
kqueue_reactor::~kqueue_reactor()
{
close(kqueue_fd_);
}
void kqueue_reactor::shutdown_service()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
while (descriptor_state* state = registered_descriptors_.first())
{
for (int i = 0; i < max_ops; ++i)
ops.push(state->op_queue_[i]);
state->shutdown_ = true;
registered_descriptors_.free(state);
}
timer_queues_.get_all_timers(ops);
}
void kqueue_reactor::init_task()
{
io_service_.init_task();
}
int kqueue_reactor::register_descriptor(socket_type,
kqueue_reactor::per_descriptor_data& descriptor_data)
{
mutex::scoped_lock lock(registered_descriptors_mutex_);
descriptor_data = registered_descriptors_.alloc();
descriptor_data->shutdown_ = false;
return 0;
}
void kqueue_reactor::start_op(int op_type, socket_type descriptor,
kqueue_reactor::per_descriptor_data& descriptor_data,
reactor_op* op, bool allow_speculative)
{
if (!descriptor_data)
{
op->ec_ = asio::error::bad_descriptor;
post_immediate_completion(op);
return;
}
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
if (descriptor_data->shutdown_)
{
post_immediate_completion(op);
return;
}
bool first = descriptor_data->op_queue_[op_type].empty();
if (first)
{
if (allow_speculative)
{
if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
{
if (op->perform())
{
descriptor_lock.unlock();
io_service_.post_immediate_completion(op);
return;
}
}
}
}
descriptor_data->op_queue_[op_type].push(op);
io_service_.work_started();
if (first)
{
struct kevent event;
switch (op_type)
{
case read_op:
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
break;
case write_op:
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
break;
case except_op:
if (!descriptor_data->op_queue_[read_op].empty())
return; // Already registered for read events.
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
break;
}
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
op->ec_ = asio::error_code(errno,
asio::error::get_system_category());
descriptor_data->op_queue_[op_type].pop();
io_service_.post_deferred_completion(op);
}
}
}
void kqueue_reactor::cancel_ops(socket_type,
kqueue_reactor::per_descriptor_data& descriptor_data)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_lock.unlock();
io_service_.post_deferred_completions(ops);
}
void kqueue_reactor::close_descriptor(socket_type,
kqueue_reactor::per_descriptor_data& descriptor_data)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
if (!descriptor_data->shutdown_)
{
// Remove the descriptor from the set of known descriptors. The descriptor
// will be automatically removed from the kqueue set when it is closed.
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
{
while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
op->ec_ = asio::error::operation_aborted;
descriptor_data->op_queue_[i].pop();
ops.push(op);
}
}
descriptor_data->shutdown_ = true;
descriptor_lock.unlock();
registered_descriptors_.free(descriptor_data);
descriptor_data = 0;
descriptors_lock.unlock();
io_service_.post_deferred_completions(ops);
}
}
void kqueue_reactor::run(bool block, op_queue<operation>& ops)
{
mutex::scoped_lock lock(mutex_);
// Determine how long to block while waiting for events.
timespec timeout_buf = { 0, 0 };
timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
lock.unlock();
// Block on the kqueue descriptor.
struct kevent events[128];
int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].ident;
void* ptr = reinterpret_cast<void*>(events[i].udata);
if (ptr == &interrupter_)
{
// No need to reset the interrupter since we're leaving the descriptor
// in a ready-to-read state and relying on one-shot notifications.
}
else
{
descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
#if defined(__NetBSD__)
static const unsigned int filter[max_ops] =
#else
static const int filter[max_ops] =
#endif
{ EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
for (int j = max_ops - 1; j >= 0; --j)
{
if (events[i].filter == filter[j])
{
if (j != except_op || events[i].flags & EV_OOBAND)
{
while (reactor_op* op = descriptor_data->op_queue_[j].front())
{
if (events[i].flags & EV_ERROR)
{
op->ec_ = asio::error_code(events[i].data,
asio::error::get_system_category());
descriptor_data->op_queue_[j].pop();
ops.push(op);
}
if (op->perform())
{
descriptor_data->op_queue_[j].pop();
ops.push(op);
}
else
break;
}
}
}
}
// Renew registration for event notifications.
struct kevent event;
switch (events[i].filter)
{
case EVFILT_READ:
if (!descriptor_data->op_queue_[read_op].empty())
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
else if (!descriptor_data->op_queue_[except_op].empty())
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
else
continue;
case EVFILT_WRITE:
if (!descriptor_data->op_queue_[write_op].empty())
ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
else
continue;
default:
break;
}
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno,
asio::error::get_system_category());
for (int j = 0; j < max_ops; ++j)
{
while (reactor_op* op = descriptor_data->op_queue_[j].front())
{
op->ec_ = error;
descriptor_data->op_queue_[j].pop();
ops.push(op);
}
}
}
}
}
lock.lock();
timer_queues_.get_ready_timers(ops);
}
void kqueue_reactor::interrupt()
{
struct kevent event;
ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(),
EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
}
int kqueue_reactor::do_kqueue_create()
{
int fd = ::kqueue();
if (fd == -1)
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::detail::throw_error(ec, "kqueue");
}
return fd;
}
void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
timespec* kqueue_reactor::get_timeout(timespec& ts)
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
ts.tv_sec = usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
return &ts;
}
} // namespace detail
} // namespace asio
#undef ASIO_KQUEUE_EV_SET
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_KQUEUE)
#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP

View File

@@ -0,0 +1,96 @@
//
// detail/impl/pipe_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS)
#if !defined(__CYGWIN__)
#if !defined(__SYMBIAN32__)
#if !defined(ASIO_HAS_EVENTFD)
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "asio/detail/pipe_select_interrupter.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
pipe_select_interrupter::pipe_select_interrupter()
{
int pipe_fds[2];
if (pipe(pipe_fds) == 0)
{
read_descriptor_ = pipe_fds[0];
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::detail::throw_error(ec, "pipe_select_interrupter");
}
}
pipe_select_interrupter::~pipe_select_interrupter()
{
if (read_descriptor_ != -1)
::close(read_descriptor_);
if (write_descriptor_ != -1)
::close(write_descriptor_);
}
void pipe_select_interrupter::interrupt()
{
char byte = 0;
int result = ::write(write_descriptor_, &byte, 1);
(void)result;
}
bool pipe_select_interrupter::reset()
{
for (;;)
{
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_HAS_EVENTFD)
#endif // !defined(__SYMBIAN32__)
#endif // !defined(__CYGWIN__)
#endif // !defined(BOOST_WINDOWS)
#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP

View File

@@ -0,0 +1,46 @@
//
// detail/impl/posix_event.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#include "asio/detail/posix_event.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
posix_event::posix_event()
: signalled_(false)
{
int error = ::pthread_cond_init(&cond_, 0);
asio::error_code ec(error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "event");
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP

View File

@@ -0,0 +1,46 @@
//
// detail/impl/posix_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#include "asio/detail/posix_mutex.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
posix_mutex::posix_mutex()
{
int error = ::pthread_mutex_init(&mutex_, 0);
asio::error_code ec(error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "mutex");
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP

View File

@@ -0,0 +1,74 @@
//
// detail/impl/posix_thread.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#include "asio/detail/posix_thread.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
posix_thread::~posix_thread()
{
if (!joined_)
::pthread_detach(thread_);
}
void posix_thread::join()
{
if (!joined_)
{
::pthread_join(thread_, 0);
joined_ = true;
}
}
void posix_thread::start_thread(func_base* arg)
{
int error = ::pthread_create(&thread_, 0,
asio_detail_posix_thread_function, arg);
if (error != 0)
{
delete arg;
asio::error_code ec(error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "thread");
}
}
void* asio_detail_posix_thread_function(void* arg)
{
posix_thread::auto_func_base_ptr func = {
static_cast<posix_thread::func_base*>(arg) };
func.ptr->run();
return 0;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP

View File

@@ -0,0 +1,46 @@
//
// detail/impl/posix_tss_ptr.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#include "asio/detail/posix_tss_ptr.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
void posix_tss_ptr_create(pthread_key_t& key)
{
int error = ::pthread_key_create(&key, 0);
asio::error_code ec(error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "tss");
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS)
#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP

View File

@@ -0,0 +1,136 @@
//
// detail/impl/reactive_descriptor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/error.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
reactive_descriptor_service::reactive_descriptor_service(
asio::io_service& io_service)
: reactor_(asio::use_service<reactor>(io_service))
{
reactor_.init_task();
}
void reactive_descriptor_service::shutdown_service()
{
}
void reactive_descriptor_service::construct(
reactive_descriptor_service::implementation_type& impl)
{
impl.descriptor_ = -1;
impl.state_ = 0;
}
void reactive_descriptor_service::destroy(
reactive_descriptor_service::implementation_type& impl)
{
if (is_open(impl))
reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
asio::error_code ignored_ec;
descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
}
asio::error_code reactive_descriptor_service::assign(
reactive_descriptor_service::implementation_type& impl,
const native_type& native_descriptor, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
if (int err = reactor_.register_descriptor(
native_descriptor, impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
impl.descriptor_ = native_descriptor;
impl.state_ = 0;
ec = asio::error_code();
return ec;
}
asio::error_code reactive_descriptor_service::close(
reactive_descriptor_service::implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0)
construct(impl);
return ec;
}
asio::error_code reactive_descriptor_service::cancel(
reactive_descriptor_service::implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
ec = asio::error_code();
return ec;
}
void reactive_descriptor_service::start_op(
reactive_descriptor_service::implementation_type& impl,
int op_type, reactor_op* op, bool non_blocking, bool noop)
{
if (!noop)
{
if ((impl.state_ & descriptor_ops::non_blocking) ||
descriptor_ops::set_internal_non_blocking(
impl.descriptor_, impl.state_, op->ec_))
{
reactor_.start_op(op_type, impl.descriptor_,
impl.reactor_data_, op, non_blocking);
return;
}
}
reactor_.post_immediate_completion(op);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP

View File

@@ -0,0 +1,151 @@
//
// detail/impl/reactive_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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)
//
#ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_SERIAL_PORT)
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include <cstring>
#include "asio/detail/reactive_serial_port_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
reactive_serial_port_service::reactive_serial_port_service(
asio::io_service& io_service)
: descriptor_service_(io_service)
{
}
void reactive_serial_port_service::shutdown_service()
{
descriptor_service_.shutdown_service();
}
asio::error_code reactive_serial_port_service::open(
reactive_serial_port_service::implementation_type& impl,
const std::string& device, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
descriptor_ops::state_type state = 0;
int fd = descriptor_ops::open(device.c_str(),
O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
if (fd < 0)
return ec;
int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
if (s >= 0)
s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
if (s < 0)
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
return ec;
}
// Set up default serial port options.
termios ios;
errno = 0;
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
if (s >= 0)
{
#if defined(_BSD_SOURCE)
::cfmakeraw(&ios);
#else
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
| ISTRIP | INLCR | IGNCR | ICRNL | IXON);
ios.c_oflag &= ~OPOST;
ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
ios.c_cflag &= ~(CSIZE | PARENB);
ios.c_cflag |= CS8;
#endif
ios.c_iflag |= IGNPAR;
ios.c_cflag |= CREAD | CLOCAL;
errno = 0;
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
}
if (s < 0)
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
return ec;
}
// We're done. Take ownership of the serial port descriptor.
if (descriptor_service_.assign(impl, fd, ec))
{
asio::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
}
return ec;
}
asio::error_code reactive_serial_port_service::do_set_option(
reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::store_function_type store,
const void* option, asio::error_code& ec)
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native(impl), &ios), ec);
if (ec)
return ec;
if (store(option, ios, ec))
return ec;
errno = 0;
descriptor_ops::error_wrapper(::tcsetattr(
descriptor_service_.native(impl), TCSANOW, &ios), ec);
return ec;
}
asio::error_code reactive_serial_port_service::do_get_option(
const reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::load_function_type load,
void* option, asio::error_code& ec) const
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native(impl), &ios), ec);
if (ec)
return ec;
return load(option, ios, ec);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#endif // defined(ASIO_HAS_SERIAL_PORT)
#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP

View File

@@ -0,0 +1,212 @@
//
// detail/reactive_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_HAS_IOCP)
#include "asio/detail/reactive_socket_service_base.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
reactive_socket_service_base::reactive_socket_service_base(
asio::io_service& io_service)
: reactor_(use_service<reactor>(io_service))
{
reactor_.init_task();
}
void reactive_socket_service_base::shutdown_service()
{
}
void reactive_socket_service_base::construct(
reactive_socket_service_base::base_implementation_type& impl)
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
}
void reactive_socket_service_base::destroy(
reactive_socket_service_base::base_implementation_type& impl)
{
if (impl.socket_ != invalid_socket)
{
reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
asio::error_code ignored_ec;
socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
}
}
asio::error_code reactive_socket_service_base::close(
reactive_socket_service_base::base_implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0)
construct(impl);
return ec;
}
asio::error_code reactive_socket_service_base::cancel(
reactive_socket_service_base::base_implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
ec = asio::error_code();
return ec;
}
asio::error_code reactive_socket_service_base::do_open(
reactive_socket_service_base::base_implementation_type& impl,
int af, int type, int protocol, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
socket_holder sock(socket_ops::socket(af, type, protocol, ec));
if (sock.get() == invalid_socket)
return ec;
if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
impl.socket_ = sock.release();
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
ec = asio::error_code();
return ec;
}
asio::error_code reactive_socket_service_base::do_assign(
reactive_socket_service_base::base_implementation_type& impl, int type,
const reactive_socket_service_base::native_type& native_socket,
asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
if (int err = reactor_.register_descriptor(
native_socket, impl.reactor_data_))
{
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
impl.socket_ = native_socket;
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
ec = asio::error_code();
return ec;
}
void reactive_socket_service_base::start_op(
reactive_socket_service_base::base_implementation_type& impl,
int op_type, reactor_op* op, bool non_blocking, bool noop)
{
if (!noop)
{
if ((impl.state_ & socket_ops::non_blocking)
|| socket_ops::set_internal_non_blocking(
impl.socket_, impl.state_, op->ec_))
{
reactor_.start_op(op_type, impl.socket_,
impl.reactor_data_, op, non_blocking);
return;
}
}
reactor_.post_immediate_completion(op);
}
void reactive_socket_service_base::start_accept_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, bool peer_is_open)
{
if (!peer_is_open)
start_op(impl, reactor::read_op, op, true, false);
else
{
op->ec_ = asio::error::already_open;
reactor_.post_immediate_completion(op);
}
}
void reactive_socket_service_base::start_connect_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, const socket_addr_type* addr, size_t addrlen)
{
if ((impl.state_ & socket_ops::non_blocking)
|| socket_ops::set_internal_non_blocking(
impl.socket_, impl.state_, op->ec_))
{
if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
{
if (op->ec_ == asio::error::in_progress
|| op->ec_ == asio::error::would_block)
{
op->ec_ = asio::error_code();
reactor_.start_op(reactor::connect_op,
impl.socket_, impl.reactor_data_, op, false);
return;
}
}
}
reactor_.post_immediate_completion(op);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP

View File

@@ -0,0 +1,106 @@
//
// detail/impl/resolver_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/resolver_service_base.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class resolver_service_base::work_io_service_runner
{
public:
work_io_service_runner(asio::io_service& io_service)
: io_service_(io_service) {}
void operator()() { io_service_.run(); }
private:
asio::io_service& io_service_;
};
resolver_service_base::resolver_service_base(
asio::io_service& io_service)
: io_service_impl_(asio::use_service<io_service_impl>(io_service)),
work_io_service_(new asio::io_service),
work_io_service_impl_(asio::use_service<
io_service_impl>(*work_io_service_)),
work_(new asio::io_service::work(*work_io_service_)),
work_thread_(0)
{
}
resolver_service_base::~resolver_service_base()
{
shutdown_service();
}
void resolver_service_base::shutdown_service()
{
work_.reset();
if (work_io_service_)
{
work_io_service_->stop();
if (work_thread_)
{
work_thread_->join();
work_thread_.reset();
}
work_io_service_.reset();
}
}
void resolver_service_base::construct(
resolver_service_base::implementation_type& impl)
{
impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
}
void resolver_service_base::destroy(
resolver_service_base::implementation_type&)
{
}
void resolver_service_base::cancel(
resolver_service_base::implementation_type& impl)
{
impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
}
void resolver_service_base::start_resolve_op(operation* op)
{
start_work_thread();
io_service_impl_.work_started();
work_io_service_impl_.post_immediate_completion(op);
}
void resolver_service_base::start_work_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!work_thread_)
{
work_thread_.reset(new asio::detail::thread(
work_io_service_runner(*work_io_service_)));
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP

View File

@@ -0,0 +1,84 @@
//
// detail/impl/select_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP) \
|| (!defined(ASIO_HAS_DEV_POLL) \
&& !defined(ASIO_HAS_EPOLL) \
&& !defined(ASIO_HAS_KQUEUE))
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
io_service_.post_immediate_completion(op);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
io_service_.work_started();
if (earliest)
interrupter_.interrupt();
}
template <typename Time_Traits>
std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer)
{
asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops);
lock.unlock();
io_service_.post_deferred_completions(ops);
return n;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
// || (!defined(ASIO_HAS_DEV_POLL)
// && !defined(ASIO_HAS_EPOLL)
// && !defined(ASIO_HAS_KQUEUE))
#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP

View File

@@ -0,0 +1,273 @@
//
// detail/impl/select_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP) \
|| (!defined(ASIO_HAS_DEV_POLL) \
&& !defined(ASIO_HAS_EPOLL) \
&& !defined(ASIO_HAS_KQUEUE))
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/fd_set_adapter.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
select_reactor::select_reactor(asio::io_service& io_service)
: asio::detail::service_base<select_reactor>(io_service),
io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
interrupter_(),
#if defined(ASIO_HAS_IOCP)
stop_thread_(false),
thread_(0),
#endif // defined(ASIO_HAS_IOCP)
shutdown_(false)
{
#if defined(ASIO_HAS_IOCP)
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&select_reactor::call_run_thread, this));
#endif // defined(ASIO_HAS_IOCP)
}
select_reactor::~select_reactor()
{
shutdown_service();
}
void select_reactor::shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
#if defined(ASIO_HAS_IOCP)
stop_thread_ = true;
#endif // defined(ASIO_HAS_IOCP)
lock.unlock();
#if defined(ASIO_HAS_IOCP)
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
#endif // defined(ASIO_HAS_IOCP)
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
op_queue_[i].get_all_operations(ops);
timer_queues_.get_all_timers(ops);
}
void select_reactor::init_task()
{
io_service_.init_task();
}
int select_reactor::register_descriptor(socket_type,
select_reactor::per_descriptor_data&)
{
return 0;
}
void select_reactor::start_op(int op_type, socket_type descriptor,
select_reactor::per_descriptor_data&, reactor_op* op, bool)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op);
return;
}
bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
io_service_.work_started();
if (first)
interrupter_.interrupt();
}
void select_reactor::cancel_ops(socket_type descriptor,
select_reactor::per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
void select_reactor::close_descriptor(socket_type descriptor,
select_reactor::per_descriptor_data&)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
}
void select_reactor::run(bool block, op_queue<operation>& ops)
{
asio::detail::mutex::scoped_lock lock(mutex_);
#if defined(ASIO_HAS_IOCP)
// Check if the thread is supposed to stop.
if (stop_thread_)
return;
#endif // defined(ASIO_HAS_IOCP)
// Set up the descriptor sets.
fd_set_adapter fds[max_select_ops];
fds[read_op].set(interrupter_.read_descriptor());
socket_type max_fd = 0;
bool have_work_to_do = !timer_queues_.all_empty();
for (int i = 0; i < max_select_ops; ++i)
{
have_work_to_do = have_work_to_do || !op_queue_[i].empty();
op_queue_[i].get_descriptors(fds[i], ops);
if (fds[i].max_descriptor() > max_fd)
max_fd = fds[i].max_descriptor();
}
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Connection operations on Windows use both except and write fd_sets.
have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
op_queue_[connect_op].get_descriptors(fds[write_op], ops);
if (fds[write_op].max_descriptor() > max_fd)
max_fd = fds[write_op].max_descriptor();
op_queue_[connect_op].get_descriptors(fds[except_op], ops);
if (fds[except_op].max_descriptor() > max_fd)
max_fd = fds[except_op].max_descriptor();
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && !have_work_to_do)
return;
// Determine how long to block while waiting for events.
timeval tv_buf = { 0, 0 };
timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
lock.unlock();
// Block on the select call until descriptors become ready.
asio::error_code ec;
int retval = socket_ops::select(static_cast<int>(max_fd + 1),
fds[read_op], fds[write_op], fds[except_op], tv, ec);
// Reset the interrupter.
if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
interrupter_.reset();
lock.lock();
// Dispatch all ready operations.
if (retval > 0)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Connection operations on Windows use both except and write fd_sets.
op_queue_[connect_op].perform_operations_for_descriptors(
fds[except_op], ops);
op_queue_[connect_op].perform_operations_for_descriptors(
fds[write_op], ops);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
for (int i = max_select_ops - 1; i >= 0; --i)
op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
}
timer_queues_.get_ready_timers(ops);
}
void select_reactor::interrupt()
{
interrupter_.interrupt();
}
#if defined(ASIO_HAS_IOCP)
void select_reactor::run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
op_queue<operation> ops;
run(true, ops);
io_service_.post_deferred_completions(ops);
lock.lock();
}
}
void select_reactor::call_run_thread(select_reactor* reactor)
{
reactor->run_thread();
}
#endif // defined(ASIO_HAS_IOCP)
void select_reactor::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
timeval* select_reactor::get_timeout(timeval& tv)
{
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
return &tv;
}
void select_reactor::cancel_ops_unlocked(socket_type descriptor,
const asio::error_code& ec)
{
bool need_interrupt = false;
op_queue<operation> ops;
for (int i = 0; i < max_ops; ++i)
need_interrupt = op_queue_[i].cancel_operations(
descriptor, ops, ec) || need_interrupt;
io_service_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
// || (!defined(ASIO_HAS_DEV_POLL)
// && !defined(ASIO_HAS_EPOLL)
// && !defined(ASIO_HAS_KQUEUE))
#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP

View File

@@ -0,0 +1,70 @@
//
// detail/impl/service_registry.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Service>
Service& service_registry::use_service()
{
asio::io_service::service::key key;
init_key(key, Service::id);
factory_type factory = &service_registry::create<Service>;
return *static_cast<Service*>(do_use_service(key, factory));
}
template <typename Service>
void service_registry::add_service(Service* new_service)
{
asio::io_service::service::key key;
init_key(key, Service::id);
return do_add_service(key, new_service);
}
template <typename Service>
bool service_registry::has_service() const
{
asio::io_service::service::key key;
init_key(key, Service::id);
return do_has_service(key);
}
#if !defined(ASIO_NO_TYPEID)
template <typename Service>
void service_registry::init_key(asio::io_service::service::key& key,
const asio::detail::service_id<Service>& /*id*/)
{
key.type_info_ = &typeid(typeid_wrapper<Service>);
key.id_ = 0;
}
#endif // !defined(ASIO_NO_TYPEID)
template <typename Service>
asio::io_service::service* service_registry::create(
asio::io_service& owner)
{
return new Service(owner);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP

View File

@@ -0,0 +1,164 @@
//
// detail/impl/service_registry.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/service_registry.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
service_registry::service_registry(asio::io_service& o)
: owner_(o),
first_service_(0)
{
}
service_registry::~service_registry()
{
// Shutdown all services. This must be done in a separate loop before the
// services are destroyed since the destructors of user-defined handler
// objects may try to access other service objects.
asio::io_service::service* service = first_service_;
while (service)
{
service->shutdown_service();
service = service->next_;
}
// Destroy all services.
while (first_service_)
{
asio::io_service::service* next_service = first_service_->next_;
destroy(first_service_);
first_service_ = next_service;
}
}
void service_registry::init_key(asio::io_service::service::key& key,
const asio::io_service::id& id)
{
key.type_info_ = 0;
key.id_ = &id;
}
bool service_registry::keys_match(
const asio::io_service::service::key& key1,
const asio::io_service::service::key& key2)
{
if (key1.id_ && key2.id_)
if (key1.id_ == key2.id_)
return true;
if (key1.type_info_ && key2.type_info_)
if (*key1.type_info_ == *key2.type_info_)
return true;
return false;
}
void service_registry::destroy(asio::io_service::service* service)
{
delete service;
}
asio::io_service::service* service_registry::do_use_service(
const asio::io_service::service::key& key,
factory_type factory)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// First see if there is an existing service object with the given key.
asio::io_service::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
return service;
service = service->next_;
}
// Create a new service object. The service registry's mutex is not locked
// at this time to allow for nested calls into this function from the new
// service's constructor.
lock.unlock();
auto_service_ptr new_service = { factory(owner_) };
new_service.ptr_->key_ = key;
lock.lock();
// Check that nobody else created another service object of the same type
// while the lock was released.
service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
return service;
service = service->next_;
}
// Service was successfully initialised, pass ownership to registry.
new_service.ptr_->next_ = first_service_;
first_service_ = new_service.ptr_;
new_service.ptr_ = 0;
return first_service_;
}
void service_registry::do_add_service(
const asio::io_service::service::key& key,
asio::io_service::service* new_service)
{
if (&owner_ != &new_service->io_service())
boost::throw_exception(invalid_service_owner());
asio::detail::mutex::scoped_lock lock(mutex_);
// Check if there is an existing service object with the given key.
asio::io_service::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
boost::throw_exception(service_already_exists());
service = service->next_;
}
// Take ownership of the service object.
new_service->key_ = key;
new_service->next_ = first_service_;
first_service_ = new_service;
}
bool service_registry::do_has_service(
const asio::io_service::service::key& key) const
{
asio::detail::mutex::scoped_lock lock(mutex_);
asio::io_service::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
return true;
service = service->next_;
}
return false;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
//
// detail/impl/socket_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) \
|| defined(__CYGWIN__) \
|| defined(__SYMBIAN32__)
#include <cstdlib>
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_select_interrupter.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
socket_select_interrupter::socket_select_interrupter()
{
asio::error_code ec;
socket_holder acceptor(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (acceptor.get() == invalid_socket)
asio::detail::throw_error(ec, "socket_select_interrupter");
int opt = 1;
socket_ops::state_type acceptor_state = 0;
socket_ops::setsockopt(acceptor.get(), acceptor_state,
SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
using namespace std; // For memset.
sockaddr_in4_type addr;
std::size_t addr_len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 0;
if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
&addr_len, ec) == socket_error_retval)
asio::detail::throw_error(ec, "socket_select_interrupter");
// Some broken firewalls on Windows will intermittently cause getsockname to
// return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
// explicitly specify the target address here to work around this problem.
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (socket_ops::listen(acceptor.get(),
SOMAXCONN, ec) == socket_error_retval)
asio::detail::throw_error(ec, "socket_select_interrupter");
socket_holder client(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (client.get() == invalid_socket)
asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
asio::detail::throw_error(ec, "socket_select_interrupter");
socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
if (server.get() == invalid_socket)
asio::detail::throw_error(ec, "socket_select_interrupter");
ioctl_arg_type non_blocking = 1;
socket_ops::state_type client_state = 0;
if (socket_ops::ioctl(client.get(), client_state,
FIONBIO, &non_blocking, ec))
asio::detail::throw_error(ec, "socket_select_interrupter");
opt = 1;
socket_ops::setsockopt(client.get(), client_state,
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
non_blocking = 1;
socket_ops::state_type server_state = 0;
if (socket_ops::ioctl(server.get(), server_state,
FIONBIO, &non_blocking, ec))
asio::detail::throw_error(ec, "socket_select_interrupter");
opt = 1;
socket_ops::setsockopt(server.get(), server_state,
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
read_descriptor_ = server.release();
write_descriptor_ = client.release();
}
socket_select_interrupter::~socket_select_interrupter()
{
asio::error_code ec;
socket_ops::state_type state = socket_ops::internal_non_blocking;
if (read_descriptor_ != invalid_socket)
socket_ops::close(read_descriptor_, state, true, ec);
if (write_descriptor_ != invalid_socket)
socket_ops::close(write_descriptor_, state, true, ec);
}
void socket_select_interrupter::interrupt()
{
char byte = 0;
socket_ops::buf b;
socket_ops::init_buf(b, &byte, 1);
asio::error_code ec;
socket_ops::send(write_descriptor_, &b, 1, 0, ec);
}
bool socket_select_interrupter::reset()
{
char data[1024];
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
asio::error_code ec;
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
return was_interrupted;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS)
// || defined(__CYGWIN__)
// || defined(__SYMBIAN32__)
#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP

View File

@@ -0,0 +1,140 @@
//
// detail/impl/strand_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/call_stack.hpp"
#include "asio/detail/completion_handler.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
inline strand_service::strand_impl::strand_impl()
: operation(&strand_service::do_complete),
count_(0)
{
}
struct strand_service::on_dispatch_exit
{
io_service_impl* io_service_;
strand_impl* impl_;
~on_dispatch_exit()
{
impl_->mutex_.lock();
bool more_handlers = (--impl_->count_ > 0);
impl_->mutex_.unlock();
if (more_handlers)
io_service_->post_immediate_completion(impl_);
}
};
inline void strand_service::destroy(strand_service::implementation_type& impl)
{
impl = 0;
}
template <typename Handler>
void strand_service::dispatch(strand_service::implementation_type& impl,
Handler handler)
{
// If we are already in the strand then the handler can run immediately.
if (call_stack<strand_impl>::contains(impl))
{
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
return;
}
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::addressof(handler),
asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(handler);
// If we are running inside the io_service, and no other handler is queued
// or running, then the handler can run immediately.
bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
impl->mutex_.lock();
bool first = (++impl->count_ == 1);
if (can_dispatch && first)
{
// Immediate invocation is allowed.
impl->mutex_.unlock();
// Memory must be releaesed before any upcall is made.
p.reset();
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_dispatch_exit on_exit = { &io_service_, impl };
(void)on_exit;
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
return;
}
// Immediate invocation is not allowed, so enqueue for later.
impl->queue_.push(p.p);
impl->mutex_.unlock();
p.v = p.p = 0;
// The first handler to be enqueued is responsible for scheduling the
// strand.
if (first)
io_service_.post_immediate_completion(impl);
}
// Request the io_service to invoke the given handler and return immediately.
template <typename Handler>
void strand_service::post(strand_service::implementation_type& impl,
Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::addressof(handler),
asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(handler);
// Add the handler to the queue.
impl->mutex_.lock();
bool first = (++impl->count_ == 1);
impl->queue_.push(p.p);
impl->mutex_.unlock();
p.v = p.p = 0;
// The first handler to be enqueue is responsible for scheduling the strand.
if (first)
io_service_.post_immediate_completion(impl);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP

View File

@@ -0,0 +1,106 @@
//
// detail/impl/strand_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/strand_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
struct strand_service::on_do_complete_exit
{
io_service_impl* owner_;
strand_impl* impl_;
~on_do_complete_exit()
{
impl_->mutex_.lock();
bool more_handlers = (--impl_->count_ > 0);
impl_->mutex_.unlock();
if (more_handlers)
owner_->post_immediate_completion(impl_);
}
};
strand_service::strand_service(asio::io_service& io_service)
: asio::detail::service_base<strand_service>(io_service),
io_service_(asio::use_service<io_service_impl>(io_service)),
mutex_(),
salt_(0)
{
}
void strand_service::shutdown_service()
{
op_queue<operation> ops;
asio::detail::mutex::scoped_lock lock(mutex_);
for (std::size_t i = 0; i < num_implementations; ++i)
if (strand_impl* impl = implementations_[i].get())
ops.push(impl->queue_);
}
void strand_service::construct(strand_service::implementation_type& impl)
{
std::size_t salt = salt_++;
std::size_t index = reinterpret_cast<std::size_t>(&impl);
index += (reinterpret_cast<std::size_t>(&impl) >> 3);
index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
index = index % num_implementations;
asio::detail::mutex::scoped_lock lock(mutex_);
if (!implementations_[index])
implementations_[index].reset(new strand_impl);
impl = implementations_[index].get();
}
void strand_service::do_complete(io_service_impl* owner, operation* base,
asio::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
if (owner)
{
strand_impl* impl = static_cast<strand_impl*>(base);
// Get the next handler to be executed.
impl->mutex_.lock();
operation* o = impl->queue_.front();
impl->queue_.pop();
impl->mutex_.unlock();
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_do_complete_exit on_exit = { owner, impl };
(void)on_exit;
o->complete(*owner);
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP

View File

@@ -0,0 +1,60 @@
//
// detail/impl/task_io_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/call_stack.hpp"
#include "asio/detail/completion_handler.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Handler>
void task_io_service::dispatch(Handler handler)
{
if (call_stack<task_io_service>::contains(this))
{
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
}
else
post(handler);
}
template <typename Handler>
void task_io_service::post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::addressof(handler),
asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(handler);
post_immediate_completion(p.p);
p.v = p.p = 0;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP

View File

@@ -0,0 +1,354 @@
//
// detail/impl/task_io_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
#define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_HAS_IOCP)
#include <boost/limits.hpp>
#include "asio/detail/call_stack.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/reactor.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
struct task_io_service::task_cleanup
{
~task_cleanup()
{
// Enqueue the completed operations and reinsert the task at the end of
// the operation queue.
lock_->lock();
task_io_service_->task_interrupted_ = true;
task_io_service_->op_queue_.push(*ops_);
task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
}
task_io_service* task_io_service_;
mutex::scoped_lock* lock_;
op_queue<operation>* ops_;
};
struct task_io_service::work_finished_on_block_exit
{
~work_finished_on_block_exit()
{
task_io_service_->work_finished();
}
task_io_service* task_io_service_;
};
struct task_io_service::idle_thread_info
{
event wakeup_event;
idle_thread_info* next;
};
task_io_service::task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service>(io_service),
mutex_(),
task_(0),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
}
void task_io_service::init(std::size_t /*concurrency_hint*/)
{
}
void task_io_service::shutdown_service()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
// Destroy handler objects.
while (!op_queue_.empty())
{
operation* o = op_queue_.front();
op_queue_.pop();
if (o != &task_operation_)
o->destroy();
}
// Reset to initial state.
task_ = 0;
}
void task_io_service::init_task()
{
mutex::scoped_lock lock(mutex_);
if (!shutdown_ && !task_)
{
task_ = &use_service<reactor>(this->get_io_service());
op_queue_.push(&task_operation_);
wake_one_thread_and_unlock(lock);
}
}
std::size_t task_io_service::run(asio::error_code& ec)
{
ec = asio::error_code();
if (outstanding_work_ == 0)
{
stop();
return 0;
}
call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
mutex::scoped_lock lock(mutex_);
std::size_t n = 0;
for (; do_one(lock, &this_idle_thread); lock.lock())
if (n != (std::numeric_limits<std::size_t>::max)())
++n;
return n;
}
std::size_t task_io_service::run_one(asio::error_code& ec)
{
ec = asio::error_code();
if (outstanding_work_ == 0)
{
stop();
return 0;
}
call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.next = 0;
mutex::scoped_lock lock(mutex_);
return do_one(lock, &this_idle_thread);
}
std::size_t task_io_service::poll(asio::error_code& ec)
{
if (outstanding_work_ == 0)
{
stop();
ec = asio::error_code();
return 0;
}
call_stack<task_io_service>::context ctx(this);
mutex::scoped_lock lock(mutex_);
std::size_t n = 0;
for (; do_one(lock, 0); lock.lock())
if (n != (std::numeric_limits<std::size_t>::max)())
++n;
return n;
}
std::size_t task_io_service::poll_one(asio::error_code& ec)
{
ec = asio::error_code();
if (outstanding_work_ == 0)
{
stop();
return 0;
}
call_stack<task_io_service>::context ctx(this);
mutex::scoped_lock lock(mutex_);
return do_one(lock, 0);
}
void task_io_service::stop()
{
mutex::scoped_lock lock(mutex_);
stop_all_threads(lock);
}
void task_io_service::reset()
{
mutex::scoped_lock lock(mutex_);
stopped_ = false;
}
void task_io_service::post_immediate_completion(task_io_service::operation* op)
{
work_started();
post_deferred_completion(op);
}
void task_io_service::post_deferred_completion(task_io_service::operation* op)
{
mutex::scoped_lock lock(mutex_);
op_queue_.push(op);
wake_one_thread_and_unlock(lock);
}
void task_io_service::post_deferred_completions(
op_queue<task_io_service::operation>& ops)
{
if (!ops.empty())
{
mutex::scoped_lock lock(mutex_);
op_queue_.push(ops);
wake_one_thread_and_unlock(lock);
}
}
std::size_t task_io_service::do_one(mutex::scoped_lock& lock,
task_io_service::idle_thread_info* this_idle_thread)
{
bool polling = !this_idle_thread;
bool task_has_run = false;
while (!stopped_)
{
if (!op_queue_.empty())
{
// Prepare to execute first handler from queue.
operation* o = op_queue_.front();
op_queue_.pop();
bool more_handlers = (!op_queue_.empty());
if (o == &task_operation_)
{
task_interrupted_ = more_handlers || polling;
// If the task has already run and we're polling then we're done.
if (task_has_run && polling)
{
task_interrupted_ = true;
op_queue_.push(&task_operation_);
return 0;
}
task_has_run = true;
if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
lock.unlock();
op_queue<operation> completed_ops;
task_cleanup c = { this, &lock, &completed_ops };
(void)c;
// Run the task. May throw an exception. Only block if the operation
// queue is empty and we're not polling, otherwise we want to return
// as soon as possible.
task_->run(!more_handlers && !polling, completed_ops);
}
else
{
if (more_handlers)
wake_one_thread_and_unlock(lock);
else
lock.unlock();
// Ensure the count of outstanding work is decremented on block exit.
work_finished_on_block_exit on_exit = { this };
(void)on_exit;
// Complete the operation. May throw an exception.
o->complete(*this); // deletes the operation object
return 1;
}
}
else if (this_idle_thread)
{
// Nothing to run right now, so just wait for work to do.
this_idle_thread->next = first_idle_thread_;
first_idle_thread_ = this_idle_thread;
this_idle_thread->wakeup_event.clear(lock);
this_idle_thread->wakeup_event.wait(lock);
}
else
{
return 0;
}
}
return 0;
}
void task_io_service::stop_all_threads(
mutex::scoped_lock& lock)
{
stopped_ = true;
while (first_idle_thread_)
{
idle_thread_info* idle_thread = first_idle_thread_;
first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal(lock);
}
if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
task_->interrupt();
}
}
bool task_io_service::wake_one_idle_thread_and_unlock(
mutex::scoped_lock& lock)
{
if (first_idle_thread_)
{
idle_thread_info* idle_thread = first_idle_thread_;
first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
idle_thread->wakeup_event.signal_and_unlock(lock);
return true;
}
return false;
}
void task_io_service::wake_one_thread_and_unlock(
mutex::scoped_lock& lock)
{
if (!wake_one_idle_thread_and_unlock(lock))
{
if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
task_->interrupt();
}
lock.unlock();
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP

View File

@@ -0,0 +1,47 @@
//
// detail/impl/throw_error.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP
#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/throw_error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
ASIO_DECL
void do_throw_error(const asio::error_code& err)
{
asio::system_error e(err);
boost::throw_exception(e);
}
ASIO_DECL
void do_throw_error(const asio::error_code& err, const char* location)
{
asio::system_error e(err, location);
boost::throw_exception(e);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP

View File

@@ -0,0 +1,85 @@
//
// detail/impl/timer_queue.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
#define ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_HEADER_ONLY)
#include "asio/detail/timer_queue.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()
{
}
timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()
{
}
bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(
const time_type& time, per_timer_data& timer, timer_op* op)
{
return impl_.enqueue_timer(time, timer, op);
}
bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const
{
return impl_.empty();
}
long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(
long max_duration) const
{
return impl_.wait_duration_msec(max_duration);
}
long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(
long max_duration) const
{
return impl_.wait_duration_usec(max_duration);
}
void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(
op_queue<operation>& ops)
{
impl_.get_ready_timers(ops);
}
void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(
op_queue<operation>& ops)
{
impl_.get_all_timers(ops);
}
std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
per_timer_data& timer, op_queue<operation>& ops)
{
return impl_.cancel_timer(timer, ops);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_HEADER_ONLY)
#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP

View File

@@ -0,0 +1,101 @@
//
// detail/impl/timer_queue_set.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/timer_queue_set.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
timer_queue_set::timer_queue_set()
: first_(0)
{
}
void timer_queue_set::insert(timer_queue_base* q)
{
q->next_ = first_;
first_ = q;
}
void timer_queue_set::erase(timer_queue_base* q)
{
if (first_)
{
if (q == first_)
{
first_ = q->next_;
q->next_ = 0;
return;
}
for (timer_queue_base* p = first_; p->next_; p = p->next_)
{
if (p->next_ == q)
{
p->next_ = q->next_;
q->next_ = 0;
return;
}
}
}
}
bool timer_queue_set::all_empty() const
{
for (timer_queue_base* p = first_; p; p = p->next_)
if (!p->empty())
return false;
return true;
}
long timer_queue_set::wait_duration_msec(long max_duration) const
{
long min_duration = max_duration;
for (timer_queue_base* p = first_; p; p = p->next_)
min_duration = p->wait_duration_msec(min_duration);
return min_duration;
}
long timer_queue_set::wait_duration_usec(long max_duration) const
{
long min_duration = max_duration;
for (timer_queue_base* p = first_; p; p = p->next_)
min_duration = p->wait_duration_usec(min_duration);
return min_duration;
}
void timer_queue_set::get_ready_timers(op_queue<operation>& ops)
{
for (timer_queue_base* p = first_; p; p = p->next_)
p->get_ready_timers(ops);
}
void timer_queue_set::get_all_timers(op_queue<operation>& ops)
{
for (timer_queue_base* p = first_; p; p = p->next_)
p->get_all_timers(ops);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP

View File

@@ -0,0 +1,50 @@
//
// detail/win_event.ipp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP
#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_event.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
win_event::win_event()
: event_(::CreateEvent(0, true, false, 0))
{
if (!event_)
{
DWORD last_error = ::GetLastError();
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "event");
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS)
#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP

View File

@@ -0,0 +1,452 @@
//
// detail/impl/win_iocp_handle_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/detail/win_iocp_handle_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class win_iocp_handle_service::overlapped_wrapper
: public OVERLAPPED
{
public:
explicit overlapped_wrapper(asio::error_code& ec)
{
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
// Create a non-signalled manual-reset event, for GetOverlappedResult.
hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
if (hEvent)
{
// As documented in GetQueuedCompletionStatus, setting the low order
// bit of this event prevents our synchronous writes from being treated
// as completion port events.
*reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
}
else
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
~overlapped_wrapper()
{
if (hEvent)
{
::CloseHandle(hEvent);
}
}
};
win_iocp_handle_service::win_iocp_handle_service(
asio::io_service& io_service)
: iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
mutex_(),
impl_list_(0)
{
}
void win_iocp_handle_service::shutdown_service()
{
// Close all implementations, causing all operations to complete.
asio::detail::mutex::scoped_lock lock(mutex_);
implementation_type* impl = impl_list_;
while (impl)
{
close_for_destruction(*impl);
impl = impl->next_;
}
}
void win_iocp_handle_service::construct(
win_iocp_handle_service::implementation_type& impl)
{
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
// Insert implementation into linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
impl.next_ = impl_list_;
impl.prev_ = 0;
if (impl_list_)
impl_list_->prev_ = &impl;
impl_list_ = &impl;
}
void win_iocp_handle_service::destroy(
win_iocp_handle_service::implementation_type& impl)
{
close_for_destruction(impl);
// Remove implementation from linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
if (impl_list_ == &impl)
impl_list_ = impl.next_;
if (impl.prev_)
impl.prev_->next_ = impl.next_;
if (impl.next_)
impl.next_->prev_= impl.prev_;
impl.next_ = 0;
impl.prev_ = 0;
}
asio::error_code win_iocp_handle_service::assign(
win_iocp_handle_service::implementation_type& impl,
const native_type& native_handle, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
if (iocp_service_.register_handle(native_handle, ec))
return ec;
impl.handle_ = native_handle;
ec = asio::error_code();
return ec;
}
asio::error_code win_iocp_handle_service::close(
win_iocp_handle_service::implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
{
if (!::CloseHandle(impl.handle_))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
}
ec = asio::error_code();
return ec;
}
asio::error_code win_iocp_handle_service::cancel(
win_iocp_handle_service::implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
}
else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
if (!cancel_io_ex(impl.handle_, 0))
{
DWORD last_error = ::GetLastError();
if (last_error == ERROR_NOT_FOUND)
{
// ERROR_NOT_FOUND means that there were no operations to be
// cancelled. We swallow this error to match the behaviour on other
// platforms.
ec = asio::error_code();
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
else
{
ec = asio::error_code();
}
}
else if (impl.safe_cancellation_thread_id_ == 0)
{
// No operations have been started, so there's nothing to cancel.
ec = asio::error_code();
}
else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
{
// Asynchronous operations have been started from the current thread only,
// so it is safe to try to cancel them using CancelIo.
if (!::CancelIo(impl.handle_))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
else
{
ec = asio::error_code();
}
}
else
{
// Asynchronous operations have been started from more than one thread,
// so cancellation is not safe.
ec = asio::error::operation_not_supported;
}
return ec;
}
size_t win_iocp_handle_service::do_write(
win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
const asio::const_buffer& buffer, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
ec = asio::error_code();
return 0;
}
overlapped_wrapper overlapped(ec);
if (ec)
{
return 0;
}
// Write the data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::WriteFile(impl.handle_,
asio::buffer_cast<LPCVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error != ERROR_IO_PENDING)
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
}
// Wait for the operation to complete.
DWORD bytes_transferred = 0;
ok = ::GetOverlappedResult(impl.handle_,
&overlapped, &bytes_transferred, TRUE);
if (!ok)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
ec = asio::error_code();
return bytes_transferred;
}
void win_iocp_handle_service::start_write_op(
win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
const asio::const_buffer& buffer, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (!is_open(impl))
{
iocp_service_.on_completion(op, asio::error::bad_descriptor);
}
else if (asio::buffer_size(buffer) == 0)
{
// A request to write 0 bytes on a handle is a no-op.
iocp_service_.on_completion(op);
}
else
{
DWORD bytes_transferred = 0;
op->Offset = offset & 0xFFFFFFFF;
op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::WriteFile(impl.handle_,
asio::buffer_cast<LPCVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)),
&bytes_transferred, op);
DWORD last_error = ::GetLastError();
if (!ok && last_error != ERROR_IO_PENDING
&& last_error != ERROR_MORE_DATA)
{
iocp_service_.on_completion(op, last_error, bytes_transferred);
}
else
{
iocp_service_.on_pending(op);
}
}
}
size_t win_iocp_handle_service::do_read(
win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
const asio::mutable_buffer& buffer, asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream handle is a no-op.
if (asio::buffer_size(buffer) == 0)
{
ec = asio::error_code();
return 0;
}
overlapped_wrapper overlapped(ec);
if (ec)
{
return 0;
}
// Read some data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_,
asio::buffer_cast<LPVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
{
if (last_error == ERROR_HANDLE_EOF)
{
ec = asio::error::eof;
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
return 0;
}
}
// Wait for the operation to complete.
DWORD bytes_transferred = 0;
ok = ::GetOverlappedResult(impl.handle_,
&overlapped, &bytes_transferred, TRUE);
if (!ok)
{
DWORD last_error = ::GetLastError();
if (last_error == ERROR_HANDLE_EOF)
{
ec = asio::error::eof;
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
return 0;
}
ec = asio::error_code();
return bytes_transferred;
}
void win_iocp_handle_service::start_read_op(
win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset,
const asio::mutable_buffer& buffer, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (!is_open(impl))
{
iocp_service_.on_completion(op, asio::error::bad_descriptor);
}
else if (asio::buffer_size(buffer) == 0)
{
// A request to read 0 bytes on a handle is a no-op.
iocp_service_.on_completion(op);
}
else
{
DWORD bytes_transferred = 0;
op->Offset = offset & 0xFFFFFFFF;
op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_,
asio::buffer_cast<LPVOID>(buffer),
static_cast<DWORD>(asio::buffer_size(buffer)),
&bytes_transferred, op);
DWORD last_error = ::GetLastError();
if (!ok && last_error != ERROR_IO_PENDING
&& last_error != ERROR_MORE_DATA)
{
iocp_service_.on_completion(op, last_error, bytes_transferred);
}
else
{
iocp_service_.on_pending(op);
}
}
}
void win_iocp_handle_service::update_cancellation_thread_id(
win_iocp_handle_service::implementation_type& impl)
{
if (impl.safe_cancellation_thread_id_ == 0)
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
impl.safe_cancellation_thread_id_ = ~DWORD(0);
}
void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
{
if (is_open(impl))
{
::CloseHandle(impl.handle_);
impl.handle_ = INVALID_HANDLE_VALUE;
impl.safe_cancellation_thread_id_ = 0;
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP

View File

@@ -0,0 +1,115 @@
//
// detail/impl/win_iocp_io_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/detail/call_stack.hpp"
#include "asio/detail/completion_handler.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Handler>
void win_iocp_io_service::dispatch(Handler handler)
{
if (call_stack<win_iocp_io_service>::contains(this))
{
asio::detail::fenced_block b;
asio_handler_invoke_helpers::invoke(handler, handler);
}
else
post(handler);
}
template <typename Handler>
void win_iocp_io_service::post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::addressof(handler),
asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(handler);
post_immediate_completion(p.p);
p.v = p.p = 0;
}
template <typename Time_Traits>
void win_iocp_io_service::add_timer_queue(
timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
template <typename Time_Traits>
void win_iocp_io_service::remove_timer_queue(
timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, timer_op* op)
{
// If the service has been shut down we silently discard the timer.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
{
post_immediate_completion(op);
return;
}
mutex::scoped_lock lock(dispatch_mutex_);
bool earliest = queue.enqueue_timer(time, timer, op);
work_started();
if (earliest)
update_timeout();
}
template <typename Time_Traits>
std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer)
{
// If the service has been shut down we silently ignore the cancellation.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return 0;
mutex::scoped_lock lock(dispatch_mutex_);
op_queue<win_iocp_operation> ops;
std::size_t n = queue.cancel_timer(timer, ops);
post_deferred_completions(ops);
return n;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP

View File

@@ -0,0 +1,496 @@
//
// detail/impl/win_iocp_io_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
#include <boost/limits.hpp>
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
struct win_iocp_io_service::work_finished_on_block_exit
{
~work_finished_on_block_exit()
{
io_service_->work_finished();
}
win_iocp_io_service* io_service_;
};
struct win_iocp_io_service::timer_thread_function
{
void operator()()
{
while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0)
{
if (::WaitForSingleObject(io_service_->waitable_timer_.handle,
INFINITE) == WAIT_OBJECT_0)
{
::InterlockedExchange(&io_service_->dispatch_required_, 1);
::PostQueuedCompletionStatus(io_service_->iocp_.handle,
0, wake_for_dispatch, 0);
}
}
}
win_iocp_io_service* io_service_;
};
win_iocp_io_service::win_iocp_io_service(asio::io_service& io_service)
: asio::detail::service_base<win_iocp_io_service>(io_service),
iocp_(),
outstanding_work_(0),
stopped_(0),
shutdown_(0),
dispatch_required_(0)
{
}
void win_iocp_io_service::init(size_t concurrency_hint)
{
iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
if (!iocp_.handle)
{
DWORD last_error = ::GetLastError();
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "iocp");
}
}
void win_iocp_io_service::shutdown_service()
{
::InterlockedExchange(&shutdown_, 1);
if (timer_thread_)
{
LARGE_INTEGER timeout;
timeout.QuadPart = 1;
::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
}
while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
{
op_queue<win_iocp_operation> ops;
timer_queues_.get_all_timers(ops);
ops.push(completed_ops_);
if (!ops.empty())
{
while (win_iocp_operation* op = ops.front())
{
ops.pop();
::InterlockedDecrement(&outstanding_work_);
op->destroy();
}
}
else
{
DWORD bytes_transferred = 0;
dword_ptr_t completion_key = 0;
LPOVERLAPPED overlapped = 0;
::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
&completion_key, &overlapped, gqcs_timeout);
if (overlapped)
{
::InterlockedDecrement(&outstanding_work_);
static_cast<win_iocp_operation*>(overlapped)->destroy();
}
}
}
if (timer_thread_)
timer_thread_->join();
}
asio::error_code win_iocp_io_service::register_handle(
HANDLE handle, asio::error_code& ec)
{
if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
else
{
ec = asio::error_code();
}
return ec;
}
size_t win_iocp_io_service::run(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
stop();
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
size_t n = 0;
while (do_one(true, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
size_t win_iocp_io_service::run_one(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
stop();
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
return do_one(true, ec);
}
size_t win_iocp_io_service::poll(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
stop();
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
size_t n = 0;
while (do_one(false, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
size_t win_iocp_io_service::poll_one(asio::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
stop();
ec = asio::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
return do_one(false, ec);
}
void win_iocp_io_service::stop()
{
if (::InterlockedExchange(&stopped_, 1) == 0)
{
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
DWORD last_error = ::GetLastError();
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "pqcs");
}
}
}
void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op)
{
// Flag the operation as ready.
op->ready_ = 1;
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
0, overlapped_contains_result, op))
{
// Out of resources. Put on completed queue instead.
mutex::scoped_lock lock(dispatch_mutex_);
completed_ops_.push(op);
::InterlockedExchange(&dispatch_required_, 1);
}
}
void win_iocp_io_service::post_deferred_completions(
op_queue<win_iocp_operation>& ops)
{
while (win_iocp_operation* op = ops.front())
{
ops.pop();
// Flag the operation as ready.
op->ready_ = 1;
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
0, overlapped_contains_result, op))
{
// Out of resources. Put on completed queue instead.
mutex::scoped_lock lock(dispatch_mutex_);
completed_ops_.push(op);
completed_ops_.push(ops);
::InterlockedExchange(&dispatch_required_, 1);
}
}
}
void win_iocp_io_service::on_pending(win_iocp_operation* op)
{
if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
{
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
0, overlapped_contains_result, op))
{
// Out of resources. Put on completed queue instead.
mutex::scoped_lock lock(dispatch_mutex_);
completed_ops_.push(op);
::InterlockedExchange(&dispatch_required_, 1);
}
}
}
void win_iocp_io_service::on_completion(win_iocp_operation* op,
DWORD last_error, DWORD bytes_transferred)
{
// Flag that the operation is ready for invocation.
op->ready_ = 1;
// Store results in the OVERLAPPED structure.
op->Internal = asio::error::get_system_category();
op->Offset = last_error;
op->OffsetHigh = bytes_transferred;
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
0, overlapped_contains_result, op))
{
// Out of resources. Put on completed queue instead.
mutex::scoped_lock lock(dispatch_mutex_);
completed_ops_.push(op);
::InterlockedExchange(&dispatch_required_, 1);
}
}
void win_iocp_io_service::on_completion(win_iocp_operation* op,
const asio::error_code& ec, DWORD bytes_transferred)
{
// Flag that the operation is ready for invocation.
op->ready_ = 1;
// Store results in the OVERLAPPED structure.
op->Internal = ec.category();
op->Offset = ec.value();
op->OffsetHigh = bytes_transferred;
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
0, overlapped_contains_result, op))
{
// Out of resources. Put on completed queue instead.
mutex::scoped_lock lock(dispatch_mutex_);
completed_ops_.push(op);
::InterlockedExchange(&dispatch_required_, 1);
}
}
size_t win_iocp_io_service::do_one(bool block, asio::error_code& ec)
{
for (;;)
{
// Try to acquire responsibility for dispatching timers and completed ops.
if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)
{
mutex::scoped_lock lock(dispatch_mutex_);
// Dispatch pending timers and operations.
op_queue<win_iocp_operation> ops;
ops.push(completed_ops_);
timer_queues_.get_ready_timers(ops);
post_deferred_completions(ops);
update_timeout();
}
// Get the next operation from the queue.
DWORD bytes_transferred = 0;
dword_ptr_t completion_key = 0;
LPOVERLAPPED overlapped = 0;
::SetLastError(0);
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
&completion_key, &overlapped, block ? gqcs_timeout : 0);
DWORD last_error = ::GetLastError();
if (overlapped)
{
win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
asio::error_code result_ec(last_error,
asio::error::get_system_category());
// We may have been passed the last_error and bytes_transferred in the
// OVERLAPPED structure itself.
if (completion_key == overlapped_contains_result)
{
result_ec = asio::error_code(static_cast<int>(op->Offset),
static_cast<asio::error_category>(op->Internal));
bytes_transferred = op->OffsetHigh;
}
// Otherwise ensure any result has been saved into the OVERLAPPED
// structure.
else
{
op->Internal = result_ec.category();
op->Offset = result_ec.value();
op->OffsetHigh = bytes_transferred;
}
// Dispatch the operation only if ready. The operation may not be ready
// if the initiating function (e.g. a call to WSARecv) has not yet
// returned. This is because the initiating function still wants access
// to the operation's OVERLAPPED structure.
if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
{
// Ensure the count of outstanding work is decremented on block exit.
work_finished_on_block_exit on_exit = { this };
(void)on_exit;
op->complete(*this, result_ec, bytes_transferred);
ec = asio::error_code();
return 1;
}
}
else if (!ok)
{
if (last_error != WAIT_TIMEOUT)
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
// If we're not polling we need to keep going until we get a real handler.
if (block)
continue;
ec = asio::error_code();
return 0;
}
else if (completion_key == wake_for_dispatch)
{
// We have been woken up to try to acquire responsibility for dispatching
// timers and completed operations.
}
else
{
// The stopped_ flag is always checked to ensure that any leftover
// interrupts from a previous run invocation are ignored.
if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
{
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
}
ec = asio::error_code();
return 0;
}
}
}
}
void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(dispatch_mutex_);
timer_queues_.insert(&queue);
if (!waitable_timer_.handle)
{
waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);
if (waitable_timer_.handle == 0)
{
DWORD last_error = ::GetLastError();
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "timer");
}
LARGE_INTEGER timeout;
timeout.QuadPart = -max_timeout_usec;
timeout.QuadPart *= 10;
::SetWaitableTimer(waitable_timer_.handle,
&timeout, max_timeout_msec, 0, 0, FALSE);
}
if (!timer_thread_)
{
timer_thread_function thread_function = { this };
timer_thread_.reset(new thread(thread_function, 65536));
}
}
void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(dispatch_mutex_);
timer_queues_.erase(&queue);
}
void win_iocp_io_service::update_timeout()
{
if (timer_thread_)
{
// There's no point updating the waitable timer if the new timeout period
// exceeds the maximum timeout. In that case, we might as well wait for the
// existing period of the timer to expire.
long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);
if (timeout_usec < max_timeout_usec)
{
LARGE_INTEGER timeout;
timeout.QuadPart = -timeout_usec;
timeout.QuadPart *= 10;
::SetWaitableTimer(waitable_timer_.handle,
&timeout, max_timeout_msec, 0, 0, FALSE);
}
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP

View File

@@ -0,0 +1,180 @@
//
// detail/impl/win_iocp_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
#include <cstring>
#include "asio/detail/win_iocp_serial_port_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
win_iocp_serial_port_service::win_iocp_serial_port_service(
asio::io_service& io_service)
: handle_service_(io_service)
{
}
void win_iocp_serial_port_service::shutdown_service()
{
}
asio::error_code win_iocp_serial_port_service::open(
win_iocp_serial_port_service::implementation_type& impl,
const std::string& device, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
// For convenience, add a leading \\.\ sequence if not already present.
std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
// Open a handle to the serial port.
::HANDLE handle = ::CreateFileA(name.c_str(),
GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle == INVALID_HANDLE_VALUE)
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Determine the initial serial port parameters.
using namespace std; // For memset.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Set some default serial port parameters. This implementation does not
// support changing these, so they might as well be in a known state.
dcb.fBinary = TRUE; // Win32 only supports binary mode.
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE; // Do not ignore NULL characters.
dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// Set up timeouts so that the serial port will behave similarly to a
// network socket. Reads wait for at least one byte, then return with
// whatever they have. Writes return once everything is out the door.
::COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!::SetCommTimeouts(handle, &timeouts))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
// We're done. Take ownership of the serial port handle.
if (handle_service_.assign(impl, handle, ec))
::CloseHandle(handle);
return ec;
}
asio::error_code win_iocp_serial_port_service::do_set_option(
win_iocp_serial_port_service::implementation_type& impl,
win_iocp_serial_port_service::store_function_type store,
const void* option, asio::error_code& ec)
{
using namespace std; // For memcpy.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
if (store(option, dcb, ec))
return ec;
if (!::SetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
ec = asio::error_code();
return ec;
}
asio::error_code win_iocp_serial_port_service::do_get_option(
const win_iocp_serial_port_service::implementation_type& impl,
win_iocp_serial_port_service::load_function_type load,
void* option, asio::error_code& ec) const
{
using namespace std; // For memset.
::DCB dcb;
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!::GetCommState(handle_service_.native(impl), &dcb))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return ec;
}
return load(option, dcb, ec);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP

View File

@@ -0,0 +1,575 @@
//
// detail/impl/win_iocp_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_IOCP)
#include "asio/detail/win_iocp_socket_service_base.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
win_iocp_socket_service_base::win_iocp_socket_service_base(
asio::io_service& io_service)
: io_service_(io_service),
iocp_service_(use_service<win_iocp_io_service>(io_service)),
reactor_(0),
mutex_(),
impl_list_(0)
{
}
void win_iocp_socket_service_base::shutdown_service()
{
// Close all implementations, causing all operations to complete.
asio::detail::mutex::scoped_lock lock(mutex_);
base_implementation_type* impl = impl_list_;
while (impl)
{
asio::error_code ignored_ec;
close_for_destruction(*impl);
impl = impl->next_;
}
}
void win_iocp_socket_service_base::construct(
win_iocp_socket_service_base::base_implementation_type& impl)
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.cancel_token_.reset();
#if defined(ASIO_ENABLE_CANCELIO)
impl.safe_cancellation_thread_id_ = 0;
#endif // defined(ASIO_ENABLE_CANCELIO)
// Insert implementation into linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
impl.next_ = impl_list_;
impl.prev_ = 0;
if (impl_list_)
impl_list_->prev_ = &impl;
impl_list_ = &impl;
}
void win_iocp_socket_service_base::destroy(
win_iocp_socket_service_base::base_implementation_type& impl)
{
close_for_destruction(impl);
// Remove implementation from linked list of all implementations.
asio::detail::mutex::scoped_lock lock(mutex_);
if (impl_list_ == &impl)
impl_list_ = impl.next_;
if (impl.prev_)
impl.prev_->next_ = impl.next_;
if (impl.next_)
impl.next_->prev_= impl.prev_;
impl.next_ = 0;
impl.prev_ = 0;
}
asio::error_code win_iocp_socket_service_base::close(
win_iocp_socket_service_base::base_implementation_type& impl,
asio::error_code& ec)
{
if (is_open(impl))
{
// Check if the reactor was created, in which case we need to close the
// socket on the reactor as well to cancel any operations that might be
// running there.
reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
r->close_descriptor(impl.socket_, impl.reactor_data_);
}
if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0)
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.cancel_token_.reset();
#if defined(ASIO_ENABLE_CANCELIO)
impl.safe_cancellation_thread_id_ = 0;
#endif // defined(ASIO_ENABLE_CANCELIO)
}
return ec;
}
asio::error_code win_iocp_socket_service_base::cancel(
win_iocp_socket_service_base::base_implementation_type& impl,
asio::error_code& ec)
{
if (!is_open(impl))
{
ec = asio::error::bad_descriptor;
return ec;
}
else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
socket_type sock = impl.socket_;
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
if (!cancel_io_ex(sock_as_handle, 0))
{
DWORD last_error = ::GetLastError();
if (last_error == ERROR_NOT_FOUND)
{
// ERROR_NOT_FOUND means that there were no operations to be
// cancelled. We swallow this error to match the behaviour on other
// platforms.
ec = asio::error_code();
}
else
{
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
}
else
{
ec = asio::error_code();
}
}
#if defined(ASIO_ENABLE_CANCELIO)
else if (impl.safe_cancellation_thread_id_ == 0)
{
// No operations have been started, so there's nothing to cancel.
ec = asio::error_code();
}
else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
{
// Asynchronous operations have been started from the current thread only,
// so it is safe to try to cancel them using CancelIo.
socket_type sock = impl.socket_;
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
if (!::CancelIo(sock_as_handle))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
}
else
{
ec = asio::error_code();
}
}
else
{
// Asynchronous operations have been started from more than one thread,
// so cancellation is not safe.
ec = asio::error::operation_not_supported;
}
#else // defined(ASIO_ENABLE_CANCELIO)
else
{
// Cancellation is not supported as CancelIo may not be used.
ec = asio::error::operation_not_supported;
}
#endif // defined(ASIO_ENABLE_CANCELIO)
// Cancel any operations started via the reactor.
if (!ec)
{
reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
r->cancel_ops(impl.socket_, impl.reactor_data_);
}
return ec;
}
asio::error_code win_iocp_socket_service_base::do_open(
win_iocp_socket_service_base::base_implementation_type& impl,
int family, int type, int protocol, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
socket_holder sock(socket_ops::socket(family, type, protocol, ec));
if (sock.get() == invalid_socket)
return ec;
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
if (iocp_service_.register_handle(sock_as_handle, ec))
return ec;
impl.socket_ = sock.release();
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
ec = asio::error_code();
return ec;
}
asio::error_code win_iocp_socket_service_base::do_assign(
win_iocp_socket_service_base::base_implementation_type& impl,
int type, socket_type native_socket, asio::error_code& ec)
{
if (is_open(impl))
{
ec = asio::error::already_open;
return ec;
}
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
if (iocp_service_.register_handle(sock_as_handle, ec))
return ec;
impl.socket_ = native_socket;
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
ec = asio::error_code();
return ec;
}
void win_iocp_socket_service_base::start_send_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count,
socket_base::message_flags flags, bool noop, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (noop)
iocp_service_.on_completion(op);
else if (!is_open(impl))
iocp_service_.on_completion(op, asio::error::bad_descriptor);
else
{
DWORD bytes_transferred = 0;
int result = ::WSASend(impl.socket_, buffers,
static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
if (result != 0 && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error, bytes_transferred);
else
iocp_service_.on_pending(op);
}
}
void win_iocp_socket_service_base::start_send_to_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count,
const socket_addr_type* addr, int addrlen,
socket_base::message_flags flags, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (!is_open(impl))
iocp_service_.on_completion(op, asio::error::bad_descriptor);
else
{
DWORD bytes_transferred = 0;
int result = ::WSASendTo(impl.socket_, buffers,
static_cast<DWORD>(buffer_count),
&bytes_transferred, flags, addr, addrlen, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
if (result != 0 && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error, bytes_transferred);
else
iocp_service_.on_pending(op);
}
}
void win_iocp_socket_service_base::start_receive_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count,
socket_base::message_flags flags, bool noop, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (noop)
iocp_service_.on_completion(op);
else if (!is_open(impl))
iocp_service_.on_completion(op, asio::error::bad_descriptor);
else
{
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = ::WSARecv(impl.socket_, buffers,
static_cast<DWORD>(buffer_count),
&bytes_transferred, &recv_flags, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_NETNAME_DELETED)
last_error = WSAECONNRESET;
else if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
if (result != 0 && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error, bytes_transferred);
else
iocp_service_.on_pending(op);
}
}
void win_iocp_socket_service_base::start_null_buffers_receive_op(
win_iocp_socket_service_base::base_implementation_type& impl,
socket_base::message_flags flags, reactor_op* op)
{
if ((impl.state_ & socket_ops::stream_oriented) != 0)
{
// For stream sockets on Windows, we may issue a 0-byte overlapped
// WSARecv to wait until there is data available on the socket.
::WSABUF buf = { 0, 0 };
start_receive_op(impl, &buf, 1, flags, false, op);
}
else
{
start_reactor_op(impl,
(flags & socket_base::message_out_of_band)
? reactor::except_op : reactor::read_op,
op);
}
}
void win_iocp_socket_service_base::start_receive_from_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
socket_base::message_flags flags, int* addrlen, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (!is_open(impl))
iocp_service_.on_completion(op, asio::error::bad_descriptor);
else
{
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = ::WSARecvFrom(impl.socket_, buffers,
static_cast<DWORD>(buffer_count),
&bytes_transferred, &recv_flags, addr, addrlen, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
if (result != 0 && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error, bytes_transferred);
else
iocp_service_.on_pending(op);
}
}
void win_iocp_socket_service_base::start_accept_op(
win_iocp_socket_service_base::base_implementation_type& impl,
bool peer_is_open, socket_holder& new_socket, int family, int type,
int protocol, void* output_buffer, DWORD address_length, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
if (!is_open(impl))
iocp_service_.on_completion(op, asio::error::bad_descriptor);
else if (peer_is_open)
iocp_service_.on_completion(op, asio::error::already_open);
else
{
asio::error_code ec;
new_socket.reset(socket_ops::socket(family, type, protocol, ec));
if (new_socket.get() == invalid_socket)
iocp_service_.on_completion(op, ec);
else
{
DWORD bytes_read = 0;
BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
0, address_length, address_length, &bytes_read, op);
DWORD last_error = ::WSAGetLastError();
if (!result && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error);
else
iocp_service_.on_pending(op);
}
}
}
void win_iocp_socket_service_base::restart_accept_op(
socket_type s, socket_holder& new_socket, int family, int type,
int protocol, void* output_buffer, DWORD address_length, operation* op)
{
new_socket.reset();
iocp_service_.work_started();
asio::error_code ec;
new_socket.reset(socket_ops::socket(family, type, protocol, ec));
if (new_socket.get() == invalid_socket)
iocp_service_.on_completion(op, ec);
else
{
DWORD bytes_read = 0;
BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
0, address_length, address_length, &bytes_read, op);
DWORD last_error = ::WSAGetLastError();
if (!result && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error);
else
iocp_service_.on_pending(op);
}
}
void win_iocp_socket_service_base::start_reactor_op(
win_iocp_socket_service_base::base_implementation_type& impl,
int op_type, reactor_op* op)
{
reactor& r = get_reactor();
update_cancellation_thread_id(impl);
if (is_open(impl))
{
r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
return;
}
else
op->ec_ = asio::error::bad_descriptor;
iocp_service_.post_immediate_completion(op);
}
void win_iocp_socket_service_base::start_connect_op(
win_iocp_socket_service_base::base_implementation_type& impl,
reactor_op* op, const socket_addr_type* addr, std::size_t addrlen)
{
reactor& r = get_reactor();
update_cancellation_thread_id(impl);
if ((impl.state_ & socket_ops::non_blocking) != 0
|| socket_ops::set_internal_non_blocking(
impl.socket_, impl.state_, op->ec_))
{
if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
{
if (op->ec_ == asio::error::in_progress
|| op->ec_ == asio::error::would_block)
{
op->ec_ = asio::error_code();
r.start_op(reactor::connect_op, impl.socket_,
impl.reactor_data_, op, false);
return;
}
}
}
r.post_immediate_completion(op);
}
void win_iocp_socket_service_base::close_for_destruction(
win_iocp_socket_service_base::base_implementation_type& impl)
{
if (is_open(impl))
{
// Check if the reactor was created, in which case we need to close the
// socket on the reactor as well to cancel any operations that might be
// running there.
reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
r->close_descriptor(impl.socket_, impl.reactor_data_);
}
asio::error_code ignored_ec;
socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.cancel_token_.reset();
#if defined(ASIO_ENABLE_CANCELIO)
impl.safe_cancellation_thread_id_ = 0;
#endif // defined(ASIO_ENABLE_CANCELIO)
}
void win_iocp_socket_service_base::update_cancellation_thread_id(
win_iocp_socket_service_base::base_implementation_type& impl)
{
#if defined(ASIO_ENABLE_CANCELIO)
if (impl.safe_cancellation_thread_id_ == 0)
impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
impl.safe_cancellation_thread_id_ = ~DWORD(0);
#else // defined(ASIO_ENABLE_CANCELIO)
(void)impl;
#endif // defined(ASIO_ENABLE_CANCELIO)
}
reactor& win_iocp_socket_service_base::get_reactor()
{
reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!r)
{
r = &(use_service<reactor>(io_service_));
interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
}
return *r;
}
void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
void** dest, void* exch, void* cmp)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedCompareExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
reinterpret_cast<LONG>(cmp)));
#else
return InterlockedCompareExchangePointer(dest, exch, cmp);
#endif
}
void* win_iocp_socket_service_base::interlocked_exchange_pointer(
void** dest, void* val)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
#else
return InterlockedExchangePointer(dest, val);
#endif
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_IOCP)
#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP

View File

@@ -0,0 +1,78 @@
//
// detail/impl/win_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_mutex.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
win_mutex::win_mutex()
{
int error = do_init();
asio::error_code ec(error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "mutex");
}
int win_mutex::do_init()
{
#if defined(__MINGW32__)
// Not sure if MinGW supports structured exception handling, so for now
// we'll just call the Windows API and hope.
# if defined(UNDER_CE)
::InitializeCriticalSection(&crit_section_);
# else
if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
return ::GetLastError();
# endif
return 0;
#else
__try
{
# if defined(UNDER_CE)
::InitializeCriticalSection(&crit_section_);
# else
if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
return ::GetLastError();
# endif
}
__except(GetExceptionCode() == STATUS_NO_MEMORY
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return ERROR_OUTOFMEMORY;
}
return 0;
#endif
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS)
#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP

View File

@@ -0,0 +1,138 @@
//
// detail/impl/win_thread.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP
#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include <process.h>
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_thread.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
win_thread::~win_thread()
{
::CloseHandle(thread_);
// The exit_event_ handle is deliberately allowed to leak here since it
// is an error for the owner of an internal thread not to join() it.
}
void win_thread::join()
{
HANDLE handles[2] = { exit_event_, thread_ };
::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
::CloseHandle(exit_event_);
if (terminate_threads())
{
::TerminateThread(thread_, 0);
}
else
{
::QueueUserAPC(apc_function, thread_, 0);
::WaitForSingleObject(thread_, INFINITE);
}
}
void win_thread::start_thread(func_base* arg, unsigned int stack_size)
{
::HANDLE entry_event = 0;
arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
if (!entry_event)
{
DWORD last_error = ::GetLastError();
delete arg;
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "thread.entry_event");
}
arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
if (!exit_event_)
{
DWORD last_error = ::GetLastError();
delete arg;
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "thread.exit_event");
}
unsigned int thread_id = 0;
thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,
stack_size, win_thread_function, arg, 0, &thread_id));
if (!thread_)
{
DWORD last_error = ::GetLastError();
delete arg;
if (entry_event)
::CloseHandle(entry_event);
if (exit_event_)
::CloseHandle(exit_event_);
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "thread");
}
if (entry_event)
{
::WaitForSingleObject(entry_event, INFINITE);
::CloseHandle(entry_event);
}
}
unsigned int __stdcall win_thread_function(void* arg)
{
std::auto_ptr<win_thread::func_base> func(
static_cast<win_thread::func_base*>(arg));
::SetEvent(func->entry_event_);
func->run();
// 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 defined(WINVER) && (WINVER < 0x0500)
void __stdcall apc_function(ULONG) {}
#else
void __stdcall apc_function(ULONG_PTR) {}
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP

View File

@@ -0,0 +1,57 @@
//
// detail/impl/win_tss_ptr.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_tss_ptr.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
DWORD win_tss_ptr_create()
{
#if defined(UNDER_CE)
enum { out_of_indexes = 0xFFFFFFFF };
#else
enum { out_of_indexes = TLS_OUT_OF_INDEXES };
#endif
DWORD tss_key = ::TlsAlloc();
if (tss_key == out_of_indexes)
{
DWORD last_error = ::GetLastError();
asio::error_code ec(last_error,
asio::error::get_system_category());
asio::detail::throw_error(ec, "tss");
}
return tss_key;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS)
#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP

View File

@@ -0,0 +1,69 @@
//
// detail/impl/winsock_init.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 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)
//
#ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/socket_types.hpp"
#include "asio/detail/winsock_init.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
void winsock_init_base::startup(data& d,
unsigned char major, unsigned char minor)
{
if (::InterlockedIncrement(&d.init_count_) == 1)
{
WSADATA wsa_data;
long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data);
::InterlockedExchange(&d.result_, result);
}
}
void winsock_init_base::cleanup(data& d)
{
if (::InterlockedDecrement(&d.init_count_) == 0)
{
::WSACleanup();
}
}
void winsock_init_base::throw_on_error(data& d)
{
long result = ::InterlockedExchangeAdd(&d.result_, 0);
if (result != 0)
{
asio::error_code ec(result,
asio::error::get_system_category());
asio::detail::throw_error(ec, "winsock");
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP

View File

@@ -1,8 +1,8 @@
//
// io_control.hpp
// ~~~~~~~~~~~~~~
// detail/io_control.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2011 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)
@@ -15,15 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include "asio/detail/config.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
namespace io_control {

Some files were not shown because too many files have changed in this diff Show More