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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2008-07-02 10:46:21 UTC
  • Revision ID: james.westby@ubuntu.com-20080702104621-jzx3pfke9lkcxfxn
Tags: upstream-0.13.1
ImportĀ upstreamĀ versionĀ 0.13.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// reactor_op_queue.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_REACTOR_OP_QUEUE_HPP
 
12
#define ASIO_DETAIL_REACTOR_OP_QUEUE_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/detail/push_options.hpp"
 
21
#include <memory>
 
22
#include "asio/detail/pop_options.hpp"
 
23
 
 
24
#include "asio/error.hpp"
 
25
#include "asio/detail/hash_map.hpp"
 
26
#include "asio/detail/noncopyable.hpp"
 
27
 
 
28
namespace asio {
 
29
namespace detail {
 
30
 
 
31
template <typename Descriptor>
 
32
class reactor_op_queue
 
33
  : private noncopyable
 
34
{
 
35
public:
 
36
  // Constructor.
 
37
  reactor_op_queue()
 
38
    : operations_(),
 
39
      cancelled_operations_(0),
 
40
      cleanup_operations_(0)
 
41
  {
 
42
  }
 
43
 
 
44
  // Add a new operation to the queue. Returns true if this is the only
 
45
  // operation for the given descriptor, in which case the reactor's event
 
46
  // demultiplexing function call may need to be interrupted and restarted.
 
47
  template <typename Handler>
 
48
  bool enqueue_operation(Descriptor descriptor, Handler handler)
 
49
  {
 
50
    op_base* new_op = new op<Handler>(descriptor, handler);
 
51
 
 
52
    typedef typename operation_map::iterator iterator;
 
53
    typedef typename operation_map::value_type value_type;
 
54
    std::pair<iterator, bool> entry =
 
55
      operations_.insert(value_type(descriptor, new_op));
 
56
    if (entry.second)
 
57
      return true;
 
58
 
 
59
    op_base* current_op = entry.first->second;
 
60
    while (current_op->next_)
 
61
      current_op = current_op->next_;
 
62
    current_op->next_ = new_op;
 
63
 
 
64
    return false;
 
65
  }
 
66
 
 
67
  // Cancel all operations associated with the descriptor. Any operations
 
68
  // pending for the descriptor will be notified that they have been cancelled
 
69
  // next time dispatch_cancellations is called. Returns true if any operations
 
70
  // were cancelled, in which case the reactor's event demultiplexing function
 
71
  // may need to be interrupted and restarted.
 
72
  bool cancel_operations(Descriptor descriptor)
 
73
  {
 
74
    typename operation_map::iterator i = operations_.find(descriptor);
 
75
    if (i != operations_.end())
 
76
    {
 
77
      op_base* last_op = i->second;
 
78
      while (last_op->next_)
 
79
        last_op = last_op->next_;
 
80
      last_op->next_ = cancelled_operations_;
 
81
      cancelled_operations_ = i->second;
 
82
      operations_.erase(i);
 
83
      return true;
 
84
    }
 
85
 
 
86
    return false;
 
87
  }
 
88
 
 
89
  // Whether there are no operations in the queue.
 
90
  bool empty() const
 
91
  {
 
92
    return operations_.empty();
 
93
  }
 
94
 
 
95
  // Determine whether there are any operations associated with the descriptor.
 
96
  bool has_operation(Descriptor descriptor) const
 
97
  {
 
98
    return operations_.find(descriptor) != operations_.end();
 
99
  }
 
100
 
 
101
  // Dispatch the first operation corresponding to the descriptor. Returns true
 
102
  // if there are more operations queued for the descriptor.
 
103
  bool dispatch_operation(Descriptor descriptor,
 
104
      const asio::error_code& result)
 
105
  {
 
106
    typename operation_map::iterator i = operations_.find(descriptor);
 
107
    if (i != operations_.end())
 
108
    {
 
109
      op_base* this_op = i->second;
 
110
      i->second = this_op->next_;
 
111
      this_op->next_ = cleanup_operations_;
 
112
      cleanup_operations_ = this_op;
 
113
      bool done = this_op->invoke(result);
 
114
      if (done)
 
115
      {
 
116
        // Operation has finished.
 
117
        if (i->second)
 
118
        {
 
119
          return true;
 
120
        }
 
121
        else
 
122
        {
 
123
          operations_.erase(i);
 
124
          return false;
 
125
        }
 
126
      }
 
127
      else
 
128
      {
 
129
        // Operation wants to be called again. Leave it at the front of the
 
130
        // queue for this descriptor, and remove from the cleanup list.
 
131
        cleanup_operations_ = this_op->next_;
 
132
        this_op->next_ = i->second;
 
133
        i->second = this_op;
 
134
        return true;
 
135
      }
 
136
    }
 
137
    return false;
 
138
  }
 
139
 
 
140
  // Dispatch all operations corresponding to the descriptor.
 
141
  void dispatch_all_operations(Descriptor descriptor,
 
142
      const asio::error_code& result)
 
143
  {
 
144
    typename operation_map::iterator i = operations_.find(descriptor);
 
145
    if (i != operations_.end())
 
146
    {
 
147
      while (i->second)
 
148
      {
 
149
        op_base* this_op = i->second;
 
150
        i->second = this_op->next_;
 
151
        this_op->next_ = cleanup_operations_;
 
152
        cleanup_operations_ = this_op;
 
153
        bool done = this_op->invoke(result);
 
154
        if (!done)
 
155
        {
 
156
          // Operation has not finished yet, so leave at front of queue, and
 
157
          // remove from the cleanup list.
 
158
          cleanup_operations_ = this_op->next_;
 
159
          this_op->next_ = i->second;
 
160
          i->second = this_op;
 
161
          return;
 
162
        }
 
163
      }
 
164
      operations_.erase(i);
 
165
    }
 
166
  }
 
167
 
 
168
  // Fill a descriptor set with the descriptors corresponding to each active
 
169
  // operation.
 
170
  template <typename Descriptor_Set>
 
171
  void get_descriptors(Descriptor_Set& descriptors)
 
172
  {
 
173
    typename operation_map::iterator i = operations_.begin();
 
174
    while (i != operations_.end())
 
175
    {
 
176
      Descriptor descriptor = i->first;
 
177
      ++i;
 
178
      if (!descriptors.set(descriptor))
 
179
      {
 
180
        asio::error_code ec(error::fd_set_failure);
 
181
        dispatch_all_operations(descriptor, ec);
 
182
      }
 
183
    }
 
184
  }
 
185
 
 
186
  // Dispatch the operations corresponding to the ready file descriptors
 
187
  // contained in the given descriptor set.
 
188
  template <typename Descriptor_Set>
 
189
  void dispatch_descriptors(const Descriptor_Set& descriptors,
 
190
      const asio::error_code& result)
 
191
  {
 
192
    typename operation_map::iterator i = operations_.begin();
 
193
    while (i != operations_.end())
 
194
    {
 
195
      typename operation_map::iterator op_iter = i++;
 
196
      if (descriptors.is_set(op_iter->first))
 
197
      {
 
198
        op_base* this_op = op_iter->second;
 
199
        op_iter->second = this_op->next_;
 
200
        this_op->next_ = cleanup_operations_;
 
201
        cleanup_operations_ = this_op;
 
202
        bool done = this_op->invoke(result);
 
203
        if (done)
 
204
        {
 
205
          if (!op_iter->second)
 
206
            operations_.erase(op_iter);
 
207
        }
 
208
        else
 
209
        {
 
210
          // Operation has not finished yet, so leave at front of queue, and
 
211
          // remove from the cleanup list.
 
212
          cleanup_operations_ = this_op->next_;
 
213
          this_op->next_ = op_iter->second;
 
214
          op_iter->second = this_op;
 
215
        }
 
216
      }
 
217
    }
 
218
  }
 
219
 
 
220
  // Dispatch any pending cancels for operations.
 
221
  void dispatch_cancellations()
 
222
  {
 
223
    while (cancelled_operations_)
 
224
    {
 
225
      op_base* this_op = cancelled_operations_;
 
226
      cancelled_operations_ = this_op->next_;
 
227
      this_op->next_ = cleanup_operations_;
 
228
      cleanup_operations_ = this_op;
 
229
      this_op->invoke(asio::error::operation_aborted);
 
230
    }
 
231
  }
 
232
 
 
233
  // Destroy operations that are waiting to be cleaned up.
 
234
  void cleanup_operations()
 
235
  {
 
236
    while (cleanup_operations_)
 
237
    {
 
238
      op_base* next_op = cleanup_operations_->next_;
 
239
      cleanup_operations_->next_ = 0;
 
240
      cleanup_operations_->destroy();
 
241
      cleanup_operations_ = next_op;
 
242
    }
 
243
  }
 
244
 
 
245
  // Destroy all operations owned by the queue.
 
246
  void destroy_operations()
 
247
  {
 
248
    while (cancelled_operations_)
 
249
    {
 
250
      op_base* next_op = cancelled_operations_->next_;
 
251
      cancelled_operations_->next_ = 0;
 
252
      cancelled_operations_->destroy();
 
253
      cancelled_operations_ = next_op;
 
254
    }
 
255
 
 
256
    while (cleanup_operations_)
 
257
    {
 
258
      op_base* next_op = cleanup_operations_->next_;
 
259
      cleanup_operations_->next_ = 0;
 
260
      cleanup_operations_->destroy();
 
261
      cleanup_operations_ = next_op;
 
262
    }
 
263
 
 
264
    typename operation_map::iterator i = operations_.begin();
 
265
    while (i != operations_.end())
 
266
    {
 
267
      typename operation_map::iterator op_iter = i++;
 
268
      op_base* curr_op = op_iter->second;
 
269
      operations_.erase(op_iter);
 
270
      while (curr_op)
 
271
      {
 
272
        op_base* next_op = curr_op->next_;
 
273
        curr_op->next_ = 0;
 
274
        curr_op->destroy();
 
275
        curr_op = next_op;
 
276
      }
 
277
    }
 
278
  }
 
279
 
 
280
private:
 
281
  // Base class for reactor operations. A function pointer is used instead of
 
282
  // virtual functions to avoid the associated overhead.
 
283
  class op_base
 
284
  {
 
285
  public:
 
286
    // Get the descriptor associated with the operation.
 
287
    Descriptor descriptor() const
 
288
    {
 
289
      return descriptor_;
 
290
    }
 
291
 
 
292
    // Perform the operation.
 
293
    bool invoke(const asio::error_code& result)
 
294
    {
 
295
      return invoke_func_(this, result);
 
296
    }
 
297
 
 
298
    // Destroy the operation.
 
299
    void destroy()
 
300
    {
 
301
      return destroy_func_(this);
 
302
    }
 
303
 
 
304
  protected:
 
305
    typedef bool (*invoke_func_type)(op_base*,
 
306
        const asio::error_code&);
 
307
    typedef void (*destroy_func_type)(op_base*);
 
308
 
 
309
    // Construct an operation for the given descriptor.
 
310
    op_base(invoke_func_type invoke_func,
 
311
        destroy_func_type destroy_func, Descriptor descriptor)
 
312
      : invoke_func_(invoke_func),
 
313
        destroy_func_(destroy_func),
 
314
        descriptor_(descriptor),
 
315
        next_(0)
 
316
    {
 
317
    }
 
318
 
 
319
    // Prevent deletion through this type.
 
320
    ~op_base()
 
321
    {
 
322
    }
 
323
 
 
324
  private:
 
325
    friend class reactor_op_queue<Descriptor>;
 
326
 
 
327
    // The function to be called to dispatch the handler.
 
328
    invoke_func_type invoke_func_;
 
329
 
 
330
    // The function to be called to delete the handler.
 
331
    destroy_func_type destroy_func_;
 
332
 
 
333
    // The descriptor associated with the operation.
 
334
    Descriptor descriptor_;
 
335
 
 
336
    // The next operation for the same file descriptor.
 
337
    op_base* next_;
 
338
  };
 
339
 
 
340
  // Adaptor class template for using handlers in operations.
 
341
  template <typename Handler>
 
342
  class op
 
343
    : public op_base
 
344
  {
 
345
  public:
 
346
    // Constructor.
 
347
    op(Descriptor descriptor, Handler handler)
 
348
      : op_base(&op<Handler>::invoke_handler,
 
349
          &op<Handler>::destroy_handler, descriptor),
 
350
        handler_(handler)
 
351
    {
 
352
    }
 
353
 
 
354
    // Invoke the handler.
 
355
    static bool invoke_handler(op_base* base,
 
356
        const asio::error_code& result)
 
357
    {
 
358
      return static_cast<op<Handler>*>(base)->handler_(result);
 
359
    }
 
360
 
 
361
    // Delete the handler.
 
362
    static void destroy_handler(op_base* base)
 
363
    {
 
364
      delete static_cast<op<Handler>*>(base);
 
365
    }
 
366
 
 
367
  private:
 
368
    Handler handler_;
 
369
  };
 
370
 
 
371
  // The type for a map of operations.
 
372
  typedef hash_map<Descriptor, op_base*> operation_map;
 
373
 
 
374
  // The operations that are currently executing asynchronously.
 
375
  operation_map operations_;
 
376
 
 
377
  // The list of operations that have been cancelled.
 
378
  op_base* cancelled_operations_;
 
379
 
 
380
  // The list of operations to be destroyed.
 
381
  op_base* cleanup_operations_;
 
382
};
 
383
 
 
384
} // namespace detail
 
385
} // namespace asio
 
386
 
 
387
#include "asio/detail/pop_options.hpp"
 
388
 
 
389
#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP