From: ian AT cygnus DOT com (Ian Lance Taylor) Subject: Re: rxvt and latest Ian's changes. 2 Feb 1998 09:50:32 -0800 Message-ID: <199802021727.MAA11798.cygnus.cygwin32.developers@subrogation.cygnus.com> References: <01BD2FFE DOT 50C15C90 AT gater DOT krystalbank DOT msk DOT ru> Reply-To: gnu-win32-developers AT cygnus DOT com To: cygwin32-developers AT cygnus DOT com From: Sergey Okhapkin Date: Mon, 2 Feb 1998 17:16:34 +0300 Thu Jan 22 18:46:40 1998 Ian Lance Taylor * tty.h (class tty): Change slave_handles to int. * tty.cc (fhandler_tty_slave::open): Check for invalid tty handles. If this is the first slave, set slave_handles to 2; otherwise, increment slave_handles. (fhandler_tty_slave::close): Only close the tty handles if the slave_handles field drops to 1. This changes fools rxvt. Rxvt does the following: pty = open("/dev/ptmx"); slave = ptsname(pty); lstat(slave); tty = open(slave); Lstat call implemented in cygwin as fd=open(name); fstat(fd); close(fd). This close call closes input_handle and output_handle in tty structure (because number of slaves drops to 1) and tty=open(slave) call fails. Ian, any ideas to fix it? The basic problem with implementing ptys on top of pipes is getting the handles closed appropriately. To make expect work, I needed the master pty to correctly detect EOF when the slave pty was closed. The slave was open in a child process, and the master was sleeping in the read system call. To make this work, I made opening a slave copy the handles into the process opening the slave. This is done in fhandler_tty_slave::open. Of course, it follows that closing the slave must close the handles, which happens in fhandler_tty_slave::close when all the slaves are closed. Unfortunately, this does not handle the case of the master opening the pty, then a child opening the pty, and then closing the pty, and then another child opening the pty. This works on Unix, but I do not know how to make it work on Windows. I don't happen to know of any programs that rely on this behaviour, but there may be some. You are running into this problem, because lstat does an open behind the scenes. I can think of a couple of ways to fix this particular instance of the problem. 1) Change stat and lstat to not actually call open on the file. Doing that seems moderately bogus anyhow. You should be able to call stat without running out of file descriptors. It does seem that for some reason Windows before NT 4.0 forces you to call OpenFile, but that does not need to imply open. 2) Have the fhandler_tty_save::open check whether the master and the slave are the same process. In this case, there is no need to duplicate the tty handles at all. We would have to record this in some other way in the tty structure, perhaps by adding a flag field of some sort. This needs to be handled correctly when doing a fork tricky. If the slave is closed in the parent, we will need to hand off the descriptors to the child in order to make read detect EOF correctly. However, if the slave is not closed, we do not want to hand off the descriptors. So the handoff would need to happen when the slave is closed. This is basically a matter of updating the tty structure information when the slave is closed in the parent. The pty code is full of race conditions at present, and this would unfortunately be another one. This would not solve the general problem of reopening a slave pty, but it would solve the particular case you are running into. Does anybody have any other thoughts? Ian