[comp.sys.amiga.tech] CloseWindowSafely

chk@dretor.dciem.dnd.ca (C. Harald Koch) (11/04/88)

I am writing a program that opens lots of windows, so I need to share a
single message port among them. Can someone please send source for
the CloseWindowSafely() routine?

	aTdHvAaNnKcSe!

--
C. Harald Koch		NTT Systems, Inc., Toronto, Ontario
chk@zorac.dciem.dnd.ca, chk@gpu.utcs.toronto.edu, chk@chk.mef.unicus.com
Note: some sites may still have zorac.dciem.dnd.ca as zorac.ARPA.
"I give you my phone number. If you worry, call me. I'll make you happy."

cunniff@hpfcdc.HP.COM (Ross Cunniff) (01/28/89)

Regarding the AmigaMail function CloseWindowSafely() (which I
can't seem to find anywhere (hint,hint)), I have come up with
something that seems to work for windows which are sharing IDCMPs:

	ILock = LockIBase( 0 );

		while( Msg = GetMsg( Win->UserPort ) ) {
		    ReplyMsg( Msg );
		}
		Win->UserPort = NULL;
		CloseWindow( Win );

	UnlockIBase( ILock );

My questions about this are:

	1. Will this guarantee no GURUs?  (The code without the
	   LockIBase and the while( Msg = Getmsg() ) will GURU
	   if there are any pending messages to Win)

	2. Is it desirable to have the CloseWindow inside the
	   LockIBase()/UnlockIBase() protected region?  It seems
	   to work and has caused no problems, but it makes me
	   nervous to call Intuition functions inside the
	   protected region.  On the other hand, there may
	   be a window (pun intended) of vulnerability if the
	   UnlockIBase() is placed BEFORE the CloseWindow().

	3. There is no 3.

Answers, anybody?

					Ross Cunniff
					Hewlett-Packard Colorado Languages Lab
					...{ucbvax,hplabs}!hpfcrt!cunniff
					cunniff%hpfcrt@hplabs.ARPA

jimm@amiga.UUCP (Jim Mackraz) (01/30/89)

In article <11640008@hpfcdc.HP.COM> cunniff@hpfcdc.HP.COM (Ross Cunniff) writes:
)Regarding the AmigaMail function CloseWindowSafely() (which I
)can't seem to find anywhere (hint,hint)), I have come up with
)something that seems to work for windows which are sharing IDCMPs:
)
)	ILock = LockIBase( 0 );
)
)		while( Msg = GetMsg( Win->UserPort ) ) {
)		    ReplyMsg( Msg );
)		}
)		Win->UserPort = NULL;
)		CloseWindow( Win );
)
)	UnlockIBase( ILock );

)My questions about this are:
)
)	1. Will this guarantee no GURUs?  (The code without the
)	   LockIBase and the while( Msg = Getmsg() ) will GURU
)	   if there are any pending messages to Win)

No guarantee, but I can assure you there is a potential for deadlocks.

)	2. Is it desirable to have the CloseWindow inside the
)	   LockIBase()/UnlockIBase() protected region?  It seems
)	   to work and has caused no problems, but it makes me
)	   nervous to call Intuition functions inside the
)	   protected region.  On the other hand, there may
)	   be a window (pun intended) of vulnerability if the
)	   UnlockIBase() is placed BEFORE the CloseWindow().

As well it should make you nervous.  The purposes of LockIBase() are explicitly
stated: for quick inspection of the public data of IntuitionBase which would
not otherwise be safe.

Making assumptions about Intuition's locking protocol is not wise in the least.

The problem with your example is that it clears ALL the messages from the port,
even those intended for windows other than the one you are closing.  Indeed,
you must get the messages out of there for the window you close, also insuring
that no others will be sent and that Intuition won't deallocate the port
that other windows are using.  Use CloseWindowSafely().  There's been a modification
to it to check that you don't pass a NULL window, or something, so the
copy I have on line isn't the best.  If it doesn't appear magically soon, I'll
try to get it posted.

)	3. There is no 3.

