[comp.windows.x] R4 Athena Widget question.

spanki@color.ced.berkeley.edu (Frank Goodman) (02/24/90)

I've got a few questions about the quit functions of core clients in the R4 
distribution.

I'm writing an application that uses one of my own widgets under X11 R4
Athena. For a while, I was following the examples of the source code in
$TOP/clients. Most of these clients exit via a function that looks similar to
this.

Exit(w, call, client)
    Widget w;
    caddr_t call, client;
    {
    XtDestroyApplicationContext(app_con);
    exit(0);
    }

Now, from my own trauma with my application I have found that this will NOT
call ANY of the widget's destroyCallback procedures. I now understand why
(thanks to Paul Asente: asente@decwrl.dec.com). Now, many of the athena
widgets do indeed have destroy callbacks, so it would seem that any
application that exits in the above fashion is "doing the wrong thing".
Would you (Consortium Staff), say this is true? The reason I bring this up,
is basically for clarification for myself, and others. The documentation
covers XtDestroyWidget, and XtDestroyApplicationContext, but it doesn't
address this phenomenom at all. If a widget writer puts a destroycallback
into their widget, there is assumed to be a good reason for this. Now, In 
my eyes an application writer should not have to look through the widget 
code to see if the destroy callback is "worth calling" or not. In my case,
it was imperative that my destroyCallback got called, beacuse it has to
remove a 30MB tmp file.

The hack I'm using (again, thanks to Paul Asente) is as follows:


void Exit()
    {
    xtUnmapWidget(top);
    XtDestroyWidget(top);
    /* global flag */
    exitFlag = True;
    }

MainLoop()
    {
    while (1)
        {
	/* dpy, and app_con are global */
        XEvent event;
        XtAppNextEvent(app_con, &event);
        XtDispatchEvent(&event);
        if (exitFlag)
            {
            XFlush(dpy);
            break;
            }
        }
    XtDestroyApplicationContext(app_con);
    exit(0);
    }
In this way, by the time the flag is set, all the events (XtCallCallbacks)
are already on the que, so XFlush, moves 'm on through, then we exit.

I'm wondering what the deal is? Why did the Consortium Staff neglect this
aspect of exiting? It is well documented, that XtDestoryWidget is a two pass
operation, it's equally well ignored by the applciations in the
distribution. What gives?

Furthermore, I'm even more curious if this is the cause of the notorious
"Memory Leaks". In other words, I'm curious if every application that uses 
widgets, and exits without waiting for these callbacks are leaving stuff in 
the server and therefore it would seem to continually grow?

Also, Since every application that uses widgets has a toplevelshell, could 
there perhaps be some sort of event dispatched when that shell is finally
detroyed? Maybe you could then pass the toplevelwidget to a new
XtAppMainLoop, and it would exit appropriately when the shell is dead?


I would be really interested to hear what people think about this.
My hope is that someone can give me an explanation for these
inconsistencies or, explain to me (nicely please) why I don't know what 
I'm talking about.

Thanks
Frank.
---------------------------------------------------------------------------
Frank  Goodman				arpa:  spanki@CED.Berkeley.EDU
University of California, Berkeley	  or:  spanki%CED@jade.Berkeley.EDU
College of Environmental Design		uucp:  ...hplabs!ucbvax!ced!spanki 
S.I.S Research Laboratory	 	phone: Novelty item, not necessary
---------------------------------------------------------------------------

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (02/25/90)

    Furthermore, I'm even more curious if this is the cause of the notorious
    "Memory Leaks". In other words, I'm curious if every application that uses 
    widgets, and exits without waiting for these callbacks are leaving stuff in 
    the server and therefore it would seem to continually grow?

"The server don' 'llow no resource leakin' 'roun here."  The server doesn't
care "how" the client terminates, it always frees all resources created
(unless the client has explicitly asked for a Retain CloseDownMode).

kit@EXPO.LCS.MIT.EDU (Chris D. Peterson) (02/27/90)

> Exit(w, call, client)
>    Widget w;
>    caddr_t call, client;
>   {
>    XtDestroyApplicationContext(app_con);
>    exit(0);
>    }

