def test_exit(self): try: import posix, _rawffi except ImportError: skip("requires posix.fork() to test") # pid = posix.fork() if pid == 0: _rawffi.exit(5) # in the child pid, status = posix.waitpid(pid, 0) assert posix.WIFEXITED(status) assert posix.WEXITSTATUS(status) == 5
def Wait(self): # This is a list of async jobs while True: try: pid, status = posix.wait() except OSError as e: #log('wait() error: %s', e) if e.errno == errno.ECHILD: return False # nothing to wait for caller should stop elif e.errno == errno.EINTR: # This happens when we register a handler for SIGINT, and thus never # get the KeyboardInterrupt exception? Not sure why. # Try # $ cat # Now hit Ctrl-C #log('Continuing') continue # try again else: # An error we don't know about. raise else: break # no exception thrown, so no need to retry #log('WAIT got %s %s', pid, status) # TODO: change status in more cases. if posix.WIFSIGNALED(status): if posix.WTERMSIG(status) == signal.SIGINT: print() elif posix.WIFEXITED(status): status = posix.WEXITSTATUS(status) #log('exit status: %s', status) # This could happen via coding error. But this may legitimately happen # if a grandchild outlives the child (its parent). Then it is reparented # under this process, so we might receive notification of its exit, even # though we didn't start it. We can't have any knowledge of such # processes, so print a warning. if pid not in self.callbacks: util.warn("PID %d stopped, but osh didn't start it", pid) return True # caller should keep waiting callback = self.callbacks.pop(pid) callback(pid, status) self.last_status = status # for wait -n return True # caller should keep waiting