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. *
chan@hpfcmgw.HP.COM (Chan Benson) (08/11/90)
> the pristine "clean-room" environment of my mind. > > Niels Mayer -- hplabs!mayer -- mayer@hplabs.hp.com Hmmmm. Must be a different Niels Mayer. But enough levity. If I read the original question correctly, the fork is being done in the library code, so the application programmer can't close all the fd's after the fork. Strangely enough though, the library code *is* closing all the fd's after the fork. Does your code do any forking? There is some weird stuff in there to handle SIGCLD when the NLS server is forked (actually as a grandchild of the original process). Any NLS gurus out there? -- Chan Benson HP Fort Collins
dave@dptechno.UUCP (Dave Lee) (08/13/90)
In article <5768@hplabsz.HPL.HP.COM> mayer@hplabs.hp.com (Niels Mayer) writes: >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()? > > 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. > >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. A cleaner way to handle the above problems (if indeed they are due to the open fd from a display connection) is ... #include <fcntl.h> fcntl( DISPLAY_PTR , F_SETFD , 1 ); Where "DISPLAY_PTR" is a pointer to the open Display from XOpenDisplay(); Insert this just after opening the display, or before doing any system() popen(), or fork()/exec. This should then remove the need to recode system() or popen() from scratch. # # # # # # -- Dave Lee uunet!dptechno!dave
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)