2 * Copyright (C) 2014-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "FDEventMonitor.h"
11 #include "threads/SingleLock.h"
12 #include "utils/log.h"
18 #include <sys/eventfd.h>
21 #include "PlatformDefs.h"
23 CFDEventMonitor::CFDEventMonitor() :
24 CThread("FDEventMonitor")
28 CFDEventMonitor::~CFDEventMonitor()
30 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
38 /* wake up the poll() call */
39 eventfd_write(m_wakeupfd
, 1);
41 /* Wait for the thread to stop */
43 CSingleExit
exit(m_mutex
);
51 void CFDEventMonitor::AddFD(const MonitoredFD
& monitoredFD
, int& id
)
53 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
56 AddFDLocked(monitoredFD
, id
);
61 void CFDEventMonitor::AddFDs(const std::vector
<MonitoredFD
>& monitoredFDs
,
62 std::vector
<int>& ids
)
64 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
67 for (unsigned int i
= 0; i
< monitoredFDs
.size(); ++i
)
70 AddFDLocked(monitoredFDs
[i
], id
);
77 void CFDEventMonitor::RemoveFD(int id
)
79 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
82 if (m_monitoredFDs
.erase(id
) != 1)
84 CLog::Log(LOGERROR
, "CFDEventMonitor::RemoveFD - Tried to remove non-existing monitoredFD {}",
91 void CFDEventMonitor::RemoveFDs(const std::vector
<int>& ids
)
93 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
96 for (unsigned int i
= 0; i
< ids
.size(); ++i
)
98 if (m_monitoredFDs
.erase(ids
[i
]) != 1)
101 "CFDEventMonitor::RemoveFDs - Tried to remove non-existing monitoredFD {} while "
103 ids
[i
], (unsigned)ids
.size());
110 void CFDEventMonitor::Process()
116 std::unique_lock
<CCriticalSection
> lock(m_mutex
);
117 std::unique_lock
<CCriticalSection
> pollLock(m_pollMutex
);
120 * Leave the main mutex here to allow another thread to
121 * lock it while we are in poll().
122 * By then calling InterruptPoll() the other thread can
123 * wake up poll and wait for the processing to pause at
124 * the above lock(m_mutex).
128 int err
= poll(&m_pollDescs
[0], m_pollDescs
.size(), -1);
130 if (err
< 0 && errno
!= EINTR
)
132 CLog::Log(LOGERROR
, "CFDEventMonitor::Process - poll() failed, error {}, stopping monitoring",
137 // Something woke us up - either there is data available or we are being
138 // paused/stopped via m_wakeupfd.
140 for (unsigned int i
= 0; i
< m_pollDescs
.size(); ++i
)
142 struct pollfd
& pollDesc
= m_pollDescs
[i
];
143 int id
= m_monitoredFDbyPollDescs
[i
];
144 const MonitoredFD
& monitoredFD
= m_monitoredFDs
[id
];
146 if (pollDesc
.revents
)
148 if (monitoredFD
.callback
)
150 monitoredFD
.callback(id
, pollDesc
.fd
, pollDesc
.revents
,
151 monitoredFD
.callbackData
);
154 if (pollDesc
.revents
& (POLLERR
| POLLHUP
| POLLNVAL
))
157 "CFDEventMonitor::Process - polled fd {} got revents 0x{:x}, removing it",
158 pollDesc
.fd
, pollDesc
.revents
);
160 /* Probably would be nice to inform our caller that their FD was
161 * dropped, but oh well... */
162 m_monitoredFDs
.erase(id
);
166 pollDesc
.revents
= 0;
170 /* flush wakeup fd */
171 eventfd_read(m_wakeupfd
, &dummy
);
176 void CFDEventMonitor::AddFDLocked(const MonitoredFD
& monitoredFD
, int& id
)
180 while (m_monitoredFDs
.count(id
))
186 m_monitoredFDs
[id
] = monitoredFD
;
188 AddPollDesc(id
, monitoredFD
.fd
, monitoredFD
.events
);
191 void CFDEventMonitor::AddPollDesc(int id
, int fd
, short events
)
193 struct pollfd newPollFD
;
195 newPollFD
.events
= events
;
196 newPollFD
.revents
= 0;
198 m_pollDescs
.push_back(newPollFD
);
199 m_monitoredFDbyPollDescs
.push_back(id
);
202 void CFDEventMonitor::UpdatePollDescs()
204 m_monitoredFDbyPollDescs
.clear();
207 for (const auto& it
: m_monitoredFDs
)
209 AddPollDesc(it
.first
, it
.second
.fd
, it
.second
.events
);
213 void CFDEventMonitor::StartMonitoring()
217 /* Start the monitoring thread */
219 m_wakeupfd
= eventfd(0, EFD_CLOEXEC
| EFD_NONBLOCK
);
222 CLog::Log(LOGERROR
, "CFDEventMonitor::StartMonitoring - Failed to create eventfd, error {}",
227 /* Add wakeup fd to the fd list */
229 AddFDLocked(MonitoredFD(m_wakeupfd
, POLLIN
, NULL
, NULL
), id
);
235 void CFDEventMonitor::InterruptPoll()
239 eventfd_write(m_wakeupfd
, 1);
240 /* wait for the poll() result handling (if any) to end */
241 std::unique_lock
<CCriticalSection
> pollLock(m_pollMutex
);