> Now, from my own trauma with my application I have found that this will NOT
> call ANY of the widget's destroyCallback procedures. I now understand why
> (thanks to Paul Asente: asente@decwrl.dec.com). Now, many of the athena
> widgets do indeed have destroy callbacks, so it would seem that any
> application that exits in the above fashion is "doing the wrong thing".
> Would you (Consortium Staff), say this is true?


Since both the operating system and the X server are clever enough to free
up all resources associated with the client, it should be enough to just call
exit().  You can certainly be more clever, but it didn't seem worth putting a
bunch of code that doesn't accomplish anything into all the example programs.


						Chris D. Peterson     
						MIT X Consortium 

Net:	 kit@expo.lcs.mit.edu
Phone:   (617) 253 - 9608	
Address: MIT - Room NE43-213

spanki@color.ced.berkeley.edu (Frank Goodman) (02/27/90)

In article <9002261658.AA28416@expo.lcs.mit.edu>, kit@EXPO.LCS.MIT.EDU
(Chris D. Peterson) writes:
> 
> Since both the operating system and the X server are clever enough to free
> up all resources associated with the client, it should be enough to just call
> exit().  You can certainly be more clever, but it didn't seem worth putting a
> bunch of code that doesn't accomplish anything into all the example programs.
> 
> 
> 						Chris D. Peterson     
> 						MIT X Consortium 
I think the important issue here is that application programmers don't know the
contents or mechanisms of a widget. A widget writer is supossed to destroy
everything that needs to be destroyed in the destroy callback. An
application writer doesn't know what gets destroyed there, and shouldn't
have to go look. He should ALWAYS allow the widgets to exit properly.
Wether or not the OS or Server free the X resources, neither one are going
to remove my widget's 36 meg temp file. Something an application writer 
shouldn't have to worry about when he uses my widget. However, if he follows 
the core examples he will fill his filesystem pretty darn fast and accuse me 
of writing a bad widget.

I look to the core programs as examples, and I'm sure others do too. It
seems to me that they should either "do the right thing" or explain why they
don't. Just because you all know that none of the Athena widgets really need
a destroy callback (given the server and OS), doesn't mean that it is safe
to assume this for all widgets. Why did your widget writers even bother
putting in these callbacks, if you summarily ignore them? If they are truely 
meant as "examples", than I will argue that it was worth the extra code to 
exit correctly. Your examples make it harder for those of us out here writing 
more sophisticated/powerful widgets because applications writers who follow 
those examples will undoubtedly have as much trouble as I did figuring out 
the cause of their problem. If widget abstractions are supposed to be 
"private" from the application, then widget writers should be able to work 
under the assumption that application writers will "know how" to use the 
widgets. However, neither the examples, nor the documentation really address 
this phenomenon and my feelings are that maybe they should.

-Frank.

P.S. I don't mean to belabor the point, but I feel this is an important
issue. By exiting the way you suggest, you are implying that application
writers should also do this. I disagree.
---------------------------------------------------------------------------
Frank  Goodman				arpa:  spanki@CED.Berkeley.EDU
University of California, Berkeley	  or:  spanki%CED@jade.Berkeley.EDU
College of Environmental Design		uucp:  ...hplabs!ucbvax!ced!spanki 
S.I.S Research Laboratory	 	phone: Novelty item, not necessary
---------------------------------------------------------------------------

ben@hpcvlx.cv.hp.com (Benjamin Ellsworth) (02/28/90)

OK, I give.  The twists and turns of this thread have confused me.

Is the question "How to destroy a widget hierarchy?"

If you want to destroy a widget and all of its children you call
XtDestroyWidget.  Due to some funky-ness in the Xt implementation you
sometimes have to handshake an event through, but XtDestroyWidget will
destroy the widget and (if the widget was written correctly) all of the
private data associated with the widget.  What's so hard about that?

Is the question "How do you exit an Xt application?"

My personal favorite is "exit(0);"  This is UN*X and exit has well
defined behavior on all systems that I'm familiar with.  I suppose that
if one was particularly paranoid one could destroy all widget
hierarchies, then destroy all app contexts, and then exit.  What's hard
about that?

