[Tutor] sockets, files, threads

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Wed Jan 19 21:54:16 CET 2005



On Wed, 19 Jan 2005, Marilyn Davis wrote:

> class Exim:
>      def __init__(self):
>          self.fdin = None
>          self.err_flush = []
>          self.stdout, self.stdin, self.stderr  = popen2.popen3('%s -t' % MAILER)
>          self.fdin = self.stdin.fileno()
>          self.fdout = self.stdout.fileno()
>          self.fderr = self.stderr.fileno()


Hi Marilyn,

You probably don't need to explicitly use the file descriptors here. I see
that you're using them because of the use of select() later on:

###
sel = select.select(self.outlist, [], [], 1)
###


but, although select.select() can use file descriptor numbers, it can also
take file-like objects.  See:

    http://www.python.org/doc/lib/module-select.html


So you can simplify this code to:

###
sel = select.select([self.stdout, self.stderr], [], [], 1)
###

The upside to this is that you don't need to use the low-level os.read()
or os.close() functions at all.


I suspect that some silliness with file descriptors is causing your bug,
as the following:

###
>>> os.close(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OSError: [Errno 9] Bad file descriptor
###

shows that if we feed os.close() a nonsense file descriptor, it'll throw
out a error message that you may be familiar with.


The error can happen if we close the same file descriptor twice:

###
>>> myin, myout, myerr = popen2.popen3('cat')
>>> os.close(myin.fileno())
>>> os.close(myin.fileno())
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OSError: [Errno 9] Bad file descriptor
###


Here is another particular case that might really be relevant:

###
>>> myin, myout, myerr = popen2.popen3('cat')
>>> os.close(myin.fileno())
>>> myin.close()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IOError: [Errno 9] Bad file descriptor
###

We're getting an IOError here for exactly the same reasons: the high-level
'myin' object has no knowledge that its underlying file descriptor was
closed.

This is exactly why we've been saying not to mix file-descriptor stuff
with high-level file-like object manipulation: it breaks the assumptions
that the API expects to see.



> However, all that said, I do dimly remember that poplib perhaps had some
> extra processing that maybe is not needed -- but I could be wrong.

Ok; I'll try to remember to look into poplib later and see if there's
anything silly in there.



> if __name__ == '__main__':
>     msg = '''To: %s
>
>  xx''' % TO_WHOM
>
>      p = Exim()
>      p.write(msg)
>      del p


Instead of using __del__ implicitely, drop the __del__ method and try
calling Exim.close_up()  explicitely:

###
p = Exim()
p.write(msg)
p.close_up()
###



> Are you well yet?  A lot of sick people around these days!


Feeling better.



More information about the Tutor mailing list