| ... |
... |
@@ -21,6 +21,7 @@ objects and be informed about possible IO |
|
21
|
21
|
from __future__ import unicode_literals
|
|
22
|
22
|
|
|
23
|
23
|
import os
|
|
|
24
|
+import errno
|
|
24
|
25
|
import sys
|
|
25
|
26
|
import select
|
|
26
|
27
|
import logging
|
| ... |
... |
@@ -59,7 +60,6 @@ PENDING_READ = 3 # waiting read event |
|
59
|
60
|
PENDING_WRITE = 4 # waiting write event
|
|
60
|
61
|
IS_CLOSED = 16 # channel closed
|
|
61
|
62
|
|
|
62
|
|
-
|
|
63
|
63
|
def get_idlequeue():
|
|
64
|
64
|
"""
|
|
65
|
65
|
Get an appropriate idlequeue
|
| ... |
... |
@@ -353,7 +353,7 @@ class IdleQueue(object): |
|
353
|
353
|
|
|
354
|
354
|
:param obj: the IdleObject
|
|
355
|
355
|
:param writable: True if obj has data to sent
|
|
356
|
|
- :param readable: True if obj expects data to be reiceived
|
|
|
356
|
+ :param readable: True if obj expects data to be received
|
|
357
|
357
|
"""
|
|
358
|
358
|
if obj.fd == -1:
|
|
359
|
359
|
return
|
| ... |
... |
@@ -438,16 +438,15 @@ class IdleQueue(object): |
|
438
|
438
|
return True
|
|
439
|
439
|
try:
|
|
440
|
440
|
waiting_descriptors = self.selector.poll(0)
|
|
441
|
|
- except select.error as e:
|
|
|
441
|
+ except OSError as e:
|
|
442
|
442
|
waiting_descriptors = []
|
|
443
|
|
- if e[0] != 4: # interrupt
|
|
|
443
|
+ if e.errno != errno.EINTR:
|
|
444
|
444
|
raise
|
|
445
|
445
|
for fd, flags in waiting_descriptors:
|
|
446
|
446
|
self._process_events(fd, flags)
|
|
447
|
447
|
self._check_time_events()
|
|
448
|
448
|
return True
|
|
449
|
449
|
|
|
450
|
|
-
|
|
451
|
450
|
class SelectIdleQueue(IdleQueue):
|
|
452
|
451
|
"""
|
|
453
|
452
|
Extends IdleQueue to use select.select() for polling
|
| ... |
... |
@@ -456,6 +455,31 @@ class SelectIdleQueue(IdleQueue): |
|
456
|
455
|
support io_add_watch properly (yet)
|
|
457
|
456
|
"""
|
|
458
|
457
|
|
|
|
458
|
+ def checkQueue(self):
|
|
|
459
|
+ """
|
|
|
460
|
+ Iterates through all known file descriptors and uses os.stat to check if they're valid.
|
|
|
461
|
+ Greatly improves performance if the caller hands us and expects notification on an invalid file handle.
|
|
|
462
|
+ """
|
|
|
463
|
+ bad_fds=[]
|
|
|
464
|
+ union={}
|
|
|
465
|
+ union.update(self.write_fds)
|
|
|
466
|
+ union.update(self.read_fds)
|
|
|
467
|
+ union.update(self.error_fds)
|
|
|
468
|
+ for fd in (union.keys()):
|
|
|
469
|
+ try:
|
|
|
470
|
+ status = os.stat(fd)
|
|
|
471
|
+ except OSError as e:
|
|
|
472
|
+ # This file descriptor is invalid. Add to list for closure.
|
|
|
473
|
+ bad_fds.append(fd)
|
|
|
474
|
+
|
|
|
475
|
+ for fd in (bad_fds):
|
|
|
476
|
+ obj = self.queue.get(fd)
|
|
|
477
|
+ if obj is None:
|
|
|
478
|
+ self.unplug_idle(fd)
|
|
|
479
|
+ return
|
|
|
480
|
+ self.remove_timeout(fd)
|
|
|
481
|
+ self.unplug_idle(fd)
|
|
|
482
|
+
|
|
459
|
483
|
def _init_idle(self):
|
|
460
|
484
|
"""
|
|
461
|
485
|
Create a dict, which maps file/pipe/sock descriptor to glib event id
|
| ... |
... |
@@ -466,7 +490,7 @@ class SelectIdleQueue(IdleQueue): |
|
466
|
490
|
|
|
467
|
491
|
def _add_idle(self, fd, flags):
|
|
468
|
492
|
"""
|
|
469
|
|
- This method is called when we plug a new idle object. Remove descriptor
|
|
|
493
|
+ This method is called when we plug a new idle object. Add descriptor
|
|
470
|
494
|
to read/write/error lists, according flags
|
|
471
|
495
|
"""
|
|
472
|
496
|
if flags & 3:
|
| ... |
... |
@@ -494,9 +518,10 @@ class SelectIdleQueue(IdleQueue): |
|
494
|
518
|
try:
|
|
495
|
519
|
waiting_descriptors = select.select(list(self.read_fds.keys()),
|
|
496
|
520
|
list(self.write_fds.keys()), list(self.error_fds.keys()), 0)
|
|
497
|
|
- except select.error as e:
|
|
|
521
|
+ except OSError as e:
|
|
498
|
522
|
waiting_descriptors = ((), (), ())
|
|
499
|
|
- if e[0] != 4: # interrupt
|
|
|
523
|
+ if e.errno != errno.EINTR:
|
|
|
524
|
+ self.checkQueue()
|
|
500
|
525
|
raise
|
|
501
|
526
|
for fd in waiting_descriptors[0]:
|
|
502
|
527
|
q = self.queue.get(fd)
|