Loading src/event/epoll.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -350,7 +350,8 @@ namespace netplus { // Cache fd early; after close it may be invalid / reused int fd = -1; if (ccon->csock) fd = ccon->csock->fd(); if (ccon->csock) fd = ccon->csock->fd(); // 1) Remove from epoll (ignore ENOENT / EBADF) if (fd >= 0) { Loading src/event/kqueue.cpp +20 −41 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ namespace netplus { std::mutex POLL_HANDLER_MUTEX; std::vector<socket*> SSOCKETS; std::map<int,con*> CONNECTIONS; std::map<int,std::shared_ptr<con>> CONNECTIONS; class pollapi { public: Loading Loading @@ -357,59 +357,38 @@ namespace netplus { } void CloseEventHandler(int pos, const int tid, ULONG_PTR args) { con* ccon = reinterpret_cast<con*>(_Events[pos].udata); if (!ccon) return; // Lock connection first (so nobody is inside Read/Write handler), // then take global map lock later. std::unique_lock<std::mutex> conn_lock(ccon->event_mutex); con* raw_ptr = reinterpret_cast<con*>(_Events[pos].udata); if (!raw_ptr) return; // Cache fd early; after close it may be invalid. int fd = -1; if (ccon->csock) fd = ccon->csock->fd(); std::shared_ptr<con> ccon; // 1) Remove from kqueue (ignore ENOENT) { std::lock_guard<std::mutex> global_lock(POLL_HANDLER_MUTEX); int fd = (raw_ptr->csock) ? raw_ptr->csock->fd() : -1; if (fd >= 0) { struct kevent kev[2]; EV_SET(&kev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr); EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr); // kevent can return -1 even if one filter didn't exist; treat ENOENT as OK. if (kevent(_pollFD, kev, 2, nullptr, 0, nullptr) < 0) { if (errno != ENOENT) { NetException except; char errstr[255]; strerror_r_netplus(errno, errstr, 255); except[NetException::Error] << "CloseEventHandler: failed to remove fd from kqueue: " << errstr; // continue cleanup anyway auto it = CONNECTIONS.find(fd); if (it != CONNECTIONS.end()) { ccon = it->second; CONNECTIONS.erase(it); } } } // 2) Inform application layer (do this before freeing/closing state) if (!ccon) return; std::unique_lock<std::mutex> conn_lock(ccon->event_mutex); try { evconnection->DisconnectEvent(*ccon, tid, args); } catch (...) { // don't let DisconnectEvent prevent cleanup } } catch (...) {} // 3) Close socket if (ccon->csock) { try { ccon->csock->close(); } catch (...) {} } // 4) Remove from global map (use cached fd; csock may be gone) { std::lock_guard<std::mutex> global_lock(POLL_HANDLER_MUTEX); if (fd >= 0) CONNECTIONS.erase(fd); try { ccon->csock->close(); } catch (...) {} } // 5) Clear event slot udata so it can’t be reused accidentally _Events[pos].udata = nullptr; // 6) Destroy connection object conn_lock.unlock(); delete ccon; } private: Loading Loading
src/event/epoll.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -350,7 +350,8 @@ namespace netplus { // Cache fd early; after close it may be invalid / reused int fd = -1; if (ccon->csock) fd = ccon->csock->fd(); if (ccon->csock) fd = ccon->csock->fd(); // 1) Remove from epoll (ignore ENOENT / EBADF) if (fd >= 0) { Loading
src/event/kqueue.cpp +20 −41 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ namespace netplus { std::mutex POLL_HANDLER_MUTEX; std::vector<socket*> SSOCKETS; std::map<int,con*> CONNECTIONS; std::map<int,std::shared_ptr<con>> CONNECTIONS; class pollapi { public: Loading Loading @@ -357,59 +357,38 @@ namespace netplus { } void CloseEventHandler(int pos, const int tid, ULONG_PTR args) { con* ccon = reinterpret_cast<con*>(_Events[pos].udata); if (!ccon) return; // Lock connection first (so nobody is inside Read/Write handler), // then take global map lock later. std::unique_lock<std::mutex> conn_lock(ccon->event_mutex); con* raw_ptr = reinterpret_cast<con*>(_Events[pos].udata); if (!raw_ptr) return; // Cache fd early; after close it may be invalid. int fd = -1; if (ccon->csock) fd = ccon->csock->fd(); std::shared_ptr<con> ccon; // 1) Remove from kqueue (ignore ENOENT) { std::lock_guard<std::mutex> global_lock(POLL_HANDLER_MUTEX); int fd = (raw_ptr->csock) ? raw_ptr->csock->fd() : -1; if (fd >= 0) { struct kevent kev[2]; EV_SET(&kev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr); EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr); // kevent can return -1 even if one filter didn't exist; treat ENOENT as OK. if (kevent(_pollFD, kev, 2, nullptr, 0, nullptr) < 0) { if (errno != ENOENT) { NetException except; char errstr[255]; strerror_r_netplus(errno, errstr, 255); except[NetException::Error] << "CloseEventHandler: failed to remove fd from kqueue: " << errstr; // continue cleanup anyway auto it = CONNECTIONS.find(fd); if (it != CONNECTIONS.end()) { ccon = it->second; CONNECTIONS.erase(it); } } } // 2) Inform application layer (do this before freeing/closing state) if (!ccon) return; std::unique_lock<std::mutex> conn_lock(ccon->event_mutex); try { evconnection->DisconnectEvent(*ccon, tid, args); } catch (...) { // don't let DisconnectEvent prevent cleanup } } catch (...) {} // 3) Close socket if (ccon->csock) { try { ccon->csock->close(); } catch (...) {} } // 4) Remove from global map (use cached fd; csock may be gone) { std::lock_guard<std::mutex> global_lock(POLL_HANDLER_MUTEX); if (fd >= 0) CONNECTIONS.erase(fd); try { ccon->csock->close(); } catch (...) {} } // 5) Clear event slot udata so it can’t be reused accidentally _Events[pos].udata = nullptr; // 6) Destroy connection object conn_lock.unlock(); delete ccon; } private: Loading