Good, then you only missed 2 out of 2. ;^)

)					Ross Cunniff
-- 
Jim Mackraz, I and I Computing	   	"Like you said when we crawled down
{cbmvax,well,oliveb}!amiga!jimm          from the trees: We're in transition."
							- Gang of Four
Opinions are my own.  Comments are not to be taken as Commodore official policy.

jimm@amiga.UUCP (Jim Mackraz) (04/06/89)

So, I found my copy of CloseWindowSafely(), so I thought I'd toss it
out there for those who haven't got it.  I apologize to those who
asked for me to mail it to them and got no response.  I knew it
was around somewhere.

Some people think that this function should test for NULL window pointer.  Bah.

--------------------- cut here --------------------------------
/* CloseWindowSafely.c -- use like crazy
 * Author: Neil Katin (edited by Jim Mackraz)
 */

#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/ports.h"
#include "intuition/intuition.h"

/* this function closes an Intuition window
 * that shares a port with other Intuition
 * windows (or other compatible IPC).
 *
 * It is careful to set the window's UserPort to
 * null before closing, and to reply to
 * any messages that might be pending.
 */

CloseWindowSafely( win )
struct Window *win;
{
    /* we forbid here to keep out of race conditions with Intuition */
    Forbid();

    /* send back any messages for this window 
     * that have not yet been processed
     */
    StripIntuiMessages( win->UserPort, win );

    /* clear UserPort so Intuition will not free it */
    win->UserPort = NULL;

    /* tell inuition to stop sending more messages */
    ModifyIDCMP( win, 0L );

    /* turn tasking back on */
    Permit();

    /* and really close the window */
    CloseWindow( win );
}


/* Remove and reply any IntuiMessages hanging off of a port
 * which were addressed to a particular window.
 * Note that technique does not rely on ln_Succ of a message
 * after it has been replied.
 */
StripIntuiMessages( mp, win )
struct MsgPort *mp;
struct Window *win;
{
    struct IntuiMessage *msg;
    struct Node *succ;

    msg = (struct IntuiMessage *) mp->mp_MsgList.lh_Head;

    while( succ = msg->ExecMessage.mn_Node.ln_Succ ) {

	if( msg->IDCMPWindow ==  win ) {
	    /* Intuition is about to rudely free this message.
	     * Make sure that we have politely sent it back.
	     */
	    Remove( msg );

	    ReplyMsg( msg );
	}
	    
	msg = (struct IntuiMessage *) succ;
    }
}

enjoy
	jimm
-- 
Jim Mackraz, I and I Computing	   	"Like you said when we crawled down
{cbmvax,well,oliveb}!amiga!jimm          from the trees: We're in transition."
							- Gang of Four
Opinions are my own.  Comments are not to be taken as Commodore official policy.

usenet@cps3xx.UUCP (Usenet file owner) (12/11/89)

: From: ames!dtg.nsc.com!waggoner (Mark Waggoner)
: To: porkka@frith.egr.msu.edu
: Subject: CloseWindowSafely()
: 
: Hello,
:   I've been following, and slightly involved in, the recent discussions
: about sharing a message port among several windows.  I've used this method
: before and, when closing a window, I merely made sure there were no messages
: waiting at the msgport and did a normal CloseWindow().  I have seen
This is basically exactly what CloseWindowSafely does.
: you and others mention CloseWindowSafely a number of times but I can find no
: mention of such a routine in the many manuals I have.  The closest they 
: come to it is a strong warning to make sure you have no messages pending from
: the window when it is closed.
: 
:   Can you give me the details of CloseWindowSafely() or send the code for it?
: I want to be sure I am doing everything I can to prevent system crashes.
: 
: Thanks,
:   Mark Waggoner
:   waggoner@dtg.nsc.com
: 

