@@ -1219,22 +1219,34 @@ class MultiLoopChildWatcher(AbstractChildWatcher):
12191219
12201220 def __init__ (self ):
12211221 self ._callbacks = {}
1222- self ._saved_sighandler = None
1222+ self ._saved_sighandler = {}
1223+ self ._handler_added_loops = []
12231224
12241225 def is_active (self ):
1225- return self ._saved_sighandler is not None
1226+ return self ._handler_added_loops is not []
12261227
12271228 def close (self ):
12281229 self ._callbacks .clear ()
1229- if self ._saved_sighandler is None :
1230+ if self ._handler_added_loops is [] :
12301231 return
12311232
1232- handler = signal .getsignal (signal .SIGCHLD )
1233- if handler != self ._sig_chld :
1234- logger .warning ("SIGCHLD handler was changed by outside code" )
1235- else :
1236- signal .signal (signal .SIGCHLD , self ._saved_sighandler )
1237- self ._saved_sighandler = None
1233+ # handler = signal.getsignal(signal.SIGCHLD)
1234+ # if handler != self._sig_chld:
1235+ # logger.warning("SIGCHLD handler was changed by outside code")
1236+ # else:
1237+ # signal.signal(signal.SIGCHLD, self._saved_sighandler)
1238+ # self._saved_sighandler = None
1239+
1240+ if self ._handler_added_loops is not [] and self ._callbacks :
1241+ warnings .warn (
1242+ 'Event Loops are being detached '
1243+ 'from a child watcher with pending handlers' ,
1244+ RuntimeWarning )
1245+
1246+ if self ._handler_added_loops is not []:
1247+ for loop in self ._handler_added_loops :
1248+ loop .remove_signal_handler (signal .SIGCHLD )
1249+ self ._handler_added_loops .remove (loop )
12381250
12391251 def __enter__ (self ):
12401252 return self
@@ -1244,6 +1256,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
12441256
12451257 def add_child_handler (self , pid , callback , * args ):
12461258 loop = events .get_running_loop ()
1259+ if loop not in self ._handler_added_loops :
1260+ self .attach_loop (loop )
1261+
12471262 self ._callbacks [pid ] = (loop , callback , args )
12481263
12491264 # Prevent a race condition in case the child is already terminated.
@@ -1257,21 +1272,30 @@ def remove_child_handler(self, pid):
12571272 return False
12581273
12591274 def attach_loop (self , loop ):
1260- # Don't save the loop but initialize itself if called first time
1261- # The reason to do it here is that attach_loop() is called from
1262- # unix policy only for the main thread.
1263- # Main thread is required for subscription on SIGCHLD signal
1264- if self ._saved_sighandler is not None :
1265- return
1266-
1267- self ._saved_sighandler = signal .signal (signal .SIGCHLD , self ._sig_chld )
1268- if self ._saved_sighandler is None :
1269- logger .warning ("Previous SIGCHLD handler was set by non-Python code, "
1270- "restore to default handler on watcher close." )
1271- self ._saved_sighandler = signal .SIG_DFL
1275+ # # Don't save the loop but initialize itself if called first time
1276+ # # The reason to do it here is that attach_loop() is called from
1277+ # # unix policy only for the main thread.
1278+ # # Main thread is required for subscription on SIGCHLD signal
1279+ # if self._saved_sighandler is not None:
1280+ # return
1281+
1282+ # self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld)
1283+ # if self._saved_sighandler is None:
1284+ # logger.warning("Previous SIGCHLD handler was set by non-Python code, "
1285+ # "restore to default handler on watcher close.")
1286+ # self._saved_sighandler = signal.SIG_DFL
1287+
1288+ # # Set SA_RESTART to limit EINTR occurrences.
1289+ # signal.siginterrupt(signal.SIGCHLD, False)
1290+ assert loop is None or isinstance (loop , events .AbstractEventLoop )
1291+
1292+ if loop is not None :
1293+ loop .add_signal_handler (signal .SIGCHLD , self ._sig_chld )
12721294
1273- # Set SA_RESTART to limit EINTR occurrences.
1274- signal .siginterrupt (signal .SIGCHLD , False )
1295+ # Prevent a race condition in case a child terminated
1296+ # during the switch.
1297+ self ._do_waitpid_all ()
1298+ self ._handler_added_loops .append (loop )
12751299
12761300 def _do_waitpid_all (self ):
12771301 for pid in list (self ._callbacks ):
@@ -1314,7 +1338,7 @@ def _do_waitpid(self, expected_pid):
13141338 expected_pid , returncode )
13151339 loop .call_soon_threadsafe (callback , pid , returncode , * args )
13161340
1317- def _sig_chld (self , signum , frame ):
1341+ def _sig_chld (self ):
13181342 try :
13191343 self ._do_waitpid_all ()
13201344 except (SystemExit , KeyboardInterrupt ):
0 commit comments