#define SRT_IMPORT_EVENT
#include "platform_sys.h"
#include <algorithm>
#include <cerrno>
#include <cstring>
#include <iterator>
#include "common.h"
#include "epoll.h"
#include "logging.h"
#include "udt.h"
#include "logging.h"
using namespace std;
using namespace srt::sync;
#if ENABLE_HEAVY_LOGGING
static ostream& PrintEpollEvent(ostream& os, int events, int et_events = 0);
#endif
namespace srt_logging
{
extern Logger eilog, ealog;
}
using namespace srt_logging;
#if ENABLE_HEAVY_LOGGING
#define IF_DIRNAME(tested, flag, name) (tested & flag ? name : "")
#endif
CEPoll::CEPoll():
m_iIDSeed(0)
{
setupMutex(m_EPollLock, "EPoll");
}
CEPoll::~CEPoll()
{
releaseMutex(m_EPollLock);
}
int CEPoll::create(CEPollDesc** pout)
{
ScopedLock pg(m_EPollLock);
if (++ m_iIDSeed >= 0x7FFFFFFF)
m_iIDSeed = 0;
if (m_mPolls.find(m_iIDSeed) != m_mPolls.end())
throw CUDTException(MJ_SETUP, MN_NONE);
int localid = 0;
#ifdef LINUX
localid = epoll_create(1024);
if (localid < 0)
throw CUDTException(MJ_SETUP, MN_NONE, errno);
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
localid = kqueue();
if (localid < 0)
throw CUDTException(MJ_SETUP, MN_NONE, errno);
#else
#endif
pair<map<int, CEPollDesc>::iterator, bool> res = m_mPolls.insert(make_pair(m_iIDSeed, CEPollDesc(m_iIDSeed, localid)));
if (!res.second) throw CUDTException(MJ_SETUP, MN_NONE);
if (pout)
*pout = &res.first->second;
return m_iIDSeed;
}
int CEPoll::clear_usocks(int eid)
{
ScopedLock pg (m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
CEPollDesc& d = p->second;
d.clearAll();
return 0;
}
void CEPoll::clear_ready_usocks(CEPollDesc& d, int direction)
{
if ((direction & ~SRT_EPOLL_EVENTTYPES) != 0)
{
LOGC(eilog.Error, log << "CEPoll::clear_ready_usocks: IPE, event flags exceed event types: " << direction);
return;
}
ScopedLock pg (m_EPollLock);
vector<SRTSOCKET> cleared;
CEPollDesc::enotice_t::iterator i = d.enotice_begin();
while (i != d.enotice_end())
{
IF_HEAVY_LOGGING(SRTSOCKET subsock = i->fd);
SRTSOCKET rs = d.clearEventSub(i++, direction);
if (rs != SRT_INVALID_SOCK)
{
HLOGC(eilog.Debug, log << "CEPoll::clear_ready_usocks: @" << rs << " got all subscription cleared");
cleared.push_back(rs);
}
else
{
HLOGC(eilog.Debug, log << "CEPoll::clear_ready_usocks: @" << subsock << " is still subscribed");
}
}
for (size_t i = 0; i < cleared.size(); ++i)
d.removeSubscription(cleared[i]);
}
int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
#ifdef LINUX
epoll_event ev;
memset(&ev, 0, sizeof(epoll_event));
if (NULL == events)
ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
else
{
ev.events = 0;
if (*events & SRT_EPOLL_IN)
ev.events |= EPOLLIN;
if (*events & SRT_EPOLL_OUT)
ev.events |= EPOLLOUT;
if (*events & SRT_EPOLL_ERR)
ev.events |= EPOLLERR;
}
ev.data.fd = s;
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_ADD, s, &ev) < 0)
throw CUDTException();
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
struct kevent ke[2];
int num = 0;
if (NULL == events)
{
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
}
else
{
if (*events & SRT_EPOLL_IN)
{
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
}
if (*events & SRT_EPOLL_OUT)
{
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
}
}
if (kevent(p->second.m_iLocalID, ke, num, NULL, 0, NULL) < 0)
throw CUDTException();
#else
(void)events;
(void)s;
#ifdef _MSC_VER
#pragma message("WARNING: Unsupported system for epoll. The epoll_add_ssock() API call won't work on this platform.")
#else
#warning "Unsupported system for epoll. The epoll_add_ssock() API call won't work on this platform."
#endif
#endif
p->second.m_sLocals.insert(s);
return 0;
}
int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
#ifdef LINUX
epoll_event ev; if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_DEL, s, &ev) < 0)
throw CUDTException();
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
struct kevent ke;
EV_SET(&ke, s, EVFILT_READ, EV_DELETE, 0, 0, NULL);
kevent(p->second.m_iLocalID, &ke, 1, NULL, 0, NULL);
EV_SET(&ke, s, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
kevent(p->second.m_iLocalID, &ke, 1, NULL, 0, NULL);
#endif
p->second.m_sLocals.erase(s);
return 0;
}
int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
{
ScopedLock pg(m_EPollLock);
IF_HEAVY_LOGGING(ostringstream evd);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
CEPollDesc& d = p->second;
int32_t evts = events ? *events : uint32_t(SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR);
bool edgeTriggered = evts & SRT_EPOLL_ET;
evts &= ~SRT_EPOLL_ET;
int32_t et_evts = edgeTriggered ? evts : evts & SRT_EPOLL_ETONLY;
if (evts)
{
pair<CEPollDesc::ewatch_t::iterator, bool> iter_new = d.addWatch(u, evts, et_evts);
CEPollDesc::Wait& wait = iter_new.first->second;
if (!iter_new.second)
{
const int removable = wait.watch & ~evts;
IF_HEAVY_LOGGING(PrintEpollEvent(evd, evts & (~wait.watch)));
if (removable)
{
d.removeExcessEvents(wait, evts);
}
wait.watch = evts;
wait.edge = et_evts;
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: UPDATED E" << eid << " for @" << u << " +" << evd.str());
}
else
{
IF_HEAVY_LOGGING(PrintEpollEvent(evd, evts));
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: ADDED E" << eid << " for @" << u << " " << evd.str());
}
const int newstate = wait.watch & wait.state;
if (newstate)
{
d.addEventNotice(wait, u, newstate);
}
}
else if (edgeTriggered)
{
LOGC(ealog.Error, log << "srt_epoll_update_usock: Specified only SRT_EPOLL_ET flag, but no event flag. Error.");
throw CUDTException(MJ_NOTSUP, MN_INVAL);
}
else
{
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: REMOVED E" << eid << " socket @" << u);
d.removeSubscription(u);
}
return 0;
}
int CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
#ifdef LINUX
epoll_event ev;
memset(&ev, 0, sizeof(epoll_event));
if (NULL == events)
ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
else
{
ev.events = 0;
if (*events & SRT_EPOLL_IN)
ev.events |= EPOLLIN;
if (*events & SRT_EPOLL_OUT)
ev.events |= EPOLLOUT;
if (*events & SRT_EPOLL_ERR)
ev.events |= EPOLLERR;
}
ev.data.fd = s;
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_MOD, s, &ev) < 0)
throw CUDTException();
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
struct kevent ke[2];
int num = 0;
EV_SET(&ke[0], s, EVFILT_READ, EV_DELETE, 0, 0, NULL);
kevent(p->second.m_iLocalID, ke, 1, NULL, 0, NULL);
EV_SET(&ke[0], s, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
kevent(p->second.m_iLocalID, ke, 1, NULL, 0, NULL);
if (NULL == events)
{
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
}
else
{
if (*events & SRT_EPOLL_IN)
{
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
}
if (*events & SRT_EPOLL_OUT)
{
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
}
}
if (kevent(p->second.m_iLocalID, ke, num, NULL, 0, NULL) < 0)
throw CUDTException();
#else
(void)events;
(void)s;
#endif
return 0;
}
int CEPoll::setflags(const int eid, int32_t flags)
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
CEPollDesc& ed = p->second;
int32_t oflags = ed.flags();
if (flags == -1)
return oflags;
if (flags == 0)
{
ed.clr_flags(~int32_t());
}
else
{
ed.set_flags(flags);
}
return oflags;
}
int CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut)
{
if (fdsSize < 0 || (fdsSize > 0 && !fdsSet))
throw CUDTException(MJ_NOTSUP, MN_INVAL);
steady_clock::time_point entertime = steady_clock::now();
while (true)
{
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
CEPollDesc& ed = p->second;
if (!ed.flags(SRT_EPOLL_ENABLE_EMPTY) && ed.watch_empty())
{
throw CUDTException(MJ_NOTSUP, MN_EEMPTY);
}
if (ed.flags(SRT_EPOLL_ENABLE_OUTPUTCHECK) && (fdsSet == NULL || fdsSize == 0))
{
throw CUDTException(MJ_NOTSUP, MN_INVAL);
}
if (!ed.m_sLocals.empty())
{
throw CUDTException(MJ_NOTSUP, MN_INVAL);
}
int total = 0; CEPollDesc::enotice_t::iterator i = ed.enotice_begin();
while (i != ed.enotice_end())
{
int pos = total; ++total;
if (total > fdsSize)
break;
fdsSet[pos] = *i;
ed.checkEdge(i++); }
if (total)
return total;
}
if ((msTimeOut >= 0) && (count_microseconds(srt::sync::steady_clock::now() - entertime) >= msTimeOut * int64_t(1000)))
break;
CGlobEvent::waitForEvent();
}
return 0;
}
int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefds, int64_t msTimeOut, set<SYSSOCKET>* lrfds, set<SYSSOCKET>* lwfds)
{
if (!readfds && !writefds && !lrfds && !lwfds && (msTimeOut < 0))
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
if (readfds) readfds->clear();
if (writefds) writefds->clear();
if (lrfds) lrfds->clear();
if (lwfds) lwfds->clear();
int total = 0;
srt::sync::steady_clock::time_point entertime = srt::sync::steady_clock::now();
while (true)
{
{
ScopedLock epollock(m_EPollLock);
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
{
LOGC(ealog.Error, log << "EID:" << eid << " INVALID.");
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
}
CEPollDesc& ed = p->second;
if (!ed.flags(SRT_EPOLL_ENABLE_EMPTY) && ed.watch_empty() && ed.m_sLocals.empty())
{
LOGC(ealog.Error, log << "EID:" << eid << " no sockets to check, this would deadlock");
throw CUDTException(MJ_NOTSUP, MN_EEMPTY, 0);
}
if (ed.flags(SRT_EPOLL_ENABLE_OUTPUTCHECK))
{
if (!ed.m_sLocals.empty() && (!lrfds || !lwfds))
throw CUDTException(MJ_NOTSUP, MN_INVAL);
if (!ed.watch_empty() && (!readfds || !writefds))
throw CUDTException(MJ_NOTSUP, MN_INVAL);
}
IF_HEAVY_LOGGING(int total_noticed = 0);
IF_HEAVY_LOGGING(ostringstream debug_sockets);
for (CEPollDesc::enotice_t::iterator it = ed.enotice_begin(), it_next = it; it != ed.enotice_end(); it = it_next)
{
++it_next;
IF_HEAVY_LOGGING(++total_noticed);
if (readfds && ((it->events & SRT_EPOLL_IN) || (it->events & SRT_EPOLL_ERR)))
{
if (readfds->insert(it->fd).second)
++total;
}
if (writefds && ((it->events & SRT_EPOLL_OUT) || (it->events & SRT_EPOLL_ERR)))
{
if (writefds->insert(it->fd).second)
++total;
}
IF_HEAVY_LOGGING(debug_sockets << " " << it->fd << ":"
<< IF_DIRNAME(it->events, SRT_EPOLL_IN, "R")
<< IF_DIRNAME(it->events, SRT_EPOLL_OUT, "W")
<< IF_DIRNAME(it->events, SRT_EPOLL_ERR, "E"));
if (ed.checkEdge(it)) {
IF_HEAVY_LOGGING(debug_sockets << "!");
}
}
HLOGC(ealog.Debug, log << "CEPoll::wait: REPORTED " << total << "/" << total_noticed
<< debug_sockets.str());
if (lrfds || lwfds)
{
#ifdef LINUX
const int max_events = ed.m_sLocals.size();
epoll_event ev[max_events];
int nfds = ::epoll_wait(ed.m_iLocalID, ev, max_events, 0);
IF_HEAVY_LOGGING(const int prev_total = total);
for (int i = 0; i < nfds; ++ i)
{
if ((NULL != lrfds) && (ev[i].events & EPOLLIN))
{
lrfds->insert(ev[i].data.fd);
++ total;
}
if ((NULL != lwfds) && (ev[i].events & EPOLLOUT))
{
lwfds->insert(ev[i].data.fd);
++ total;
}
}
HLOGC(ealog.Debug, log << "CEPoll::wait: LINUX: picking up " << (total - prev_total) << " ready fds.");
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
struct timespec tmout = {0, 0};
const int max_events = ed.m_sLocals.size();
struct kevent ke[max_events];
int nfds = kevent(ed.m_iLocalID, NULL, 0, ke, max_events, &tmout);
IF_HEAVY_LOGGING(const int prev_total = total);
for (int i = 0; i < nfds; ++ i)
{
if ((NULL != lrfds) && (ke[i].filter == EVFILT_READ))
{
lrfds->insert(ke[i].ident);
++ total;
}
if ((NULL != lwfds) && (ke[i].filter == EVFILT_WRITE))
{
lwfds->insert(ke[i].ident);
++ total;
}
}
HLOGC(ealog.Debug, log << "CEPoll::wait: Darwin/BSD: picking up " << (total - prev_total) << " ready fds.");
#else
int max_fd = 0;
fd_set rqreadfds;
fd_set rqwritefds;
FD_ZERO(&rqreadfds);
FD_ZERO(&rqwritefds);
for (set<SYSSOCKET>::const_iterator i = ed.m_sLocals.begin(); i != ed.m_sLocals.end(); ++ i)
{
if (lrfds)
FD_SET(*i, &rqreadfds);
if (lwfds)
FD_SET(*i, &rqwritefds);
if ((int)*i > max_fd)
max_fd = *i;
}
IF_HEAVY_LOGGING(const int prev_total = total);
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
if (::select(max_fd + 1, &rqreadfds, &rqwritefds, NULL, &tv) > 0)
{
for (set<SYSSOCKET>::const_iterator i = ed.m_sLocals.begin(); i != ed.m_sLocals.end(); ++ i)
{
if (lrfds && FD_ISSET(*i, &rqreadfds))
{
lrfds->insert(*i);
++ total;
}
if (lwfds && FD_ISSET(*i, &rqwritefds))
{
lwfds->insert(*i);
++ total;
}
}
}
HLOGC(ealog.Debug, log << "CEPoll::wait: select(otherSYS): picking up " << (total - prev_total) << " ready fds.");
#endif
}
}
HLOGC(ealog.Debug, log << "CEPoll::wait: Total of " << total << " READY SOCKETS");
if (total > 0)
return total;
if ((msTimeOut >= 0) && (count_microseconds(srt::sync::steady_clock::now() - entertime) >= msTimeOut * int64_t(1000)))
{
HLOGC(ealog.Debug, log << "EID:" << eid << ": TIMEOUT.");
throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
}
const bool wait_signaled ATR_UNUSED = CGlobEvent::waitForEvent();
HLOGC(ealog.Debug, log << "CEPoll::wait: EVENT WAITING: "
<< (wait_signaled ? "TRIGGERED" : "CHECKPOINT"));
}
return 0;
}
int CEPoll::swait(CEPollDesc& d, map<SRTSOCKET, int>& st, int64_t msTimeOut, bool report_by_exception)
{
{
ScopedLock lg (m_EPollLock);
if (!d.flags(SRT_EPOLL_ENABLE_EMPTY) && d.watch_empty() && msTimeOut < 0)
{
LOGC(ealog.Error, log << "EID:" << d.m_iID << " no sockets to check, this would deadlock");
if (report_by_exception)
throw CUDTException(MJ_NOTSUP, MN_EEMPTY, 0);
return -1;
}
}
st.clear();
steady_clock::time_point entertime = steady_clock::now();
while (true)
{
{
ScopedLock lg (m_EPollLock);
if (!d.flags(SRT_EPOLL_ENABLE_EMPTY) && d.watch_empty())
{
throw CUDTException(MJ_NOTSUP, MN_EEMPTY);
}
if (!d.m_sLocals.empty())
{
throw CUDTException(MJ_NOTSUP, MN_INVAL);
}
bool empty = d.enotice_empty();
if (!empty || msTimeOut == 0)
{
IF_HEAVY_LOGGING(ostringstream singles);
int total = 0; CEPollDesc::enotice_t::iterator i = d.enotice_begin();
while (i != d.enotice_end())
{
++total;
st[i->fd] = i->events;
IF_HEAVY_LOGGING(singles << "@" << i->fd << ":");
IF_HEAVY_LOGGING(PrintEpollEvent(singles, i->events, i->parent->edgeOnly()));
const bool edged ATR_UNUSED = d.checkEdge(i++); IF_HEAVY_LOGGING(singles << (edged ? "<^> " : " "));
}
HLOGC(ealog.Debug, log << "E" << d.m_iID << " rdy=" << total << ": "
<< singles.str()
<< " TRACKED: " << d.DisplayEpollWatch());
return total;
}
}
if ((msTimeOut >= 0) && ((steady_clock::now() - entertime) >= microseconds_from(msTimeOut * int64_t(1000))))
{
HLOGC(ealog.Debug, log << "EID:" << d.m_iID << ": TIMEOUT.");
if (report_by_exception)
throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
return 0; }
CGlobEvent::waitForEvent();
}
return 0;
}
int CEPoll::release(const int eid)
{
ScopedLock pg(m_EPollLock);
map<int, CEPollDesc>::iterator i = m_mPolls.find(eid);
if (i == m_mPolls.end())
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
#ifdef LINUX
::close(i->second.m_iLocalID);
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
::close(i->second.m_iLocalID);
#endif
m_mPolls.erase(i);
return 0;
}
int CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int events, const bool enable)
{
if ((events & ~SRT_EPOLL_EVENTTYPES) != 0)
{
LOGC(eilog.Fatal, log << "epoll/update: IPE: 'events' parameter shall not contain special flags!");
return -1; }
vector<int> lost;
IF_HEAVY_LOGGING(ostringstream debug);
IF_HEAVY_LOGGING(debug << "epoll/update: @" << uid << " " << (enable ? "+" : "-"));
IF_HEAVY_LOGGING(PrintEpollEvent(debug, events));
ScopedLock pg (m_EPollLock);
for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i)
{
map<int, CEPollDesc>::iterator p = m_mPolls.find(*i);
if (p == m_mPolls.end())
{
HLOGC(eilog.Note, log << "epoll/update: E" << *i << " was deleted in the meantime");
lost.push_back(*i);
continue;
}
CEPollDesc& ed = p->second;
CEPollDesc::Wait* pwait = ed.watch_find(uid);
if (!pwait)
{
LOGC(eilog.Error, log << "epoll/update: IPE: update struck E"
<< (*i) << " which is NOT SUBSCRIBED to @" << uid);
continue;
}
IF_HEAVY_LOGGING(string tracking = " TRACKING: " + ed.DisplayEpollWatch());
const int newstate = enable ? pwait->state | events : pwait->state & (~events);
int changes = pwait->state ^ newstate; if (!changes)
{
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
<< tracking << " NOT updated: no changes");
continue; }
pwait->state = newstate;
changes &= pwait->watch;
if (!changes)
{
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
<< tracking << " NOT updated: not subscribed");
continue; }
ed.updateEventNotice(*pwait, uid, events, enable);
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
<< " TRACKING: " << ed.DisplayEpollWatch());
}
for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i)
eids.erase(*i);
return 0;
}
#if ENABLE_HEAVY_LOGGING
static ostream& PrintEpollEvent(ostream& os, int events, int et_events)
{
static pair<int, const char*> const namemap [] = {
make_pair(SRT_EPOLL_IN, "R"),
make_pair(SRT_EPOLL_OUT, "W"),
make_pair(SRT_EPOLL_ERR, "E"),
make_pair(SRT_EPOLL_UPDATE, "U")
};
int N = Size(namemap);
for (int i = 0; i < N; ++i)
{
if (events & namemap[i].first)
{
os << "[";
if (et_events & namemap[i].first)
os << "^";
os << namemap[i].second << "]";
}
}
return os;
}
string DisplayEpollResults(const std::map<SRTSOCKET, int>& sockset)
{
typedef map<SRTSOCKET, int> fmap_t;
ostringstream os;
for (fmap_t::const_iterator i = sockset.begin(); i != sockset.end(); ++i)
{
os << "@" << i->first << ":";
PrintEpollEvent(os, i->second);
os << " ";
}
return os.str();
}
string CEPollDesc::DisplayEpollWatch()
{
ostringstream os;
for (ewatch_t::const_iterator i = m_USockWatchState.begin(); i != m_USockWatchState.end(); ++i)
{
os << "@" << i->first << ":";
PrintEpollEvent(os, i->second.watch, i->second.edge);
os << " ";
}
return os.str();
}
#endif