coroutine.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //
  2. // coroutine.h
  3. // ~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2010 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. #ifndef COROUTINE_HPP
  11. #define COROUTINE_HPP
  12. // \brief Coroutine object
  13. //
  14. // A coroutine object maintains the state of a re-enterable routine. It
  15. // is assignable and copy-constructible, and can be used as a base class
  16. // for a class that uses it, or as a data member. The copy overhead is
  17. // a single int.
  18. //
  19. // A reentrant function contains a CORO_REENTER (coroutine) { ... }
  20. // block. Whenever an asychrnonous operation is initiated within the
  21. // routine, the function is provided as the handler object. (The simplest
  22. // way to do this is to have the reentrant function be the operator()
  23. // member for the coroutine object itself.) For example:
  24. //
  25. // CORO_YIELD socket->async_read_some(buffer, *this);
  26. //
  27. // The CORO_YIELD keyword updates the current status of the coroutine to
  28. // indicate the line number currently being executed. The
  29. // async_read_some() call is initiated, with a copy of the updated
  30. // coroutine as its handler object, and the current coroutine exits. When
  31. // the async_read_some() call finishes, the copied coroutine will be
  32. // called, and will resume processing exactly where the original one left
  33. // off--right after asynchronous call. This allows asynchronous I/O
  34. // routines to be written with a logical flow, step following step, rather
  35. // than as a linked chain of separate handler functions.
  36. //
  37. // When necessary, a coroutine can fork itself using the CORO_FORK keyword.
  38. // This updates the status of the coroutine and makes a copy. The copy can
  39. // then be called directly or posted to the ASIO service queue so that both
  40. // coroutines will continue forward, one "parent" and one "child". The
  41. // is_parent() and is_child() methods indicate which is which.
  42. //
  43. // The CORO_REENTER, CORO_YIELD and CORO_FORK keywords are implemented
  44. // via preprocessor macros. The CORO_REENTER block is actually a large,
  45. // complex switch statement. Because of this, inline variable declaration
  46. // is impossible within CORO_REENTER unless it is done in a subsidiary
  47. // scope--and if it is, that scope cannot contain CORO_YIELD or CORO_FORK
  48. // keywords.
  49. //
  50. // Because coroutines are frequently copied, it is best to minimize copy
  51. // overhead by limiting the size of data members in derived classes.
  52. //
  53. // It should be noted that when a coroutine falls out of scope its memory
  54. // is reclaimed, even though it may be scheduled to resume when an
  55. // asynchronous operation completes. Any shared_ptr<> objects declared in
  56. // the coroutine may be destroyed if their reference count drops to zero,
  57. // in which case the coroutine will have serious problems once it resumes.
  58. // One solution so this is to have the space that will be used by a
  59. // coroutine pre-allocated and stored on a free list; a new coroutine can
  60. // fetch the block of space off a free list, place a shared pointer to it
  61. // on an "in use" list, and carry on. The reference in the "in use" list
  62. // would prevent the data from being destroyed.
  63. class coroutine
  64. {
  65. public:
  66. coroutine() : value_(0) {}
  67. virtual ~coroutine() {}
  68. bool is_child() const { return value_ < 0; }
  69. bool is_parent() const { return !is_child(); }
  70. bool is_complete() const { return value_ == -1; }
  71. int get_value() const { return value_; }
  72. private:
  73. friend class coroutine_ref;
  74. int value_;
  75. };
  76. class coroutine_ref
  77. {
  78. public:
  79. coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
  80. coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
  81. ~coroutine_ref() { if (!modified_) value_ = -1; }
  82. operator int() const { return value_; }
  83. int& operator=(int v) { modified_ = true; return value_ = v; }
  84. private:
  85. void operator=(const coroutine_ref&);
  86. int& value_;
  87. bool modified_;
  88. };
  89. #define CORO_REENTER(c) \
  90. switch (coroutine_ref _coro_value = c) \
  91. case -1: if (_coro_value) \
  92. { \
  93. goto terminate_coroutine; \
  94. terminate_coroutine: \
  95. _coro_value = -1; \
  96. goto bail_out_of_coroutine; \
  97. bail_out_of_coroutine: \
  98. break; \
  99. } \
  100. else case 0:
  101. #define CORO_YIELD \
  102. for (_coro_value = __LINE__;;) \
  103. if (_coro_value == 0) \
  104. { \
  105. case __LINE__: ; \
  106. break; \
  107. } \
  108. else \
  109. switch (_coro_value ? 0 : 1) \
  110. for (;;) \
  111. case -1: if (_coro_value) \
  112. goto terminate_coroutine; \
  113. else for (;;) \
  114. case 1: if (_coro_value) \
  115. goto bail_out_of_coroutine; \
  116. else case 0:
  117. #define CORO_FORK \
  118. for (_coro_value = -__LINE__;; _coro_value = __LINE__) \
  119. if (_coro_value == __LINE__) \
  120. { \
  121. case -__LINE__: ; \
  122. break; \
  123. } \
  124. else
  125. #endif // COROUTINE_HPP