| 27 | | template <typename ThreadTag> |
| 28 | | typename coroutine<ThreadTag>::handler* coroutine<ThreadTag>::s_current = NULL; |
| 29 | | |
| 30 | | template <typename ThreadTag> |
| 31 | | std::auto_ptr< coroutine<ThreadTag> > coroutine<ThreadTag>::s_instance; |
| 32 | | |
| 33 | | |
| 34 | | template <typename ThreadTag> |
| 35 | | void coroutine<ThreadTag>::initialize() |
| 36 | | { |
| 37 | | s_instance.reset(new coroutine<ThreadTag>()); |
| 38 | | } |
| 39 | | |
| 40 | | template <typename ThreadTag> |
| 41 | | void coroutine<ThreadTag>::destroy() |
| 42 | | { |
| 43 | | coroutine<ThreadTag>::end(); |
| 44 | | s_instance.reset(NULL); |
| 45 | | } |
| 46 | | |
| 47 | | template <typename ThreadTag> |
| 48 | | coroutine<ThreadTag>::coroutine() : |
| 49 | | m_main_coro(coro_t::main()), |
| 50 | | m_end_flag(0) |
| 51 | | { |
| 52 | | // register fdnotify with NULL handler |
| 53 | | if( m_event.add(m_fdnotify.getfd(), EV_READ, (handler*)NULL) < 0 ) { |
| 54 | | throw std::runtime_error("add fdnotify failed"); |
| 55 | | } |
| 56 | | } |
| 57 | | |
| 58 | | |
| 59 | | template <typename ThreadTag> |
| 60 | | coroutine<ThreadTag>::~coroutine() |
| | 27 | template <typename IMPL> |
| | 28 | fiber::handler::handler(IMPL* pimpl) : |
| | 29 | current_fd(-1), |
| | 30 | context( |
| | 31 | &object_callback<void ()>::mem_fun<IMPL, &IMPL::operator()>, |
| | 32 | pimpl |
| | 33 | ) |
| 64 | | template <typename ThreadTag> |
| 65 | | int coroutine<ThreadTag>::run_impl() |
| 66 | | { |
| 67 | | int fd; |
| 68 | | short event; |
| 69 | | while(!m_end_flag) { |
| 70 | | |
| 71 | | // event notify |
| 72 | | while( m_event.next(&fd, &event) ) { |
| 73 | | |
| 74 | | if( fd == m_fdnotify.getfd() ) { |
| 75 | | // event on fdnotify |
| 76 | | // receive waked handler |
| 77 | | handler* waked; |
| 78 | | while( m_fdnotify.try_receive(&waked) ) { |
| 79 | | if( waked != NULL ) { // wake == NULL means interrupt |
| 80 | | call_handler(*waked); |
| 81 | | } |
| 82 | | } |
| 83 | | |
| 84 | | } else { |
| 85 | | // event on fd |
| 86 | | cb_t& cb( m_event.data(fd) ); |
| 87 | | call_handler(cb.get()); |
| 88 | | } |
| 89 | | } |
| 90 | | |
| 91 | | // join notify |
| 92 | | while( !m_join_notify.empty() ) { |
| 93 | | join_notify_t tmp; |
| 94 | | tmp.swap(m_join_notify); // now m_join_notify is empty |
| 95 | | for(typename join_notify_t::iterator it(tmp.begin()), it_end(tmp.end()); |
| 96 | | it != it_end; |
| 97 | | ++it) { |
| 98 | | call_handler( *(*it) ); |
| 99 | | } |
| 100 | | } |
| 101 | | |
| 102 | | // wait event |
| 103 | | if( m_event.wait() < 0 ) { |
| 104 | | return -1; |
| 105 | | } |
| 106 | | |
| 107 | | } |
| 108 | | |
| 109 | | return 0; |
| 110 | | } |
| 111 | | |
| 112 | | template <typename ThreadTag> |
| 113 | | void coroutine<ThreadTag>::call_handler(handler& target) |
| 114 | | { |
| 115 | | s_current = ⌖ |
| 116 | | m_main_coro.spawn( target.get_coro() ); |
| 117 | | if( target.exited() ) { |
| 118 | | std::copy(target.waited.begin(), |
| 119 | | target.waited.end(), |
| 120 | | std::back_inserter(m_join_notify)); |
| 121 | | if( target.current_fd >= 0 ) { |
| 122 | | remove(target); |
| 123 | | } |
| 124 | | } |
| 125 | | } |
| 126 | | |
| 127 | | |
| 128 | | template <typename ThreadTag> |
| 129 | | void coroutine<ThreadTag>::end_impl() |
| 130 | | try { |
| 131 | | if(m_end_flag) { return; } |
| 132 | | m_end_flag = 1; |
| 133 | | interrupt_impl(); |
| 134 | | } catch (...) |
| 135 | | { } |
| 136 | | |
| 137 | | |
| 138 | | template <typename ThreadTag> |
| 139 | | template <typename IMPL> |
| 140 | | coroutine<ThreadTag>::handler::handler(IMPL* pimpl) : |
| 141 | | current_fd(-1), |
| 142 | | m_coro( |
| 143 | | &object_callback<void ()>::mem_fun<IMPL, &IMPL::operator()>, |
| 144 | | pimpl |
| 145 | | ) |
| 146 | | {} |
| 147 | | |
| 148 | | template <typename ThreadTag> |
| 149 | | coroutine<ThreadTag>::handler::~handler() {} |
| 150 | | |
| 151 | | |
| 152 | | template <typename ThreadTag> |
| 153 | | void coroutine<ThreadTag>::add_handler_impl(int fd, short event, handler& routine) |
| 154 | | { |
| 155 | | add(routine, fd, event); |
| 156 | | } |
| 157 | | |
| 158 | | |
| 159 | | template <typename ThreadTag> |
| 160 | | void coroutine<ThreadTag>::yield_impl(int fd, short event) |
| 161 | | { |
| 162 | | handler& self(*s_current); |
| 163 | | |
| 164 | | // modify current state |
| 165 | | if( self.current_event >= 0 ) { |
| 166 | | |
| 167 | | if( fd == self.current_fd ) { |
| 168 | | // same fd and ... |
| 169 | | if( self.current_event == event ) { |
| 170 | | // same event, modify nothing |
| 171 | | goto next; |
| 172 | | } |
| 173 | | |
| 174 | | // different event, modify event |
| 175 | | modify(self, event); |
| 176 | | goto next; |
| 177 | | |
| 178 | | } else { |
| 179 | | // different fd, change fd |
| 180 | | remove(self); |
| 181 | | add(self, fd, event); |
| 182 | | } |
| 183 | | |
| 184 | | // add new event |
| 185 | | } else { |
| 186 | | add(self, fd, event); |
| 187 | | } |
| 188 | | |
| 189 | | next: |
| 190 | | self.yield(); |
| 191 | | } |
| 192 | | |
| 193 | | |
| 194 | | template <typename ThreadTag> |
| 195 | | void coroutine<ThreadTag>::suspend_impl() |
| 196 | | { |
| 197 | | handler& self(*s_current); |
| 198 | | if( self.current_event >= 0 ) { |
| 199 | | remove(self); |
| 200 | | } |
| 201 | | self.yield(); |
| 202 | | } |
| 203 | | |
| 204 | | |
| 205 | | template <typename ThreadTag> |
| 206 | | void coroutine<ThreadTag>::join_impl(handler& target) |
| 207 | | { |
| 208 | | if(target.exited()) { return; } |
| 209 | | handler& self(*s_current); |
| 210 | | target.waited.push_back(&self); |
| 211 | | suspend_impl(); |
| 212 | | } |
| 213 | | |
| 214 | | |
| 215 | | template <typename ThreadTag> |
| 216 | | void coroutine<ThreadTag>::wake_impl(handler& target) |
| 217 | | { |
| 218 | | m_fdnotify.send(&target); |
| 219 | | } |
| 220 | | |
| 221 | | |
| 222 | | template <typename ThreadTag> |
| 223 | | void coroutine<ThreadTag>::interrupt_impl() |
| 224 | | { |
| 225 | | m_fdnotify.send((handler*)NULL); |
| 226 | | } |
| 227 | | |
| 228 | | |
| 229 | | template <typename ThreadTag> |
| 230 | | bool coroutine<ThreadTag>::test_impl(int fd) |
| 231 | | { |
| 232 | | return m_event.test(fd); |
| 233 | | } |
| 234 | | |
| 235 | | |
| 236 | | template <typename ThreadTag> |
| 237 | | void coroutine<ThreadTag>::modify(handler& target, short event) |
| 238 | | { |
| 239 | | if( m_event.modify(target.current_fd, target.current_event, event) < 0 ) { |
| 240 | | throw std::runtime_error("modify failed"); |
| 241 | | } |
| 242 | | target.current_event = event; |
| 243 | | } |
| 244 | | |
| 245 | | |
| 246 | | template <typename ThreadTag> |
| 247 | | void coroutine<ThreadTag>::add(handler& target, int fd, short event) |
| 248 | | { |
| 249 | | if( m_event.add(fd, event, &target) < 0 ) { |
| 250 | | throw std::runtime_error("add failed"); |
| 251 | | } |
| 252 | | target.current_fd = fd; |
| 253 | | target.current_event = event; |
| 254 | | } |
| 255 | | |
| 256 | | template <typename ThreadTag> |
| 257 | | void coroutine<ThreadTag>::remove(handler& target) |
| 258 | | { |
| 259 | | // ignore error |
| 260 | | m_event.remove(target.current_fd, target.current_event); |
| 261 | | target.current_fd = -1; |
| 262 | | } |
| | 37 | inline fiber::handler::~handler() { } |