Of course, I could have missed the point entirely...

-----------------------------------------------------------------------
Benjamin Ellsworth      | ben@cv.hp.com                | INTERNET
Hewlett-Packard Company | {backbone}!hplabs!hp-pcd!ben | UUCP
1000 N.E. Circle        | (USA) (503) 750-4980         | FAX
Corvallis, OR 97330     | (USA) (503) 757-2000         | VOICE
-----------------------------------------------------------------------
                     All relevant disclaimers apply.
-----------------------------------------------------------------------

kit@EXPO.LCS.MIT.EDU (Chris D. Peterson) (03/01/90)

> > me
> Frank
me

> > Since both the operating system and the X server are clever enough to free
> > up all resources associated with the client, it should be enough to just call
> > exit().  You can certainly be more clever, but it didn't seem worth putting a
> > bunch of code that doesn't accomplish anything into all the example programs.

> I think the important issue here is that application programmers don't know the
> contents or mechanisms of a widget. A widget writer is supossed to destroy
> everything that needs to be destroyed in the destroy callback.

After thinking about this some more I agree something else should be happening
here.  We will look into solving the problem.

						Chris D. Peterson     
						MIT X Consortium 

Net:	 kit@expo.lcs.mit.edu
Phone:   (617) 253 - 9608	
Address: MIT - Room NE43-213

asente@decwrl.dec.com (Paul Asente) (03/01/90)

In article <1990Feb26.192750.15430@agate.berkeley.edu> spanki@color.ced.berkeley.edu (Frank Goodman) writes:
...a bunch of stuff berating the MIT applications for ust exiting instead
of destroying their widgets...

When you write a non-toolkit program that uses malloc, do you explicitly
free all of the allocated storage before you exit?  Of course you don't.
You know that malloc doesn't consume any system resources that won't be
recovered when you program exits.  This places some future constraints on
malloc (that it *never* be changed to consume resources that need explicit
freeing) but it's considered a reasonable tradeoff not to have to do a
whole slew of completely useless work before you exit the program.

The situation with widgets is completely analogous.  If a widget consumes
a resource that needs explicit freeing, the widget documentation had
better document this so that the application can be sure to destroy the
widget before exiting.  Otherwise there is no point in having the
program spend time freeing storage, destroying windows, freeing fonts and
graphics contexts, and so forth when these things would all be done
automatically (and much more quickly) if the application just exits.

The destroy methods and callbacks are mostly for applications that need to
continue after destroying some or all of their widgets.  The toolkit was
not designed to require or encourage explicit destruction in normal cases;
the preferred way to exit an application has always been to call exit.

We could have made things more convenient for the cases where a particular
kind of widget needs to be destroyed, but the current scheme of setting a
flag and writing your own event loop is not difficult to program and works
just fine.

	-paul asente
	    asente@decwrl.dec.com	decwrl!asente

ben@hpcvlx.cv.hp.com (Benjamin Ellsworth) (03/01/90)

Somebody condescended to give me the genesis of this thread.  To quote

	The problem is that Joe Blow (whoever started this thread)
	wrote a widget that creates a 32 meg temp file.  When
	applications exit with "exit(0);" the destroy callback for
	this widget is not called, and the file is not deleted.

GOOD HEAVENS!  Is THAT the problem???!!!!

[ ...grumble, grumble... ]

Every UN*X system that I've used allows the programmer to create a
file, and then unlink it from the file system.  As long as it is not
closed, it exists known only by the program until it exits.  (The
Morris worm exploited this behavior.)  When the program calls exit(),
the system calls clean everything up very nicely.

----

Ben

"It is a poor workman who blames his tools..."

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (03/02/90)

    If a widget consumes
    a resource that needs explicit freeing, the widget documentation had
    better document this so that the application can be sure to destroy the
    widget before exiting.

