[comp.windows.x] fork

zjmw0a@apctrc.trc.amoco.com (Joe M. Wade) (09/08/89)

In an effort to separate functionality between programs, one of my 
colleagues (cohorts?) produced code using popen to start another
process which would use X to plot data created by the initial 
process. He then found the initial process had to be forked so
that the command widget which spawned the popen would return to
its sensitive state. Everything works hunky-dory except for one 
thing-the initial process dies when the quit button is pushed,
but the window doesn't go away until the spawned-off process is
also exited. Killing the window manager didn't help, although it 
seems as though that would probably be the source of the difficulty.
Below is a short piece of code demonstrating the problem. It produces
two buttons, fork and quit. If you hit fork, it does a popen of 
this same process. Try using the quit button of the original process
and its pid disappears, but the windows remain.

Pertinent info: Sun 3/60 OS 4.0.1, X11R3, twm

#include <stdio.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>
#include <X11/Cardinals.h>
#include <X11/Box.h>
#include <X11/Command.h>
#include <X11/Shell.h>

void quit();
void fork_process();

main(argc, argv)
int argc;
char *argv[];
    {
    extern void time_out();

    Widget toplevel, outerform, quitter, forker;
    int screen;
    Display *display;
    Arg arg[5];
    int fork_value;

    /*
     * fork this process 
     */
    if ( (fork_value = fork()) != 0 )
        exit(0);

    toplevel = XtInitialize(NULL, "XLabel", NULL, 0, &argc, argv);
    display = XtDisplay(toplevel);
    screen = XDefaultScreen(display);

    outerform = XtCreateManagedWidget("outerform", boxWidgetClass, toplevel,
                                   (Arg*) arg, NULL);

    XtSetArg(arg[0], XtNlabel, (String) "Quit");
    quitter = XtCreateManagedWidget("Quit", commandWidgetClass,
                                    outerform, (Arg*) arg, ONE);

    /*
     * Create a command widget to popen a new process
     */
    XtSetArg(arg[0], XtNlabel, (String) "Fork");
    forker = XtCreateManagedWidget("Fork", commandWidgetClass,
                                    outerform, (Arg*) arg, ONE);

    XtAddCallback(quitter, XtNcallback, quit, &toplevel);
    XtAddCallback(forker, XtNcallback, fork_process, NULL);

    XtRealizeWidget(toplevel);

    time_out();
    XtMainLoop();
    }

void fork_process()
    {
    FILE *fptr;
    /*
     * start a new process
     */
    fptr = popen( "fork", "r");
    pclose( fptr );
    return;
    }

void quit ( button, top_widget )
Widget button;
caddr_t *top_widget;
/* 
 * destroy the top level widget and exit 
 */
    {
    XtDestroyWidget( *((Widget *) top_widget) );
    exit (0);
    }

Any info/input would be greatly appreciated.

*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
*  Joe M. Wade (zjmw0a@apctrc.trc.amoco.com) (918) 660-4387    *
*  Amoco Research Center * 4502 E. 41st St. * Tulsa, OK  74102 *
*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *

DCOOPER%ESDSDF.DECnet@CRDGW1.GE.COM (09/08/89)

Excerpt of message <1015@apctrc.UUCP> from Joe M. Wade:

>
> ...Everything works hunky-dory except for one
> thing-the initial process dies when the quit button is pushed,
> but the window doesn't go away until the spawned-off process is
> also exited.
>

This bug has bitten me and a number of others.  The problem is that
the socket is not closed on exec, therefore the window does not disappear
until the socket is finally closed when the process terminates.

My solution was to set close-on-exec by:

	#include <fcntl.h>

		...

	fcntl(ConnectionNumber(XtDisplay(toplevel)), F_SETFD, 1);

where toplevel is the widget returned from XtInitialize.


I submitted this problem to xbugs but it was rejected.

(denial is the first step in my debugging process too  :-)


Dwight Cooper
GE Electronic Systems Dept.
dcooper%esdsdf.decnet@crd.ge.com

spencer@eecs.umich.edu (Spencer W. Thomas) (09/08/89)

Problem summary: process forks, then exits, but windows stay up until
subprocess also exits.

Solution: (I think) close the display connection after fork and before
exec.  You can set the "close on exec" flag for the display connection by:

#include <fcntl.h>

	fcntl( ConnectionNumber(display), F_SETFD, 1 );

Oddities dept: I had to make one other change to get the program to
work as advertised: I had to change the pclose to a close, apparently
pclose (Sun OS 4.0.1) waits for the child to exit?


--
=Spencer (spencer@eecs.umich.edu)

mouse@lightning.mcrcim.mcgill.EDU (der Mouse) (03/06/91)

> I'm writing a Motif application which requires me to fork() and
> continue processing with the same windows & environment.  The first
> time I try to bring up a new window after the fork(), I get the
> following error:

> X Error of failed request:  BadIDChoice (invalid resource ID chosen for this connection)

[...]

> I think that I have to create a new connection to the original
> display... but I don't know how to do that.  (This is the deepest
> I've had to delve into Xlib.)

You are correct.  When a process with an X connection open fork()s, at
most one of the resulting two processes can do anything to the
connection (where XCloseDisplay counts as doing something).  One of the
processes should probably close the connection out from under Xlib,
with close(XConnectionNumber(dpy)), and *then* XCloseDisplay() (to free
up the Xlib data structures) and open a new connection.

How this relates to toolkits and higher layers I have no idea.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu