git » pymisc » master » tree

[master] / pcmp.py

"""
pcmp - Parent-Child Message Passing
Alberto Bertogli (albertito@blitiri.com.ar)
------------------------------------------

This module implements a bidirectional channel with the Channel class, which
allows you to send and receive python objects (as long as they're pickable)
between a parent and its child.

You should instance it before you fork, and then call .child() or .parent()
according to your status. Then you can begin sending and receiving objects
with .send() and .recv().

If the pipe gets broken (one of the processes closes the pipe or dies), send()
and recv() will raise a BrokenPipe exception, defined here.

It should work under any Unix, Windows and Mac systems.
"""

import os
import errno
import pickle


class BrokenPipe (Exception):
	"Exception raised when the pipe gets broken."
	pass


class Channel (object):
	"Parent-child message passing."

	def __init__(self):
		self._p2c = os.pipe()
		self._c2p = os.pipe()
		self._rfd = None
		self._wfd = None

	def __del__(self):
		if self._rfd:
			self._rfd.close()
			self._wfd.close()
		else:
			os.close(self._p2c[0])
			os.close(self._p2c[1])
			os.close(self._c2p[0])
			os.close(self._c2p[1])

	def child(self):
		"Tell the object we're the child."
		# write via p1.w, read via p2.r, and close unnecessary fds
		# (see man 7 pipe)
		self._wfd = os.fdopen(self._c2p[1], 'w')
		self._rfd = os.fdopen(self._p2c[0], 'r')
		os.close(self._c2p[0])
		os.close(self._p2c[1])

	def parent(self):
		"Tell the object we're the parent."
		# write via p2.w, read via p1.r, and close unnecessary fds
		# (see man 7 pipe)
		self._wfd = os.fdopen(self._p2c[1], 'w')
		self._rfd = os.fdopen(self._c2p[0], 'r')
		os.close(self._p2c[0])
		os.close(self._c2p[1])

	def send(self, o):
		"Send an object."
		try:
			pickle.dump(o, self._wfd, -1)
			self._wfd.flush()
		except IOError, errno.EPIPE:
			raise BrokenPipe

	def recv(self):
		"Receive an object."
		try:
			return pickle.load(self._rfd)
		except IOError, errno.EPIPE:
			raise BrokenPipe