This seems like bad design.  I may have a Text widget today that doesn't do
checkpoint files, so my documentation doesn't say it has to be destroyed, and
the application believes this and blithely calls exit.  Tomorrow I add
checkpoint files, thinking this to be a nice addition from the user perspective,
and suddenly I have to ask all developers to rewrite their applications?  That
doesn't sound like a very good design.

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (03/02/90)

    Every UN*X system that I've used allows the programmer to create a
    file, and then unlink it from the file system.

This doesn't help for files that you *want* to stay around in the
event of a crash.

ben@HPCVXBEN.CV.HP.COM (Benjamin Ellsworth) (03/02/90)

[This is getting ridiculous...]

> 
>     Every UN*X system that I've used allows the programmer to create a
>     file, and then unlink it from the file system.
> 
> This doesn't help for files that you *want* to stay around in the
> event of a crash.

Very good Bob, but according to my source, Mr. Blow *wanted* a TEMP 
file.  It was the fact that an *unwanted* file was left after a crash
that started this whole thing.  Had Mr. Blow been finding his widget to
be leaving behind mega-bytes of useful data I'm sure that he would have
never complained about file space consumption.  Your comment seems a 
bit out of context.

---

Ben

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (03/02/90)

    Very good Bob, but according to my source, Mr. Blow *wanted* a TEMP 
    file.

A text editor checkpoint file is a "TEMP" file, in my mind.  Yes, there is
a distinction between temp files that should or shouldn't survive a crash
of the client, but they're both "temporary".

    It was the fact that an *unwanted* file was left after a crash
    that started this whole thing.

No, it wasn't a *crash*, it was a normal termination of the client.
The argument was that "normal" termination of a client should allow
widgets to "clean up" in some fashion, yet the way most core clients
exit doesn't permit this.  This is entirely distinct from a crash,
and bears directly on the distinction between the two classes of "temp"
file.

    Your comment seems a bit out of context.

I'm simply generalizing from the specific example to argue that the mechanism
is inappropriate for a certain kind of widget state.  And yes, Mr. Blow
could probably solve his particular problem under a POSIX system, but Xt is
supposed to be OS independent.

kit@EXPO.LCS.MIT.EDU (Chris D. Peterson) (03/03/90)

> > 
> >     Every UN*X system that I've used allows the programmer to create a
> >     file, and then unlink it from the file system.
> > 
> > This doesn't help for files that you *want* to stay around in the
> > event of a crash.

> Very good Bob, but according to my source, Mr. Blow *wanted* a TEMP 
> file.  It was the fact that an *unwanted* file was left after a crash
> that started this whole thing.  Had Mr. Blow been finding his widget to
> be leaving behind mega-bytes of useful data I'm sure that he would have
> never complained about file space consumption.  Your comment seems a 
> bit out of context.

Bob's message is an attempt to help people understand the more general
problem.  A problem that may be a design flaw in the Toolkit.  I will try 
to state the general problem the we seem to have uncovered by thinging about
how to solve the specific problem of the user.

Problem:

It is very difficult for an application writer to shutdown an Xt client cleanly.
If she makes the assumption suggested by the originaly poster then widgets are
the only ones who have enough information to clean up all their resources.  The
programmer must be sure that all widgets get destroyed before the application
exits.  The current Xt specification is unclear about whether or not this
happens automatically when your call XtCloseDisplay, and
XtDestroyApplicationContext.

Paul has proposed that there is insuffecient mechanism in the toolkit to
effeciently clean up these resources since there are really three types of
widget resources:

1) Those that must always be cleaned up by the widget.

2) Those that will automatically be cleaned up by the operating system when
   the program exits.

3) Those that will be automatically cleaned up by the X Server when the display
   connection is closed, or the program exits.

It seems that for optimal performance there are really three different kinds of
widget cleanup that may occure.

Solution:

We have begun internal Consortium discussion on this topic, and will attempt to
come up with a solution, but since this discussion is very preliminary I do not
want to comment further in this public forum.


						Chris D. Peterson     
						MIT X Consortium 

Net:	 kit@expo.lcs.mit.edu
Phone:   (617) 253 - 9608	
Address: MIT - Room NE43-213

