diff options
author | Zac Medico <zmedico@gentoo.org> | 2010-09-02 00:05:06 -0700 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2010-09-02 00:05:06 -0700 |
commit | 252fa9a50c264e9827c42c631291749ad62d0f4d (patch) | |
tree | 65a79cae3f0b770f60b344fbc14d65e67c9c78d1 | |
parent | 7dfbdb9025376df95af58f42e304f9ef627576e6 (diff) | |
download | portage-252fa9a50c264e9827c42c631291749ad62d0f4d.tar.gz portage-252fa9a50c264e9827c42c631291749ad62d0f4d.tar.bz2 portage-252fa9a50c264e9827c42c631291749ad62d0f4d.zip |
Adjust EbuildIpcDaemon pickle read and write code in order to ensure
atomc reading and writing of whole pickles. This should be the least
error-prone approach, given the non-blocking nature of the streams.
-rwxr-xr-x | bin/ebuild-ipc.py | 30 | ||||
-rw-r--r-- | pym/_emerge/EbuildIpcDaemon.py | 29 | ||||
-rw-r--r-- | pym/_emerge/FifoIpcDaemon.py | 5 |
3 files changed, 56 insertions, 8 deletions
diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py index cbb8c5570..52fb08226 100755 --- a/bin/ebuild-ipc.py +++ b/bin/ebuild-ipc.py @@ -48,13 +48,35 @@ class EbuildIpc(object): def _communicate(self, args): input_fd = os.open(self.ipc_out_fifo, os.O_RDONLY|os.O_NONBLOCK) - input_file = os.fdopen(input_fd, 'rb') - output_file = open(self.ipc_in_fifo, 'wb') - pickle.dump(args, output_file) + + # File streams are in unbuffered mode since we do atomic + # read and write of whole pickles. + input_file = os.fdopen(input_fd, 'rb', 0) + output_file = open(self.ipc_in_fifo, 'wb', 0) + + # Write the whole pickle in a single atomic write() call, + # since the reader is in non-blocking mode and we want + # it to get the whole pickle at once. + output_file.write(pickle.dumps(args)) output_file.flush() events = select.select([input_file], [], []) - reply = pickle.load(input_file) + + # Read the whole pickle in a single read() call since + # this stream is in non-blocking mode and pickle.load() + # has been known to raise the following exception when + # reading from a non-blocking stream: + # + # File "/usr/lib64/python2.6/pickle.py", line 1370, in load + # return Unpickler(file).load() + # File "/usr/lib64/python2.6/pickle.py", line 858, in load + # dispatch[key](self) + # File "/usr/lib64/python2.6/pickle.py", line 1195, in load_setitem + # value = stack.pop() + # IndexError: pop from empty list + + pickle_str = input_file.read() + reply = pickle.loads(pickle_str) output_file.close() input_file.close() diff --git a/pym/_emerge/EbuildIpcDaemon.py b/pym/_emerge/EbuildIpcDaemon.py index f87ffd2e0..93333a6b1 100644 --- a/pym/_emerge/EbuildIpcDaemon.py +++ b/pym/_emerge/EbuildIpcDaemon.py @@ -32,8 +32,23 @@ class EbuildIpcDaemon(FifoIpcDaemon): if event & PollConstants.POLLIN: + # Read the whole pickle in a single read() call since + # this stream is in non-blocking mode and pickle.load() + # has been known to raise the following exception when + # reading from a non-blocking stream: + # + # File "/usr/lib64/python2.6/pickle.py", line 1370, in load + # return Unpickler(file).load() + # File "/usr/lib64/python2.6/pickle.py", line 858, in load + # dispatch[key](self) + # File "/usr/lib64/python2.6/pickle.py", line 1195, in load_setitem + # value = stack.pop() + # IndexError: pop from empty list + + pickle_str = self._files.pipe_in.read() + try: - obj = pickle.load(self._files.pipe_in) + obj = pickle.loads(pickle_str) except (EnvironmentError, EOFError, ValueError, pickle.UnpicklingError): pass @@ -63,6 +78,14 @@ class EbuildIpcDaemon(FifoIpcDaemon): def _send_reply(self, reply): output_fd = os.open(self.output_fifo, os.O_WRONLY|os.O_NONBLOCK) - output_file = os.fdopen(output_fd, 'wb') - pickle.dump(reply, output_file) + + # File streams are in unbuffered mode since we do atomic + # read and write of whole pickles. + output_file = os.fdopen(output_fd, 'wb', 0) + + # Write the whole pickle in a single atomic write() call, + # since the reader is in non-blocking mode and we want + # it to get the whole pickle at once. + output_file.write(pickle.dumps(reply)) + output_file.flush() output_file.close() diff --git a/pym/_emerge/FifoIpcDaemon.py b/pym/_emerge/FifoIpcDaemon.py index 60a5096a5..b879fda95 100644 --- a/pym/_emerge/FifoIpcDaemon.py +++ b/pym/_emerge/FifoIpcDaemon.py @@ -16,7 +16,10 @@ class FifoIpcDaemon(AbstractPollTask): def _start(self): self._files = self._files_dict() input_fd = os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK) - self._files.pipe_in = os.fdopen(input_fd, 'rb') + + # File streams are in unbuffered mode since we do atomic + # read and write of whole pickles. + self._files.pipe_in = os.fdopen(input_fd, 'rb', 0) self._reg_id = self.scheduler.register( self._files.pipe_in.fileno(), |