Here is a rough sketch of CloseWindowSafely
	CloseWindowSafely(win)
	    struct Window *win;
	{
	    struct MsgPort myport = win->UserPort;
	    struct Node *x, *y;
	    struct IntuiMsg *t;

	    SetIDCMP(win, 0L); /* Inhibit any further msgs for this window*/
	    win->UserPort=0;   /* Prevent intuition from freeing my port */

	    Forbid(); /* Prevent the Msg system from posting
			 messages to "myport" while I fiddle with it */
	    for(x=myport->head; x!=endoflist;x=y) {
		y=x->next;
		t=x;
		if(t->window == win) Reply(x); /* Send it back*/
	    }
	    Permit();
	    CloseWindow(win);
	}

Why all of this?
Intuition keeps a list of all the msgs bodies that it has used
for a particular window. When the window is closed, it simply FreeMems()
them. If they are still part of a list (say, attached to a MsgPort)
then that list will become currupted, and call Mr. GURU.

So three thing need to be done before closing the window. First, stop
intuition from sending any new msgs to the msgport from this window.
Second clear the UserPort field of the Window so that intuition
won't free the port for you, since you are still using it.
Third, reply to msgs for this window that are already at the port,
thusly removing them from the ports msg list.

Then the window can be closed. The msgs that were used for this
window will then be freed, which is OK since they are not part of
you MsgPort msg list.

For a working example see my "windows.c" code in my "hyperhelp" program.
This example also deals with fonts. THis is archived at "uunet.uu.net"
in the "pub/comp.sources.amiga" directory", or I could email it to
you.

The orignal "closeWindowSafely" is on a fishdisk I think.

It should also be in release 1.4 somewhere.

I can't wait for 1.4.
 Joe Porkka   porkka@frith.egr.msu.edu

mks@cbmvax.commodore.com (Michael Sinz - CATS) (12/13/89)

In article <5740@cps3xx.UUCP> porkka@frith.egr.msu.edu () writes:
>
>: From: ames!dtg.nsc.com!waggoner (Mark Waggoner)
>: To: porkka@frith.egr.msu.edu
>: Subject: CloseWindowSafely()
>: 
>: Hello,
>:   I've been following, and slightly involved in, the recent discussions
>: about sharing a message port among several windows.  I've used this method
>: before and, when closing a window, I merely made sure there were no messages
>: waiting at the msgport and did a normal CloseWindow().  I have seen
>This is basically exactly what CloseWindowSafely does.
>: you and others mention CloseWindowSafely a number of times but I can find no
>: mention of such a routine in the many manuals I have.  The closest they 
>: come to it is a strong warning to make sure you have no messages pending from
>: the window when it is closed.
>: 
>:   Can you give me the details of CloseWindowSafely() or send the code for it?
>: I want to be sure I am doing everything I can to prevent system crashes.
>: 
>: Thanks,
>:   Mark Waggoner
>:   waggoner@dtg.nsc.com
>: 
>
>Here is a rough sketch of CloseWindowSafely
>	CloseWindowSafely(win)
>	    struct Window *win;
>	{
>	    struct MsgPort myport = win->UserPort;
>	    struct Node *x, *y;
>	    struct IntuiMsg *t;
>
>	    SetIDCMP(win, 0L); /* Inhibit any further msgs for this window*/
>	    win->UserPort=0;   /* Prevent intuition from freeing my port */
>
>	    Forbid(); /* Prevent the Msg system from posting
>			 messages to "myport" while I fiddle with it */
>	    for(x=myport->head; x!=endoflist;x=y) {
>		y=x->next;
>		t=x;
>		if(t->window == win) Reply(x); /* Send it back*/
>	    }

You forgot to remove the message from the message port.  This could
cause (actually it WILL cause) a GURU.

Using the loop you have there, the line with the if(t->window...)
should be replaced by:

if(t->window==win)
{
   Remove(t);
   Reply(t);
}

>	    Permit();
>	    CloseWindow(win);
>	}
>
>Why all of this?
>Intuition keeps a list of all the msgs bodies that it has used
>for a particular window. When the window is closed, it simply FreeMems()
>them. If they are still part of a list (say, attached to a MsgPort)
>then that list will become currupted, and call Mr. GURU.
>
>So three thing need to be done before closing the window. First, stop
>intuition from sending any new msgs to the msgport from this window.
>Second clear the UserPort field of the Window so that intuition
>won't free the port for you, since you are still using it.
>Third, reply to msgs for this window that are already at the port,
>thusly removing them from the ports msg list.
>
>Then the window can be closed. The msgs that were used for this
>window will then be freed, which is OK since they are not part of
>you MsgPort msg list.
>
>For a working example see my "windows.c" code in my "hyperhelp" program.
>This example also deals with fonts. THis is archived at "uunet.uu.net"
>in the "pub/comp.sources.amiga" directory", or I could email it to
>you.
>
>The orignal "closeWindowSafely" is on a fishdisk I think.

