OLD | NEW |
| (Empty) |
1 /***************************************************************************** | |
2 Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. | |
3 All rights reserved. | |
4 | |
5 Redistribution and use in source and binary forms, with or without | |
6 modification, are permitted provided that the following conditions are | |
7 met: | |
8 | |
9 * Redistributions of source code must retain the above | |
10 copyright notice, this list of conditions and the | |
11 following disclaimer. | |
12 | |
13 * Redistributions in binary form must reproduce the | |
14 above copyright notice, this list of conditions | |
15 and the following disclaimer in the documentation | |
16 and/or other materials provided with the distribution. | |
17 | |
18 * Neither the name of the University of Illinois | |
19 nor the names of its contributors may be used to | |
20 endorse or promote products derived from this | |
21 software without specific prior written permission. | |
22 | |
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
24 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
25 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
26 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 *****************************************************************************/ | |
35 | |
36 /***************************************************************************** | |
37 written by | |
38 Yunhong Gu, last updated 01/01/2011 | |
39 *****************************************************************************/ | |
40 | |
41 #include "udt.h" | |
42 #include "common.h" | |
43 #include "epoll.h" | |
44 #include <errno.h> | |
45 #include <algorithm> | |
46 #include <iterator> | |
47 #ifdef LINUX | |
48 #include <sys/epoll.h> | |
49 #include <unistd.h> | |
50 #endif | |
51 | |
52 using namespace std; | |
53 | |
54 CEPoll::CEPoll(): | |
55 m_iIDSeed(0) | |
56 { | |
57 CGuard::createMutex(m_EPollLock); | |
58 } | |
59 | |
60 CEPoll::~CEPoll() | |
61 { | |
62 CGuard::releaseMutex(m_EPollLock); | |
63 } | |
64 | |
65 int CEPoll::create() | |
66 { | |
67 CGuard pg(m_EPollLock); | |
68 | |
69 int localid = 0; | |
70 | |
71 #ifdef LINUX | |
72 localid = epoll_create(1024); | |
73 if (localid < 0) | |
74 throw CUDTException(-1, 0, errno); | |
75 #else | |
76 // on BSD, use kqueue | |
77 // on Solaris, use /dev/poll | |
78 // on Windows, select | |
79 #endif | |
80 | |
81 if (++ m_iIDSeed >= 0x7FFFFFFF) | |
82 m_iIDSeed = 0; | |
83 | |
84 CEPollDesc desc; | |
85 desc.m_iID = m_iIDSeed; | |
86 desc.m_iLocalID = localid; | |
87 m_mPolls[desc.m_iID] = desc; | |
88 | |
89 return desc.m_iID; | |
90 } | |
91 | |
92 int CEPoll::add_usock(const int eid, const UDTSOCKET& u, const int* /*events*/) | |
93 { | |
94 CGuard pg(m_EPollLock); | |
95 | |
96 map<int, CEPollDesc>::iterator p = m_mPolls.find(eid); | |
97 if (p == m_mPolls.end()) | |
98 throw CUDTException(5, 13); | |
99 | |
100 p->second.m_sUDTSocks.insert(u); | |
101 | |
102 return 0; | |
103 } | |
104 | |
105 int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events) | |
106 { | |
107 CGuard pg(m_EPollLock); | |
108 | |
109 map<int, CEPollDesc>::iterator p = m_mPolls.find(eid); | |
110 if (p == m_mPolls.end()) | |
111 throw CUDTException(5, 13); | |
112 | |
113 #ifdef LINUX | |
114 epoll_event ev; | |
115 | |
116 if (NULL == events) | |
117 ev.events = EPOLLIN | EPOLLOUT | EPOLLERR; | |
118 else | |
119 { | |
120 if (*events & UDT_EPOLL_IN) | |
121 ev.events |= EPOLLIN; | |
122 if (*events & UDT_EPOLL_OUT) | |
123 ev.events |= EPOLLOUT; | |
124 if (*events & UDT_EPOLL_ERR) | |
125 ev.events |= EPOLLERR; | |
126 } | |
127 | |
128 ev.data.fd = s; | |
129 if (epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_ADD, s, &ev) < 0) | |
130 throw CUDTException(); | |
131 #endif | |
132 | |
133 p->second.m_sLocals.insert(s); | |
134 | |
135 return 0; | |
136 } | |
137 | |
138 int CEPoll::remove_usock(const int eid, const UDTSOCKET& u, const int* /*events*
/) | |
139 { | |
140 CGuard pg(m_EPollLock); | |
141 | |
142 map<int, CEPollDesc>::iterator p = m_mPolls.find(eid); | |
143 if (p == m_mPolls.end()) | |
144 throw CUDTException(5, 13); | |
145 | |
146 p->second.m_sUDTSocks.erase(u); | |
147 | |
148 // when the socket is removed from a monitoring, it is not available anymore
for any IO notification | |
149 p->second.m_sUDTReads.erase(u); | |
150 p->second.m_sUDTWrites.erase(u); | |
151 | |
152 return 0; | |
153 } | |
154 | |
155 int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s, const int* events) | |
156 { | |
157 CGuard pg(m_EPollLock); | |
158 | |
159 map<int, CEPollDesc>::iterator p = m_mPolls.find(eid); | |
160 if (p == m_mPolls.end()) | |
161 throw CUDTException(5, 13); | |
162 | |
163 #ifdef LINUX | |
164 epoll_event ev; | |
165 | |
166 if (NULL == events) | |
167 ev.events = EPOLLIN | EPOLLOUT | EPOLLERR; | |
168 else | |
169 { | |
170 if (*events & UDT_EPOLL_IN) | |
171 ev.events |= EPOLLIN; | |
172 if (*events & UDT_EPOLL_OUT) | |
173 ev.events |= EPOLLOUT; | |
174 if (*events & UDT_EPOLL_ERR) | |
175 ev.events |= EPOLLERR; | |
176 } | |
177 | |
178 ev.data.fd = s; | |
179 if (epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_DEL, s, &ev) < 0) | |
180 throw CUDTException(); | |
181 #endif | |
182 | |
183 p->second.m_sLocals.erase(s); | |
184 | |
185 return 0; | |
186 } | |
187 | |
188 int CEPoll::wait(const int eid, set<UDTSOCKET>* readfds, set<UDTSOCKET>* writefd
s, int64_t msTimeOut, set<SYSSOCKET>* lrfds, set<SYSSOCKET>* lwfds) | |
189 { | |
190 // if all fields is NULL and waiting time is infinite, then this would be a d
eadlock | |
191 if (!readfds && !writefds && !lrfds && lwfds && (msTimeOut < 0)) | |
192 throw CUDTException(5, 3, 0); | |
193 | |
194 int total = 0; | |
195 | |
196 int64_t entertime = CTimer::getTime(); | |
197 while (true) | |
198 { | |
199 CGuard::enterCS(m_EPollLock); | |
200 | |
201 map<int, CEPollDesc>::iterator p = m_mPolls.find(eid); | |
202 if (p == m_mPolls.end()) | |
203 { | |
204 CGuard::leaveCS(m_EPollLock); | |
205 throw CUDTException(5, 13); | |
206 } | |
207 | |
208 if (((readfds || writefds) && p->second.m_sUDTSocks.empty()) && ((lrfds ||
lwfds) && p->second.m_sLocals.empty())) | |
209 { | |
210 // no socket is being monitored, this may be a deadlock | |
211 CGuard::leaveCS(m_EPollLock); | |
212 throw CUDTException(5, 3); | |
213 } | |
214 | |
215 if ((NULL != readfds) && !p->second.m_sUDTReads.empty()) | |
216 { | |
217 *readfds = p->second.m_sUDTReads; | |
218 total += p->second.m_sUDTReads.size(); | |
219 } | |
220 | |
221 if ((NULL != writefds) && !p->second.m_sUDTWrites.empty()) | |
222 { | |
223 *writefds = p->second.m_sUDTWrites; | |
224 total += p->second.m_sUDTWrites.size(); | |
225 } | |
226 | |
227 if (lrfds || lwfds) | |
228 { | |
229 if (lrfds) | |
230 lrfds->clear(); | |
231 | |
232 if (lwfds) | |
233 lwfds->clear(); | |
234 | |
235 #ifdef LINUX | |
236 const int max_events = p->second.m_sLocals.size(); | |
237 epoll_event ev[max_events]; | |
238 int nfds = epoll_wait(p->second.m_iLocalID, ev, max_events, 0); | |
239 | |
240 for (int i = 0; i < nfds; ++ i) | |
241 { | |
242 if ((NULL != lrfds) && (ev[i].events & EPOLLIN)) | |
243 { | |
244 lrfds->insert(ev[i].data.fd); | |
245 ++ total; | |
246 } | |
247 if ((NULL != lwfds) && (ev[i].events & EPOLLOUT)) | |
248 { | |
249 lwfds->insert(ev[i].data.fd); | |
250 ++ total; | |
251 } | |
252 } | |
253 #else | |
254 //currently "select" is used for all non-Linux platforms. | |
255 //faster approaches can be applied for specific systems in the future. | |
256 | |
257 //"select" has a limitation on the number of sockets | |
258 | |
259 fd_set readfds; | |
260 fd_set writefds; | |
261 FD_ZERO(&readfds); | |
262 FD_ZERO(&writefds); | |
263 | |
264 for (set<SYSSOCKET>::const_iterator i = p->second.m_sLocals.begin(); i
!= p->second.m_sLocals.end(); ++ i) | |
265 { | |
266 if (lrfds) | |
267 FD_SET(*i, &readfds); | |
268 if (lwfds) | |
269 FD_SET(*i, &writefds); | |
270 } | |
271 | |
272 timeval tv; | |
273 tv.tv_sec = 0; | |
274 tv.tv_usec = 0; | |
275 int r = select(0, &readfds, &writefds, NULL, &tv); | |
276 | |
277 if (r > 0) | |
278 { | |
279 for (set<SYSSOCKET>::const_iterator i = p->second.m_sLocals.begin();
i != p->second.m_sLocals.end(); ++ i) | |
280 { | |
281 if (lrfds) | |
282 { | |
283 if (FD_ISSET(*i, &readfds)) | |
284 { | |
285 lrfds->insert(*i); | |
286 ++ total; | |
287 } | |
288 } | |
289 | |
290 if (lwfds) | |
291 { | |
292 if (FD_ISSET(*i, &writefds)) | |
293 { | |
294 lwfds->insert(*i); | |
295 ++ total; | |
296 } | |
297 } | |
298 } | |
299 } | |
300 #endif | |
301 } | |
302 | |
303 CGuard::leaveCS(m_EPollLock); | |
304 | |
305 if (total > 0) | |
306 return total; | |
307 | |
308 if ((msTimeOut >= 0) && (int64_t(CTimer::getTime() - entertime) >= msTimeO
ut * 1000LL)) | |
309 break; | |
310 | |
311 CTimer::waitForEvent(); | |
312 } | |
313 | |
314 return 0; | |
315 } | |
316 | |
317 int CEPoll::release(const int eid) | |
318 { | |
319 CGuard pg(m_EPollLock); | |
320 | |
321 map<int, CEPollDesc>::iterator i = m_mPolls.find(eid); | |
322 if (i == m_mPolls.end()) | |
323 throw CUDTException(5, 13); | |
324 | |
325 #ifdef LINUX | |
326 // release local/system epoll descriptor | |
327 ::close(i->second.m_iLocalID); | |
328 #endif | |
329 | |
330 m_mPolls.erase(i); | |
331 | |
332 return 0; | |
333 } | |
334 | |
335 int CEPoll::enable_write(const UDTSOCKET& uid, set<int>& eids) | |
336 { | |
337 CGuard pg(m_EPollLock); | |
338 | |
339 map<int, CEPollDesc>::iterator p; | |
340 | |
341 vector<int> lost; | |
342 for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i) | |
343 { | |
344 p = m_mPolls.find(*i); | |
345 if (p == m_mPolls.end()) | |
346 { | |
347 lost.push_back(*i); | |
348 } | |
349 else | |
350 { | |
351 p->second.m_sUDTWrites.insert(uid); | |
352 } | |
353 } | |
354 | |
355 for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i) | |
356 eids.erase(*i); | |
357 | |
358 return 0; | |
359 } | |
360 | |
361 int CEPoll::enable_read(const UDTSOCKET& uid, set<int>& eids) | |
362 { | |
363 CGuard pg(m_EPollLock); | |
364 | |
365 map<int, CEPollDesc>::iterator p; | |
366 | |
367 vector<int> lost; | |
368 for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i) | |
369 { | |
370 p = m_mPolls.find(*i); | |
371 if (p == m_mPolls.end()) | |
372 { | |
373 lost.push_back(*i); | |
374 } | |
375 else | |
376 { | |
377 p->second.m_sUDTReads.insert(uid); | |
378 } | |
379 } | |
380 | |
381 for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i) | |
382 eids.erase(*i); | |
383 | |
384 return 0; | |
385 } | |
386 | |
387 int CEPoll::disable_write(const UDTSOCKET& uid, set<int>& eids) | |
388 { | |
389 CGuard pg(m_EPollLock); | |
390 | |
391 map<int, CEPollDesc>::iterator p; | |
392 | |
393 vector<int> lost; | |
394 for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i) | |
395 { | |
396 p = m_mPolls.find(*i); | |
397 if (p == m_mPolls.end()) | |
398 { | |
399 lost.push_back(*i); | |
400 } | |
401 else | |
402 { | |
403 p->second.m_sUDTWrites.erase(uid); | |
404 } | |
405 } | |
406 | |
407 for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i) | |
408 eids.erase(*i); | |
409 | |
410 return 0; | |
411 } | |
412 | |
413 int CEPoll::disable_read(const UDTSOCKET& uid, set<int>& eids) | |
414 { | |
415 CGuard pg(m_EPollLock); | |
416 | |
417 map<int, CEPollDesc>::iterator p; | |
418 | |
419 vector<int> lost; | |
420 for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i) | |
421 { | |
422 p = m_mPolls.find(*i); | |
423 if (p == m_mPolls.end()) | |
424 { | |
425 lost.push_back(*i); | |
426 } | |
427 else | |
428 { | |
429 p->second.m_sUDTReads.erase(uid); | |
430 } | |
431 } | |
432 | |
433 for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i) | |
434 eids.erase(*i); | |
435 | |
436 return 0; | |
437 } | |
OLD | NEW |