8
8
import sys
9
9
import select
10
10
import logging
11
+ import threading
11
12
from subprocess import (
12
13
call ,
13
14
Popen ,
@@ -72,22 +73,31 @@ def read_line_slow(stream):
72
73
return line
73
74
# end
74
75
75
- fdmap = { process .stdout .fileno () : (process .stdout , stdout_handler , read_line_fast ),
76
- process .stderr .fileno () : (process .stderr , stderr_handler , read_line_slow ) }
77
-
78
- if hasattr (select , 'poll' ):
79
- def dispatch_line (fd ):
80
- stream , handler , readline = fdmap [fd ]
76
+ def dispatch_line (fno ):
77
+ stream , handler , readline = fdmap [fno ]
81
78
# this can possibly block for a while, but since we wake-up with at least one or more lines to handle,
82
79
# we are good ...
83
80
line = readline (stream ).decode (defenc )
84
81
if line and handler :
85
82
handler (line )
86
83
return line
87
84
# end dispatch helper
85
+ # end
86
+
87
+ def deplete_buffer (fno ):
88
+ while True :
89
+ line = dispatch_line (fno )
90
+ if not line :
91
+ break
92
+ # end deplete buffer
93
+ # end
94
+
95
+ fdmap = { process .stdout .fileno () : (process .stdout , stdout_handler , read_line_fast ),
96
+ process .stderr .fileno () : (process .stderr , stderr_handler , read_line_slow ) }
88
97
89
- # poll is preferred, as select is limited to file handles up to 1024 ... . Not an issue for us though,
90
- # as we deal with relatively blank processes
98
+ if hasattr (select , 'poll' ):
99
+ # poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
100
+ # an issue for us, as it matters how many handles or own process has
91
101
poll = select .poll ()
92
102
READ_ONLY = select .POLLIN | select .POLLPRI | select .POLLHUP | select .POLLERR
93
103
CLOSED = select .POLLHUP | select .POLLERR
@@ -113,18 +123,23 @@ def dispatch_line(fd):
113
123
# end endless loop
114
124
115
125
# Depelete all remaining buffers
116
- for fno , _ in fdmap .items ():
117
- while True :
118
- line = dispatch_line (fno )
119
- if not line :
120
- break
121
- # end deplete buffer
126
+ for fno in fdmap .keys ():
127
+ deplete_buffer (fno )
122
128
# end for each file handle
123
129
else :
124
130
# Oh ... probably we are on windows. select.select() can only handle sockets, we have files
125
131
# The only reliable way to do this now is to use threads and wait for both to finish
126
132
# Since the finalizer is expected to wait, we don't have to introduce our own wait primitive
127
- raise NotImplementedError ()
133
+ # NO: It's not enough unfortunately, and we will have to sync the threads
134
+ threads = list ()
135
+ for fno in fdmap .keys ():
136
+ t = threading .Thread (target = lambda : deplete_buffer (fno ))
137
+ threads .append (t )
138
+ t .start ()
139
+ # end
140
+ for t in threads :
141
+ t .join ()
142
+ # end
128
143
# end
129
144
130
145
return finalizer (process )
0 commit comments