~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to include/libtorrent/asio/detail/reactive_descriptor_service.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Sauthier
  • Date: 2010-08-10 12:59:37 UTC
  • mfrom: (1.3.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100810125937-jbcmmf17y8yo9hgz
Tags: 0.15.0-0ubuntu1
* New upstream version.
* debian/patches/100_fix_html_docs.patch: refreshed.
* debian/control: bump up standards-version to 3.9.1 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// reactive_descriptor_service.hpp
3
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
 
//
5
 
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6
 
//
7
 
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
 
//
10
 
 
11
 
#ifndef ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
12
 
#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
13
 
 
14
 
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
 
# pragma once
16
 
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
 
 
18
 
#include "asio/detail/push_options.hpp"
19
 
 
20
 
#include "asio/buffer.hpp"
21
 
#include "asio/error.hpp"
22
 
#include "asio/io_service.hpp"
23
 
#include "asio/detail/bind_handler.hpp"
24
 
#include "asio/detail/handler_base_from_member.hpp"
25
 
#include "asio/detail/noncopyable.hpp"
26
 
#include "asio/detail/service_base.hpp"
27
 
#include "asio/detail/descriptor_ops.hpp"
28
 
 
29
 
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
30
 
 
31
 
namespace asio {
32
 
namespace detail {
33
 
 
34
 
template <typename Reactor>
35
 
class reactive_descriptor_service
36
 
  : public asio::detail::service_base<
37
 
      reactive_descriptor_service<Reactor> >
38
 
{
39
 
public:
40
 
  // The native type of a descriptor.
41
 
  typedef int native_type;
42
 
 
43
 
  // The implementation type of the descriptor.
44
 
  class implementation_type
45
 
    : private asio::detail::noncopyable
46
 
  {
47
 
  public:
48
 
    // Default constructor.
49
 
    implementation_type()
50
 
      : descriptor_(-1),
51
 
        flags_(0)
52
 
    {
53
 
    }
54
 
 
55
 
  private:
56
 
    // Only this service will have access to the internal values.
57
 
    friend class reactive_descriptor_service<Reactor>;
58
 
 
59
 
    // The native descriptor representation.
60
 
    int descriptor_;
61
 
 
62
 
    enum
63
 
    {
64
 
      user_set_non_blocking = 1, // The user wants a non-blocking descriptor.
65
 
      internal_non_blocking = 2  // The descriptor has been set non-blocking.
66
 
    };
67
 
 
68
 
    // Flags indicating the current state of the descriptor.
69
 
    unsigned char flags_;
70
 
 
71
 
    // Per-descriptor data used by the reactor.
72
 
    typename Reactor::per_descriptor_data reactor_data_;
73
 
  };
74
 
 
75
 
  // The maximum number of buffers to support in a single operation.
76
 
  enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
77
 
 
78
 
  // Constructor.
79
 
  reactive_descriptor_service(asio::io_service& io_service)
80
 
    : asio::detail::service_base<
81
 
        reactive_descriptor_service<Reactor> >(io_service),
82
 
      reactor_(asio::use_service<Reactor>(io_service))
83
 
  {
84
 
  }
85
 
 
86
 
  // Destroy all user-defined handler objects owned by the service.
87
 
  void shutdown_service()
88
 
  {
89
 
  }
90
 
 
91
 
  // Construct a new descriptor implementation.
92
 
  void construct(implementation_type& impl)
93
 
  {
94
 
    impl.descriptor_ = -1;
95
 
    impl.flags_ = 0;
96
 
  }
97
 
 
98
 
  // Destroy a descriptor implementation.
99
 
  void destroy(implementation_type& impl)
100
 
  {
101
 
    if (impl.descriptor_ != -1)
102
 
    {
103
 
      reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
104
 
 
105
 
      if (impl.flags_ & implementation_type::internal_non_blocking)
106
 
      {
107
 
        ioctl_arg_type non_blocking = 0;
108
 
        asio::error_code ignored_ec;
109
 
        descriptor_ops::ioctl(impl.descriptor_,
110
 
            FIONBIO, &non_blocking, ignored_ec);
111
 
        impl.flags_ &= ~implementation_type::internal_non_blocking;
112
 
      }
113
 
 
114
 
      asio::error_code ignored_ec;
115
 
      descriptor_ops::close(impl.descriptor_, ignored_ec);
116
 
 
117
 
      impl.descriptor_ = -1;
118
 
    }
119
 
  }
120
 
 
121
 
  // Assign a native descriptor to a descriptor implementation.
122
 
  asio::error_code assign(implementation_type& impl,
123
 
      const native_type& native_descriptor, asio::error_code& ec)
124
 
  {
125
 
    if (is_open(impl))
126
 
    {
127
 
      ec = asio::error::already_open;
128
 
      return ec;
129
 
    }
130
 
 
131
 
    if (int err = reactor_.register_descriptor(
132
 
          native_descriptor, impl.reactor_data_))
133
 
    {
134
 
      ec = asio::error_code(err,
135
 
          asio::error::get_system_category());
136
 
      return ec;
137
 
    }
138
 
 
139
 
    impl.descriptor_ = native_descriptor;
140
 
    impl.flags_ = 0;
141
 
    ec = asio::error_code();
142
 
    return ec;
143
 
  }
144
 
 
145
 
  // Determine whether the descriptor is open.
146
 
  bool is_open(const implementation_type& impl) const
147
 
  {
148
 
    return impl.descriptor_ != -1;
149
 
  }
150
 
 
151
 
  // Destroy a descriptor implementation.
152
 
  asio::error_code close(implementation_type& impl,
153
 
      asio::error_code& ec)
154
 
  {
155
 
    if (is_open(impl))
156
 
    {
157
 
      reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
158
 
 
159
 
      if (impl.flags_ & implementation_type::internal_non_blocking)
160
 
      {
161
 
        ioctl_arg_type non_blocking = 0;
162
 
        asio::error_code ignored_ec;
163
 
        descriptor_ops::ioctl(impl.descriptor_,
164
 
            FIONBIO, &non_blocking, ignored_ec);
165
 
        impl.flags_ &= ~implementation_type::internal_non_blocking;
166
 
      }
167
 
 
168
 
      if (descriptor_ops::close(impl.descriptor_, ec) == -1)
169
 
        return ec;
170
 
 
171
 
      impl.descriptor_ = -1;
172
 
    }
173
 
 
174
 
    ec = asio::error_code();
175
 
    return ec;
176
 
  }
177
 
 
178
 
  // Get the native descriptor representation.
179
 
  native_type native(const implementation_type& impl) const
180
 
  {
181
 
    return impl.descriptor_;
182
 
  }
183
 
 
184
 
  // Cancel all operations associated with the descriptor.
185
 
  asio::error_code cancel(implementation_type& impl,
186
 
      asio::error_code& ec)
187
 
  {
188
 
    if (!is_open(impl))
189
 
    {
190
 
      ec = asio::error::bad_descriptor;
191
 
      return ec;
192
 
    }
193
 
 
194
 
    reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
195
 
    ec = asio::error_code();
196
 
    return ec;
197
 
  }
198
 
 
199
 
  // Perform an IO control command on the descriptor.
200
 
  template <typename IO_Control_Command>
201
 
  asio::error_code io_control(implementation_type& impl,
202
 
      IO_Control_Command& command, asio::error_code& ec)
203
 
  {
204
 
    if (!is_open(impl))
205
 
    {
206
 
      ec = asio::error::bad_descriptor;
207
 
      return ec;
208
 
    }
209
 
 
210
 
    if (command.name() == static_cast<int>(FIONBIO))
211
 
    {
212
 
      if (command.get())
213
 
        impl.flags_ |= implementation_type::user_set_non_blocking;
214
 
      else
215
 
        impl.flags_ &= ~implementation_type::user_set_non_blocking;
216
 
      ec = asio::error_code();
217
 
    }
218
 
    else
219
 
    {
220
 
      descriptor_ops::ioctl(impl.descriptor_, command.name(),
221
 
          static_cast<ioctl_arg_type*>(command.data()), ec);
222
 
    }
223
 
    return ec;
224
 
  }
225
 
 
226
 
  // Write some data to the descriptor.
227
 
  template <typename ConstBufferSequence>
228
 
  size_t write_some(implementation_type& impl,
229
 
      const ConstBufferSequence& buffers, asio::error_code& ec)
230
 
  {
231
 
    if (!is_open(impl))
232
 
    {
233
 
      ec = asio::error::bad_descriptor;
234
 
      return 0;
235
 
    }
236
 
 
237
 
    // Copy buffers into array.
238
 
    descriptor_ops::buf bufs[max_buffers];
239
 
    typename ConstBufferSequence::const_iterator iter = buffers.begin();
240
 
    typename ConstBufferSequence::const_iterator end = buffers.end();
241
 
    size_t i = 0;
242
 
    size_t total_buffer_size = 0;
243
 
    for (; iter != end && i < max_buffers; ++iter, ++i)
244
 
    {
245
 
      asio::const_buffer buffer(*iter);
246
 
      descriptor_ops::init_buf(bufs[i],
247
 
          asio::buffer_cast<const void*>(buffer),
248
 
          asio::buffer_size(buffer));
249
 
      total_buffer_size += asio::buffer_size(buffer);
250
 
    }
251
 
 
252
 
    // A request to read_some 0 bytes on a stream is a no-op.
253
 
    if (total_buffer_size == 0)
254
 
    {
255
 
      ec = asio::error_code();
256
 
      return 0;
257
 
    }
258
 
 
259
 
    // Make descriptor non-blocking if user wants non-blocking.
260
 
    if (impl.flags_ & implementation_type::user_set_non_blocking)
261
 
    {
262
 
      if (!(impl.flags_ & implementation_type::internal_non_blocking))
263
 
      {
264
 
        ioctl_arg_type non_blocking = 1;
265
 
        if (descriptor_ops::ioctl(impl.descriptor_,
266
 
              FIONBIO, &non_blocking, ec))
267
 
          return 0;
268
 
        impl.flags_ |= implementation_type::internal_non_blocking;
269
 
      }
270
 
    }
271
 
 
272
 
    // Send the data.
273
 
    for (;;)
274
 
    {
275
 
      // Try to complete the operation without blocking.
276
 
      int bytes_sent = descriptor_ops::gather_write(
277
 
          impl.descriptor_, bufs, i, ec);
278
 
 
279
 
      // Check if operation succeeded.
280
 
      if (bytes_sent >= 0)
281
 
        return bytes_sent;
282
 
 
283
 
      // Operation failed.
284
 
      if ((impl.flags_ & implementation_type::user_set_non_blocking)
285
 
          || (ec != asio::error::would_block
286
 
            && ec != asio::error::try_again))
287
 
        return 0;
288
 
 
289
 
      // Wait for descriptor to become ready.
290
 
      if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
291
 
        return 0;
292
 
    }
293
 
  }
294
 
 
295
 
  // Wait until data can be written without blocking.
296
 
  size_t write_some(implementation_type& impl,
297
 
      const null_buffers&, asio::error_code& ec)
298
 
  {
299
 
    if (!is_open(impl))
300
 
    {
301
 
      ec = asio::error::bad_descriptor;
302
 
      return 0;
303
 
    }
304
 
 
305
 
    // Wait for descriptor to become ready.
306
 
    descriptor_ops::poll_write(impl.descriptor_, ec);
307
 
 
308
 
    return 0;
309
 
  }
310
 
 
311
 
  template <typename ConstBufferSequence, typename Handler>
312
 
  class write_operation :
313
 
    public handler_base_from_member<Handler>
314
 
  {
315
 
  public:
316
 
    write_operation(int descriptor, asio::io_service& io_service,
317
 
        const ConstBufferSequence& buffers, Handler handler)
318
 
      : handler_base_from_member<Handler>(handler),
319
 
        descriptor_(descriptor),
320
 
        io_service_(io_service),
321
 
        work_(io_service),
322
 
        buffers_(buffers)
323
 
    {
324
 
    }
325
 
 
326
 
    bool perform(asio::error_code& ec,
327
 
        std::size_t& bytes_transferred)
328
 
    {
329
 
      // Check whether the operation was successful.
330
 
      if (ec)
331
 
      {
332
 
        bytes_transferred = 0;
333
 
        return true;
334
 
      }
335
 
 
336
 
      // Copy buffers into array.
337
 
      descriptor_ops::buf bufs[max_buffers];
338
 
      typename ConstBufferSequence::const_iterator iter = buffers_.begin();
339
 
      typename ConstBufferSequence::const_iterator end = buffers_.end();
340
 
      size_t i = 0;
341
 
      for (; iter != end && i < max_buffers; ++iter, ++i)
342
 
      {
343
 
        asio::const_buffer buffer(*iter);
344
 
        descriptor_ops::init_buf(bufs[i],
345
 
            asio::buffer_cast<const void*>(buffer),
346
 
            asio::buffer_size(buffer));
347
 
      }
348
 
 
349
 
      // Write the data.
350
 
      int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec);
351
 
 
352
 
      // Check if we need to run the operation again.
353
 
      if (ec == asio::error::would_block
354
 
          || ec == asio::error::try_again)
355
 
        return false;
356
 
 
357
 
      bytes_transferred = (bytes < 0 ? 0 : bytes);
358
 
      return true;
359
 
    }
360
 
 
361
 
    void complete(const asio::error_code& ec,
362
 
        std::size_t bytes_transferred)
363
 
    {
364
 
      io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
365
 
    }
366
 
 
367
 
  private:
368
 
    int descriptor_;
369
 
    asio::io_service& io_service_;
370
 
    asio::io_service::work work_;
371
 
    ConstBufferSequence buffers_;
372
 
  };
373
 
 
374
 
  // Start an asynchronous write. The data being sent must be valid for the
375
 
  // lifetime of the asynchronous operation.
376
 
  template <typename ConstBufferSequence, typename Handler>
377
 
  void async_write_some(implementation_type& impl,
378
 
      const ConstBufferSequence& buffers, Handler handler)
379
 
  {
380
 
    if (!is_open(impl))
381
 
    {
382
 
      this->get_io_service().post(bind_handler(handler,
383
 
            asio::error::bad_descriptor, 0));
384
 
    }
385
 
    else
386
 
    {
387
 
      // Determine total size of buffers.
388
 
      typename ConstBufferSequence::const_iterator iter = buffers.begin();
389
 
      typename ConstBufferSequence::const_iterator end = buffers.end();
390
 
      size_t i = 0;
391
 
      size_t total_buffer_size = 0;
392
 
      for (; iter != end && i < max_buffers; ++iter, ++i)
393
 
      {
394
 
        asio::const_buffer buffer(*iter);
395
 
        total_buffer_size += asio::buffer_size(buffer);
396
 
      }
397
 
 
398
 
      // A request to read_some 0 bytes on a stream is a no-op.
399
 
      if (total_buffer_size == 0)
400
 
      {
401
 
        this->get_io_service().post(bind_handler(handler,
402
 
              asio::error_code(), 0));
403
 
        return;
404
 
      }
405
 
 
406
 
      // Make descriptor non-blocking.
407
 
      if (!(impl.flags_ & implementation_type::internal_non_blocking))
408
 
      {
409
 
        ioctl_arg_type non_blocking = 1;
410
 
        asio::error_code ec;
411
 
        if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
412
 
        {
413
 
          this->get_io_service().post(bind_handler(handler, ec, 0));
414
 
          return;
415
 
        }
416
 
        impl.flags_ |= implementation_type::internal_non_blocking;
417
 
      }
418
 
 
419
 
      reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
420
 
          write_operation<ConstBufferSequence, Handler>(
421
 
            impl.descriptor_, this->get_io_service(), buffers, handler));
422
 
    }
423
 
  }
424
 
 
425
 
  template <typename Handler>
426
 
  class null_buffers_operation :
427
 
    public handler_base_from_member<Handler>
428
 
  {
429
 
  public:
430
 
    null_buffers_operation(asio::io_service& io_service, Handler handler)
431
 
      : handler_base_from_member<Handler>(handler),
432
 
        work_(io_service)
433
 
    {
434
 
    }
435
 
 
436
 
    bool perform(asio::error_code&,
437
 
        std::size_t& bytes_transferred)
438
 
    {
439
 
      bytes_transferred = 0;
440
 
      return true;
441
 
    }
442
 
 
443
 
    void complete(const asio::error_code& ec,
444
 
        std::size_t bytes_transferred)
445
 
    {
446
 
      work_.get_io_service().post(bind_handler(
447
 
            this->handler_, ec, bytes_transferred));
448
 
    }
449
 
 
450
 
  private:
451
 
    asio::io_service::work work_;
452
 
  };
453
 
 
454
 
  // Start an asynchronous wait until data can be written without blocking.
455
 
  template <typename Handler>
456
 
  void async_write_some(implementation_type& impl,
457
 
      const null_buffers&, Handler handler)
458
 
  {
459
 
    if (!is_open(impl))
460
 
    {
461
 
      this->get_io_service().post(bind_handler(handler,
462
 
            asio::error::bad_descriptor, 0));
463
 
    }
464
 
    else
465
 
    {
466
 
      reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
467
 
          null_buffers_operation<Handler>(this->get_io_service(), handler),
468
 
          false);
469
 
    }
470
 
  }
471
 
 
472
 
  // Read some data from the stream. Returns the number of bytes read.
473
 
  template <typename MutableBufferSequence>
474
 
  size_t read_some(implementation_type& impl,
475
 
      const MutableBufferSequence& buffers, asio::error_code& ec)
476
 
  {
477
 
    if (!is_open(impl))
478
 
    {
479
 
      ec = asio::error::bad_descriptor;
480
 
      return 0;
481
 
    }
482
 
 
483
 
    // Copy buffers into array.
484
 
    descriptor_ops::buf bufs[max_buffers];
485
 
    typename MutableBufferSequence::const_iterator iter = buffers.begin();
486
 
    typename MutableBufferSequence::const_iterator end = buffers.end();
487
 
    size_t i = 0;
488
 
    size_t total_buffer_size = 0;
489
 
    for (; iter != end && i < max_buffers; ++iter, ++i)
490
 
    {
491
 
      asio::mutable_buffer buffer(*iter);
492
 
      descriptor_ops::init_buf(bufs[i],
493
 
          asio::buffer_cast<void*>(buffer),
494
 
          asio::buffer_size(buffer));
495
 
      total_buffer_size += asio::buffer_size(buffer);
496
 
    }
497
 
 
498
 
    // A request to read_some 0 bytes on a stream is a no-op.
499
 
    if (total_buffer_size == 0)
500
 
    {
501
 
      ec = asio::error_code();
502
 
      return 0;
503
 
    }
504
 
 
505
 
    // Make descriptor non-blocking if user wants non-blocking.
506
 
    if (impl.flags_ & implementation_type::user_set_non_blocking)
507
 
    {
508
 
      if (!(impl.flags_ & implementation_type::internal_non_blocking))
509
 
      {
510
 
        ioctl_arg_type non_blocking = 1;
511
 
        if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
512
 
          return 0;
513
 
        impl.flags_ |= implementation_type::internal_non_blocking;
514
 
      }
515
 
    }
516
 
 
517
 
    // Read some data.
518
 
    for (;;)
519
 
    {
520
 
      // Try to complete the operation without blocking.
521
 
      int bytes_read = descriptor_ops::scatter_read(
522
 
          impl.descriptor_, bufs, i, ec);
523
 
 
524
 
      // Check if operation succeeded.
525
 
      if (bytes_read > 0)
526
 
        return bytes_read;
527
 
 
528
 
      // Check for EOF.
529
 
      if (bytes_read == 0)
530
 
      {
531
 
        ec = asio::error::eof;
532
 
        return 0;
533
 
      }
534
 
 
535
 
      // Operation failed.
536
 
      if ((impl.flags_ & implementation_type::user_set_non_blocking)
537
 
          || (ec != asio::error::would_block
538
 
            && ec != asio::error::try_again))
539
 
        return 0;
540
 
 
541
 
      // Wait for descriptor to become ready.
542
 
      if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
543
 
        return 0;
544
 
    }
545
 
  }
546
 
 
547
 
  // Wait until data can be read without blocking.
548
 
  size_t read_some(implementation_type& impl,
549
 
      const null_buffers&, asio::error_code& ec)
550
 
  {
551
 
    if (!is_open(impl))
552
 
    {
553
 
      ec = asio::error::bad_descriptor;
554
 
      return 0;
555
 
    }
556
 
 
557
 
    // Wait for descriptor to become ready.
558
 
    descriptor_ops::poll_read(impl.descriptor_, ec);
559
 
 
560
 
    return 0;
561
 
  }
562
 
 
563
 
  template <typename MutableBufferSequence, typename Handler>
564
 
  class read_operation :
565
 
    public handler_base_from_member<Handler>
566
 
  {
567
 
  public:
568
 
    read_operation(int descriptor, asio::io_service& io_service,
569
 
        const MutableBufferSequence& buffers, Handler handler)
570
 
      : handler_base_from_member<Handler>(handler),
571
 
        descriptor_(descriptor),
572
 
        io_service_(io_service),
573
 
        work_(io_service),
574
 
        buffers_(buffers)
575
 
    {
576
 
    }
577
 
 
578
 
    bool perform(asio::error_code& ec,
579
 
        std::size_t& bytes_transferred)
580
 
    {
581
 
      // Check whether the operation was successful.
582
 
      if (ec)
583
 
      {
584
 
        bytes_transferred = 0;
585
 
        return true;
586
 
      }
587
 
 
588
 
      // Copy buffers into array.
589
 
      descriptor_ops::buf bufs[max_buffers];
590
 
      typename MutableBufferSequence::const_iterator iter = buffers_.begin();
591
 
      typename MutableBufferSequence::const_iterator end = buffers_.end();
592
 
      size_t i = 0;
593
 
      for (; iter != end && i < max_buffers; ++iter, ++i)
594
 
      {
595
 
        asio::mutable_buffer buffer(*iter);
596
 
        descriptor_ops::init_buf(bufs[i],
597
 
            asio::buffer_cast<void*>(buffer),
598
 
            asio::buffer_size(buffer));
599
 
      }
600
 
 
601
 
      // Read some data.
602
 
      int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec);
603
 
      if (bytes == 0)
604
 
        ec = asio::error::eof;
605
 
 
606
 
      // Check if we need to run the operation again.
607
 
      if (ec == asio::error::would_block
608
 
          || ec == asio::error::try_again)
609
 
        return false;
610
 
 
611
 
      bytes_transferred = (bytes < 0 ? 0 : bytes);
612
 
      return true;
613
 
    }
614
 
 
615
 
    void complete(const asio::error_code& ec,
616
 
        std::size_t bytes_transferred)
617
 
    {
618
 
      io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
619
 
    }
620
 
 
621
 
  private:
622
 
    int descriptor_;
623
 
    asio::io_service& io_service_;
624
 
    asio::io_service::work work_;
625
 
    MutableBufferSequence buffers_;
626
 
  };