And in an old AmigaMail and in the new RKM Libraries & Devices volume.

>
>It should also be in release 1.4 somewhere.
>
>I can't wait for 1.4.
> Joe Porkka   porkka@frith.egr.msu.edu

/----------------------------------------------------------------------\
|      /// Michael Sinz -- CATS/Amiga Software Engineer                |
|     ///  PHONE 215-431-9422  UUCP ( uunet | rutgers ) !cbmvax!mks    |
|    ///                                                               |
|\\\///          When people are free to do as they please,            |
| \XX/                they usually imitate each other.                 |
\----------------------------------------------------------------------/

jimm@amiga.UUCP (Jim Mackraz) (12/14/89)

In article <8976@cbmvax.commodore.com> mks@cbmvax.commodore.com (Michael Sinz - CATS) writes:
)>Here is a rough sketch of CloseWindowSafely
)>	CloseWindowSafely(win)
)>	    struct Window *win;
)>	{
)>	    struct MsgPort myport = win->UserPort;
)>	    struct Node *x, *y;
)>	    struct IntuiMsg *t;
)>
)>	    SetIDCMP(win, 0L); /* Inhibit any further msgs for this window*/
)>	    win->UserPort=0;   /* Prevent intuition from freeing my port */
)>
)>	    Forbid(); /* Prevent the Msg system from posting
)>			 messages to "myport" while I fiddle with it */
)>	    for(x=myport->head; x!=endoflist;x=y) {
)>		y=x->next;
)>		t=x;
)>		if(t->window == win) Reply(x); /* Send it back*/
)>	    }
)
)You forgot to remove the message from the message port.  This could
)cause (actually it WILL cause) a GURU.
)
)Using the loop you have there, the line with the if(t->window...)
)should be replaced by:
)
)if(t->window==win)
){
)   Remove(t);
)   Reply(t);
)}
)
)>	    Permit();
)>	    CloseWindow(win);
)>	}

I think you've got it close, but the neatest way to walk an exec list
with the option of removing/replying the current node is probably:

	for ( node = list->lh_Head; succ = node->ln_Succ; node = succ )

    jimm

-- 
--------------------------------------------------	- opinions by me
"This voice console is a *must*.  I press Execute. 
 `Hello, I know that you've been feeling tired.
  I bring you love and deeper understanding.' "		-lyrics by Kate Bush

usenet@cps3xx.UUCP (Usenet file owner) (12/15/89)

In article <5016@amiga.UUCP> jimm@batgirl.UUCP (Jim Mackraz) writes:
>In article <8976@cbmvax.commodore.com> mks@cbmvax.commodore.com (Michael Sinz - CATS) writes:

Alright already!

Here is the actual code extract from the hyperhelp program.
It deals with fonts too, but you can cut that out yerslevs.

void
CWS(win,font)
    struct Window *win;
    struct TextFont *font;
{
    struct MsgPort *mp = (struct MsgPort *)win->UserPort;
    struct IntuiMessage *im, *succ;

    if(win==0) {
	return;
    }
    removemenu(win);
    Forbid();
    im = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
    while ( succ=(struct IntuiMessage *)im->ExecMessage.mn_Node.ln_Succ ) {
       if ( im->IDCMPWindow == win ) {
	  Remove ( im );
	  ReplyMsg( im );
       }
       im = succ;
    }
    win->UserPort = 0;
    ModifyIDCMP( win, 0L );
    Permit();
    CloseWindow( win );
    if(font) CloseFont(font);
}
 Joe Porkka   porkka@frith.egr.msu.edu