rlk@THINK.COM (Robert L. Krawitz) (03/05/90)

   Date: 1 Mar 90 01:35:44 GMT
   From: hp-pcd!hpcvlx!ben@hplabs.hp.com  (Benjamin Ellsworth)

   Every UN*X system that I've used allows the programmer to create a
   file, and then unlink it from the file system.  As long as it is not
   closed, it exists known only by the program until it exits.  (The
   Morris worm exploited this behavior.)  When the program calls exit(),
   the system calls clean everything up very nicely.

This doesn't work too well on NFS filesystems...

ames >>>>>>>>>  |	Robert Krawitz <rlk@think.com>	245 First St.
bloom-beacon >  |think!rlk	(postmaster)		Cambridge, MA  02142
harvard >>>>>>  .	Thinking Machines Corp.		(617)876-1111

ben@hpcvlx.cv.hp.com (Benjamin Ellsworth) (03/06/90)

>> [... open and unlink as a way to keep a hidden tmp file...]
>
> This doesn't work too well on NFS filesystems...

I haven't used the approach across an NFS link.  The SVID would lead on
to believe that the approach should work regardless.  IMO this reflects
negatively on NFS (as do many other aspects of its implementation).

Thanks for the warning.

---

Ben

ben@hpcvlx.cv.hp.com (Benjamin Ellsworth) (03/06/90)

> I'm simply generalizing from the specific example to argue that the 
> mechanism is inappropriate for a certain kind of widget state.

Thanks for the clarification.  I hope that Mr. Blow is successful in
his application, and I hope that the Intrinsics can enrichen their
object model to provide for hygenic object destruction.

Later,

Ben

guy@auspex.auspex.com (Guy Harris) (03/07/90)

 >   Every UN*X system that I've used allows the programmer to create a
 >   file, and then unlink it from the file system.  As long as it is not
 >   closed, it exists known only by the program until it exits.  (The
 >   Morris worm exploited this behavior.)  When the program calls exit(),
 >   the system calls clean everything up very nicely.
 >
 >This doesn't work too well on NFS filesystems...

Gee, it works just fine on all the NFS filesystems *I've* used.  The
trick the NFS clients with which I'm familiar use is that instead of
unlinking the file, they rename it to a temporary name, and when the
last process on that client that has the file open closes it, they
remove it.  This works for the case of unlinking an open temporary file.
(Yes, if the client machine crashes, the file doesn't get unlinked. 
The solution I've seen is to use a "find" script to remove files with
names of the sort used as temporary names.)

gary@dgcad.SV.DG.COM (Gary Bridgewater) (03/07/90)

In article <9003042232.AA01692@underprize.think.com> rlk@THINK.COM (Robert L. Krawitz) writes:
>
>   Date: 1 Mar 90 01:35:44 GMT
>   From: hp-pcd!hpcvlx!ben@hplabs.hp.com  (Benjamin Ellsworth)
>
>   Every UN*X system that I've used allows the programmer to create a
>   file, and then unlink it from the file system.  As long as it is not
>   closed, it exists known only by the program until it exits.  (The
>   Morris worm exploited this behavior.)  When the program calls exit(),
>   the system calls clean everything up very nicely.
>
>This doesn't work too well on NFS filesystems...

Whose? What rev? What fails?

Scenario:
	open local file
	remove file
	do stuff with file
	system crashed
	data is gone

Scenario:
	remote shell a program that opens a "local" file over "there"
	etc.

Scenario:
	open file on NFS mounted disk
	remove file
	do stuff with file
	server crashes
	server comes up
	continue doing stuff with file
	exit {data may hang around in funny named file - cron cleans up}

Scenario:
	open file on NFS mounted disk
	remove file
	do stuff with file
	"my" system crashes
	data is gone

The difference with the NFS mounted file is that it gets renamed to
a funny name instead of being instantly destroyed. It is gone in the
sense that if you or anyone reopens the same original name it will
not exist. How is this a problem? It is a bit of an inconvenience
but, to our site, very much worth it.
-- 
Gary Bridgewater, Data General Corporation, Sunnyvale California
gary@sv.dg.com or {amdahl,aeras,amdcad}!dgcad!gary
The impossible we understand right away - the obvious takes a little longer.