void Dispatcher::AddWrite(net::Connection& _c, const Callback& write_cb) { assert(dynamic_cast<Connection*>(&_c)); Connection& c = static_cast<Connection&>(_c); std::unique_lock<std::mutex> d_lock(d_->mutex_); Watch& w = GetWatch(&c); w.write_cb.emplace_back(write_cb); if (!w.active) { std::unique_lock<std::mutex> c_lock(c.d_->mutex_); c.d_->watcher_.insert(this); w.active = true; } // our virtual sockets are always writable: issue notification. Notify(&c); }
//! Register a buffered read callback and a default exception callback. void Dispatcher::AddRead(net::Connection& _c, const Callback& read_cb) { assert(dynamic_cast<Connection*>(&_c)); Connection& c = static_cast<Connection&>(_c); std::unique_lock<std::mutex> d_lock(d_->mutex_); Watch& w = GetWatch(&c); w.read_cb.emplace_back(read_cb); if (!w.active) { std::unique_lock<std::mutex> c_lock(c.d_->mutex_); c.d_->watcher_.insert(this); w.active = true; // if already have a packet, issue notification. if (c.d_->inbound_.size()) Notify(&c); } }
void Dispatcher::DispatchOne(const std::chrono::milliseconds& timeout) { Connection* c = nullptr; if (!notify_.pop_for(c, timeout)) { sLOG << "DispatchOne timeout"; return; } if (c == nullptr) { sLOG << "DispatchOne interrupt"; return; } sLOG << "DispatchOne run"; std::unique_lock<std::mutex> d_lock(mutex_); Map::iterator it = map_.find(c); if (it == map_.end()) { sLOG << "DispatchOne expired connection?"; return; } Watch& w = it->second; assert(w.active); std::unique_lock<std::mutex> c_lock(c->mutex_); // check for readability if (w.read_cb.size() && c->inbound_.size()) { while (c->inbound_.size() && w.read_cb.size()) { c_lock.unlock(); d_lock.unlock(); bool ret = true; try { ret = w.read_cb.front()(); } catch (std::exception& e) { LOG1 << "Dispatcher: exception " << typeid(e).name() << "in read callback."; LOG1 << " what(): " << e.what(); throw; } d_lock.lock(); c_lock.lock(); if (ret) break; w.read_cb.pop_front(); } if (w.read_cb.size() == 0 && w.write_cb.size() == 0) { // if all callbacks are done, listen no longer. c->watcher_.erase(this); map_.erase(it); return; } } // "check" for writable. virtual sockets are always writable. if (w.write_cb.size()) { while (w.write_cb.size()) { c_lock.unlock(); d_lock.unlock(); bool ret = true; try { ret = w.write_cb.front()(); } catch (std::exception& e) { LOG1 << "Dispatcher: exception " << typeid(e).name() << "in write callback."; LOG1 << " what(): " << e.what(); throw; } d_lock.lock(); c_lock.lock(); if (ret) break; w.write_cb.pop_front(); } if (w.read_cb.size() == 0 && w.write_cb.size() == 0) { // if all callbacks are done, listen no longer. c->watcher_.erase(this); map_.erase(it); return; } } }