627
 
 
628
 
  // Start an asynchronous read. The buffer for the data being read must be
629
 
  // valid for the lifetime of the asynchronous operation.
630
 
  template <typename MutableBufferSequence, typename Handler>
631
 
  void async_read_some(implementation_type& impl,
632
 
      const MutableBufferSequence& buffers, Handler handler)
633
 
  {
634
 
    if (!is_open(impl))
635
 
    {
636
 
      this->get_io_service().post(bind_handler(handler,
637
 
            asio::error::bad_descriptor, 0));
638
 
    }
639
 
    else
640
 
    {
641
 
      // Determine total size of buffers.
642
 
      typename MutableBufferSequence::const_iterator iter = buffers.begin();
643
 
      typename MutableBufferSequence::const_iterator end = buffers.end();
644
 
      size_t i = 0;
645
 
      size_t total_buffer_size = 0;
646
 
      for (; iter != end && i < max_buffers; ++iter, ++i)
647
 
      {
648
 
        asio::mutable_buffer buffer(*iter);
649
 
        total_buffer_size += asio::buffer_size(buffer);
650
 
      }
651
 
 
652
 
      // A request to read_some 0 bytes on a stream is a no-op.
653
 
      if (total_buffer_size == 0)
654
 
      {
655
 
        this->get_io_service().post(bind_handler(handler,
656
 
              asio::error_code(), 0));
657
 
        return;
658
 
      }
659
 
 
660
 
      // Make descriptor non-blocking.
661
 
      if (!(impl.flags_ & implementation_type::internal_non_blocking))
662
 
      {
663
 
        ioctl_arg_type non_blocking = 1;
664
 
        asio::error_code ec;
665
 
        if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
666
 
        {
667
 
          this->get_io_service().post(bind_handler(handler, ec, 0));
668
 
          return;
669
 
        }
670
 
        impl.flags_ |= implementation_type::internal_non_blocking;
671
 
      }
672
 
 
673
 
      reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
674
 
          read_operation<MutableBufferSequence, Handler>(
675
 
            impl.descriptor_, this->get_io_service(), buffers, handler));
676
 
    }
677
 
  }
678
 
 
679
 
  // Wait until data can be read without blocking.
680
 
  template <typename Handler>
681
 
  void async_read_some(implementation_type& impl,
682
 
      const null_buffers&, Handler handler)
683
 
  {
684
 
    if (!is_open(impl))
685
 
    {
686
 
      this->get_io_service().post(bind_handler(handler,
687
 
            asio::error::bad_descriptor, 0));
688
 
    }
689
 
    else
690
 
    {
691
 
      reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
692
 
          null_buffers_operation<Handler>(this->get_io_service(), handler),
693
 
          false);
694
 
    }
695
 
  }
696
 
 
697
 
private:
698
 
  // The selector that performs event demultiplexing for the service.
699
 
  Reactor& reactor_;
700
 
};
701
 
 
702
 
} // namespace detail
703
 
} // namespace asio
704
 
 
705
 
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
706
 
 
707
 
#include "asio/detail/pop_options.hpp"
708
 
 
709
 
#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP