In UDT, epoll processes the CLOSE state and udtepollclose state.
When epoll_wait () returns the available uid, it obtains the status of the uid, which should have been BROKEN but CLOSED. However, CLOSED events cannot be handled like BROKEN events, and CLOSED events cannot be removed, therefore, epoll_wait continuously returns the uid, resulting in an endless loop. Trace the code to the underlying layer to find the cause. Int CUDTUnited: epoll_remove_usock (const int eid, const UDTSOCKET u) {int ret = m_EPoll.remove_usock (eid, u); CUDTSocket * s = locate (u); if (NULL! = S) {s-> m_pUDT-> removeEPoll (eid);} // else // {// throw CUDTException (5, 4); //} return ret ;} CUDTSocket * CUDTUnited: locate (const UDTSOCKET u) {CGuard cg (m_ControlLock); map <UDTSOCKET, CUDTSocket * >:: iterator I = m_Sockets.find (u ); if (I = m_Sockets.end () | (I-> second-> m_Status = CLOSED) return NULL; return I-> second;} void CUDT :: removeEPoll (const int eid) {// clear IO events configurations; // Since this happens after the epoll ID has been removed, they cannot be set again set <int> remove; remove. insert (eid); values (m_SocketID, remove, UDT_EPOLL_IN | UDT_EPOLL_OUT, false); CGuard: enterCS (region); m_spolspon.erase (eid); CGuard: leaveCS (region );} in CUDTUnited: epoll_remove_usock, first locate the current uid location, but if the uid status is CLO SED, then NULL is returned. Therefore, epoll_remove_usock cannot continue to call removeEPoll, so the epoll event cannot be removed. But why is a CLOSED event? According to the author's original intention, only the BROKEN event will occur and the CLOSED event will not occur. Continue to find the cause. First, let's see how the BROKEN event happened. After the client is suspected to be disconnected for more than 10 seconds, CUDT: checkTimers () will perform the following operations ...... ...... M_bClosing = true; m_bBroken = true; m_iBrokenCounter = 30; // update snd U list to remove this socket m_pSndQueue-> m_pSndUList-> update (this); releaseSynch (); // app can call any udt api to learn the connection_broken error Response (m_SocketID, m_sPollID, UDT_EPOLL_IN | UDT_EPOLL_OUT | expiration, true); CTimer: triggerEvent ();...... ...... Here, m_bBroken is set to true and the epoll event is triggered. However, this may occur before epoll_wait returns an event: # ifndef WIN32 void * CUDTUnited: garbageCollect (void * p) # else dword winapi CUDTUnited: garbageCollect (LPVOID p) # endif {CUDTUnited * self = (CUDTUnited *) p; CGuard gcguard (self-> m_GCStopLock); while (! Self-> m_bClosing) {self-> checkBrokenSockets ();...... ...... Void CUDTUnited: checkBrokenSockets () {CGuard cg (m_ControlLock); // set of sockets To Be Closed and To Be Removed vector <UDTSOCKET> tbc; vector <UDTSOCKET> tbr; for (map <UDTSOCKET, CUDTSocket *>: iterator I = m_Sockets.begin (); I! = M_Sockets.end (); ++ I) {// check broken connection if (I-> second-> m_pUDT-> m_bBroken) {if (I-> second-> m_Status = LISTENING) {// for a listening socket, it shoshould wait an extra 3 seconds in case a client is ing if (CTimer :: getTime ()-I-> second-> m_TimeStamp <3000000) continue;} else if (I-> second-> m_pUDT-> m_pRcvBuffer! = NULL) & (I-> second-> m_pUDT-> m_pRcvBuffer-> getRcvDataSize ()> 0) & (I-> second-> m_pUDT-> m_iBrokenCounter --> 0) {// if there is still data in the worker er buffer, wait longer continue ;} // close broken connections and start removal timer I-> second-> m_Status = CLOSED; I-> second-> m_TimeStamp = CTimer: getTime (); tbc. push_back (I-> first); m_ClosedSockets [I-> first] = I-> second ;............ The GC thread is the garbage collection process of UDT. Before the UDT calls cleanup (), it will remain in the checkBrokenSocket and blocking loop. Then, in checkBrokenSocket, when m_bBroken of socket is set to true, m_Status is set to CLOSED. Therefore, when getsocketstate is used to retrieve the socket state, CLOSED will be obtained, that is, the BROKEN event is clearly a CLOSED event! Then, the epoll event fails to be removed. So modify the int CEPoll: remove_usock (const int eid, const UDTSOCKET & u) {CGuard pg (m_EPollLock); map <int, CEPollDesc> :: iterator p = m_mPolls.find (eid); if (p = m_mPolls.end () throw CUDTException (5, 13); p-> second. m_sUDTSocksIn.erase (u); p-> second. m_sUDTSocksOut.erase (u); p-> second. m_sUDTSocksEx.erase (u); return 0;} changed to int CEPoll: remove_usock2 (const int eid, const UDTSOCKET & u) {CGuard pg (m_EPollLock ); Map <int, CEPollDesc >:: iterator p = m_mPolls.find (eid); if (p = m_mPolls.end () throw CUDTException (5, 13); p-> second. m_sUDTSocksIn.erase (u); p-> second. m_sUDTSocksOut.erase (u); p-> second. m_sUDTSocksEx.erase (u); p-> second. m_sUDTWrites.erase (u); p-> second. m_sUDTReads.erase (u); p-> second. m_sUDTExcepts.erase (u); return 0;} and remove the call to removeEPoll () from CUDTUnited: epoll_remove_usock. This is a relatively simple and rough change method. It should be more convenient.