[comp.windows.x.motif] fork

roger@zuken.co.jp (Roger Meunier) (08/09/90)

When a C++ program exits, it calls a list of destructors to clean up
static data.  But what happens when exit() is called after fork()?

I ran into a problem with HP's implementation of Motif 1.0.  For the
XmText widget, they allow Chinese character input by setting up a
connection with an input server.  Apparently, they fork() the server
on the first XmCreateText().  I noticed that in one of my applications,
it was taking an extremely long time to create the first text widget
(8+ sec.), and that core was being dumped during the creation.  Looking
at the core file with cdb, I noticed that exit() was being called from
the routine that did the fork(), and that subsequently all my static
destructors were being called, including one that caused the core to
be dumped (it was calling XCloseDisplay()!).  Why the *child* process
should be trying to do this is beyond me.

Has anyone else run into similar problems when fork()'ing in a C++
environment?  Is this a design problem with the C++ static object clean-up
strategy, or is HP's implementation of nlio forgetting to take C++ into
account, or both?
--
Roger Meunier @ Zuken, Inc.  Yokohama, Japan	(roger@zuken.co.jp)

mayer@hplabsz.HPL.HP.COM (Niels Mayer) (08/10/90)

In article <ROGER.90Aug9114200@rd11.zuken.co.jp> roger@zuken.co.jp (Roger Meunier) writes:
>When a C++ program exits, it calls a list of destructors to clean up
>static data.  But what happens when exit() is called after fork()?
>
>I ran into a problem with HP's implementation of Motif 1.0.  For the
>XmText widget, they allow Chinese character input by setting up a
>connection with an input server.  Apparently, they fork() the server
>on the first XmCreateText().  I noticed that in one of my applications,
>it was taking an extremely long time to create the first text widget
>(8+ sec.), and that core was being dumped during the creation.  Looking
>at the core file with cdb, I noticed that exit() was being called from
>the routine that did the fork(), and that subsequently all my static
>destructors were being called, including one that caused the core to
>be dumped (it was calling XCloseDisplay()!).  Why the *child* process
>should be trying to do this is beyond me.
>
>Has anyone else run into similar problems when fork()'ing in a C++
>environment?  Is this a design problem with the C++ static object clean-up
>strategy, or is HP's implementation of nlio forgetting to take C++ into
>account, or both?

I don't think this has much to do with HP's implementation, nor C++ -- it
is a general problem you have to watch out for when doing system(), popen()
and fork() under X.

Basically, your application's open connections to the X server take up file
descriptors, and these are all faithfully copied upon vfork()/fork()....

To fix the problem, you need to close the file descriptors after you
fork, e.g.:
  pid_t pid;
  if((pid = vfork()) == 0)
  {
    for(i=3;i<_NFILE;i++)  /* close all fd except stdin, stdout, and stderr */
        close(i);
    ...
   }

As to why the X implementation doesn't set the close-on-exec flag via
fcntl() to prevent this problem, only the experts know.

			--------------------

I'm trying to deal with a similar problem right now as a matter of fact.

Does anybody have a public domain (or non-restrictive-copyright) version of
popen() and system() that you'd be interested in sharing???

Actually, system() is easy... But I'm too lazy to go figure out how to do
popen() without sullying the pristine "clean-room" environment of my mind.

-------------------------------------------------------------------------------
	    Niels Mayer -- hplabs!mayer -- mayer@hplabs.hp.com
		  Human-Computer Interaction Department
		       Hewlett-Packard Laboratories
			      Palo Alto, CA.
				   *

roger@zuken.co.jp (Roger Meunier) (08/20/90)

In article <5768@hplabsz.HPL.HP.COM> mayer@hplabsz.HPL.HP.COM (Niels Mayer) writes:

 >I don't think this has much to do with HP's implementation, nor C++ -- it
 >is a general problem you have to watch out for when doing system(), popen()
 >and fork() under X.
 >
 >Basically, your application's open connections to the X server take up file
 >descriptors, and these are all faithfully copied upon vfork()/fork()....
 >
 >To fix the problem, you need to close the file descriptors after you
 >fork,               ^^^

I am not the one who is fork()'ing; Motif is.  My destructors get called
when the kanji input server (/usr/lib/nlio/serv/X11/xj0input) is spawned,
because exit() (rather than _exit()?) is being called in the child
environment.  My destructor calls XCloseDisplay(), at which time some
error occurs, and core is dumped because the error message cannot be
output.  Here's a sample stack trace of the core dump:

	 0 __doprnt + 0x6
	 1 __fprintf + 0x32
	 2 __XIOError + 0x30
	 3 __XReply + 0x20
	 4 _XSync + 0x52
	 5 _XCloseDisplay + 0x64
	...
	10 _STDmain_cxx_ ()
	11 _exit + 0x38
	12 __XIOError + 0x80
	13 __XReply + 0x20
	14 _XSync + 0x52
	15 _XCloseDisplay + 0x64
	...
	49003 _STDmain_cxx_ + 0x10
	49004 _exit + 0x38
	49005 _XHPInputChinese_t + 0x652
	49006 _XHPNlioctl + 0xac
	49007 _XmTextInputCreate + 0x218
	49008 _XmTextSetHighlight + 0x2f6
	49009 __XtAddDefaultConverters + 0x520
	49010 __XtCreate + 0x1da
	49011 _XtCreateWidget + 0xac
	49012 _XmCreateText + 0x1c
	...

In this case, the error during XCloseDisplay() causes a call to exit(),
which calls the destructors *again*, ad infinitum.  This doesn't occur
every time; usually _XIOError() bombs at the first _doprnt() and never
gets to call exit().

This raises another question: if static destructors can trigger an error
condition which in turn triggers a call to exit(), is there some standard
method for avoiding the above infinite looping?
--
Roger Meunier @ Zuken, Inc.  Yokohama, Japan	(roger@zuken.co.jp)

nick@esacs.UUCP (Nikolaos Tsivranidis) (03/08/91)

 Suppose you *have* to fork() a process and *not* do an exec(). 
 You end up with a child process that shares all the data
 of the parent (including her open file descriptors). Presumably
 you can now create a new window, and operate on the data space
 of the parent process while displaying on the windows of the
 child process.

 Questions:

 (1) This doesn't sound right to me, but I don't know exactly where
     the problems are. Is there a problem?

  (2) If one closes the Xserver connection and calls XtInitialize
      again, what happens? (If a segmentation fault produced a sound
      proportional to the seriousness of the error, how big would this
      sound be?)

  (3) If you have a lot of *application* specific data to display,
      and you would like to put the application in the background
      while displaying the data, what do you do? Remember, you only
      create the windows and display the data according to an application
      specific way.
      (If you don't understand (3) it is probably because I don't
       understand it either, this is somebody else's question.)

					- nick -