1111namespace hv {
1212
1313template <class TSocketChannel = SocketChannel>
14+ // TcpServerEventLoopTmpl is a loop-bound wrapper around one listening socket and its accepted channels.
15+ // When an external EventLoopPtr is supplied, the caller remains responsible for owner-loop shutdown and destruction ordering.
1416class TcpServerEventLoopTmpl {
1517public:
1618 typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
@@ -74,6 +76,7 @@ class TcpServerEventLoopTmpl {
7476 }
7577
7678 int startAccept () {
79+ acceptor_loop->assertInLoopThread ();
7780 if (listenfd < 0 ) {
7881 listenfd = createsocket (port, host.c_str ());
7982 if (listenfd < 0 ) {
@@ -101,6 +104,7 @@ class TcpServerEventLoopTmpl {
101104 }
102105
103106 int stopAccept () {
107+ acceptor_loop->assertInLoopThread ();
104108 if (listenfd < 0 ) return -1 ;
105109 hloop_t * loop = acceptor_loop->loop ();
106110 if (loop == NULL ) return -2 ;
@@ -117,6 +121,7 @@ class TcpServerEventLoopTmpl {
117121 acceptor_loop->runInLoop (std::bind (&TcpServerEventLoopTmpl::startAccept, this ));
118122 }
119123 // stop thread-safe
124+ // NOTE: When an external loop is supplied, this closes the listener but does not own that loop's lifetime.
120125 void stop (bool wait_threads_stopped = true ) {
121126 closesocket ();
122127 if (worker_threads.threadNum () > 0 ) {
@@ -173,6 +178,7 @@ class TcpServerEventLoopTmpl {
173178 return channels.size ();
174179 }
175180
181+ // NOTE: fn is executed while holding mutex_, so it must stay short and must not call server APIs that may lock channels again.
176182 int foreachChannel (std::function<void (const TSocketChannelPtr& channel)> fn) {
177183 std::lock_guard<std::mutex> locker (mutex_);
178184 for (auto & pair : channels) {
@@ -194,16 +200,19 @@ class TcpServerEventLoopTmpl {
194200
195201private:
196202 static void newConnEvent (hio_t * connio) {
203+ assert (connio != NULL );
197204 TcpServerEventLoopTmpl* server = (TcpServerEventLoopTmpl*)hevent_userdata (connio);
205+ assert (server != NULL );
206+ EventLoop* worker_loop = currentThreadEventLoop;
207+ assert (worker_loop != NULL );
198208 if (server->connectionNum () >= server->max_connections ) {
209+ --worker_loop->connectionNum ;
199210 hlogw (" over max_connections" );
200211 hio_close (connio);
201212 return ;
202213 }
203214
204215 // NOTE: attach to worker loop
205- EventLoop* worker_loop = currentThreadEventLoop;
206- assert (worker_loop != NULL );
207216 hio_attach (worker_loop->loop (), connio);
208217
209218 const TSocketChannelPtr& channel = server->addChannel (connio);
@@ -229,7 +238,7 @@ class TcpServerEventLoopTmpl {
229238 server->onConnection (channel);
230239 }
231240 server->removeChannel (channel);
232- // NOTE: After removeChannel, channel may be destroyed,
241+ // NOTE: After removeChannel, channel may be destroyed immediately ,
233242 // so in this lambda function, no code should be added below.
234243 };
235244
0 commit comments