def process(self): assert not self.closed assert self.queue conn = self.queue[0] if len(self.queue) > 1: self.log('queued request, qlen=%s' % len(self.queue)) # Try to read the single byte written by the child. # This can fail if the child died or the pipe really # wasn't ready (select returns a hint only). The fd has # been made non-blocking by spawn_child. try: ready_byte = os.read(self.fd, 1) if not ready_byte: raise IOError('null read from child') assert ready_byte == b'1', repr(ready_byte) except (OSError, IOError) as exc: if exc.errno == errno.EWOULDBLOCK: # select was wrong and fd not ready. Child might # still be busy so keep it alive (don't close). return self.log('error while getting child status: %s' % exc) else: try: passfd.sendfd(self.fd, conn.fileno()) except IOError as exc: if exc.errno == errno.EPIPE: # broken pipe, child died? self.log('EPIPE passing fd to child') else: # some other error that we don't expect self.log('IOError passing fd to child: %s' % exc.errno) else: # fd was apparently passed okay to the child. # The child could die before completing the # request but that's not our problem anymore. self.last_used = time.time() conn.close() del self.queue[0] return # We have failed to pass the fd to the child. Since the # child is not behaving how we expect, we close 'fd'. That # will cause the child to die (if it hasn't already). We will # reap the exit status in reap_children() and remove the Child() # object from the 'children' list. self.close()
def process(self, conn): # Try to read the single byte written by the child. # This can fail if the child died or the socket really # wasn't ready (select returns a hint only). The fd has # been made non-blocking by spawn_child. try: ready_byte = os.read(self.fd, 1) if not ready_byte: raise IOError('null read from child') assert ready_byte == b"1", repr(ready_byte) except (OSError, IOError) as exc: if exc.errno == errno.EWOULDBLOCK: # select was wrong and fd not ready. Child might # still be busy so keep it alive (don't close). return False else: self.log('error while getting child status: %s' % exc) else: # The byte was read okay, now we need to pass the fd # of the request to the child. This can also fail # if the child died. Again, if this fails we fall # through to the "reap_children" logic and will # retry the select call. try: passfd.sendfd(self.fd, conn.fileno()) except IOError as exc: if exc.errno == errno.EPIPE: # broken pipe, child died? self.log('EPIPE passing fd to child') else: # some other error that we don't expect self.log('IOError passing fd to child: %s' % exc.errno) else: # fd was apparently passed okay to the child. # The child could die before completing the # request but that's not our problem anymore. return True # We have failed to pass the fd to the child. Since the # child is not behaving how we expect, we close 'fd'. That # will cause the child to die (if it hasn't already). We will # reap the exit status in reap_children() and remove the Child() # object from the 'children' list. self.close() return False # did not pass fd successfully
assert ready_byte == "1", repr(ready_byte) except socket.error, exc: if exc[0] == errno.EWOULDBLOCK: pass # select was wrong else: raise except (OSError, IOError): pass # child died? else: # The byte was read okay, now we need to pass the fd # of the request to the child. This can also fail # if the child died. Again, if this fails we fall # through to the "reap_children" logic and will # retry the select call. try: passfd.sendfd(child.fd, conn.fileno()) except IOError, exc: if exc.errno == errno.EPIPE: pass # broken pipe, child died? else: raise else: # fd was apparently passed okay to the child. # The child could die before completing the # request but that's not our problem anymore. return # didn't find any child, check if any died self.reap_children() # start more children if we haven't met max_children limit
# # fork() off! # pid = os.fork() if pid != 0: # We're in the parent. # ioctl() will only pass raw filedescriptors. Find fd of fileObj. fd = fileObj.fileno() # Send to the child os.write(wfd, b'x') passfd.sendfd(wfd, fd) # Wait for child to terminate, then exit. os.waitpid(pid, 0) fileObj.close() sys.exit(0) else: # We're in the child. fileObj.close() print(os.read(rfd, 1)) fd = passfd.recvfd(rfd) # Reopen the filedescriptor as a Python File-object.