[comp.sys.amiga.programmer] Question on AbortIO

leh@otter.cis.ufl.edu (Les Hill) (05/21/91)

I have run into a situation which is not clearly documented (to me anyways) in the
RKM's (v1.2 ?).  Below I have included the relevant fragments of code:
...
   struct MsgPort *read_port, *write_port;
   struct IOExtSer *read_req, *write_req;
...
   BYTE dev_error;
   struct Message *read_msg;
...
   /* Clean up */
   if (!CheckIO(read_req)) {
      AbortIO(read_req);
      if (dev_error = WaitIO(read_req)) {
         printf("Error waiting for aborted read -- %d\n", dev_error);
         goto cleanup_8;
      }
      read_msg = GetMsg(read_port); // not necessary?
   }
...

The situation is this: a CMD_READ request *should* be queued at the device
(the CheckIO() should confirm this), the CMD_READ request is then aborted and
a WaitIO() follows as recommended in the RKMs; the WaitIO() returns a -2
(aborted request.)

The question that comes to mind is: does WaitIO() dequeue the reply at read_port (read_port is the reply port for read_req) regardless of the error?
Additionally, do I need the GetMsg()?

Thanks in advance,

Les
-- 
Extraordinary crimes against the people and the state have to be avenged by
agents extraordinary.  Two such people are John Steed -- top professional, and
his partner, Emma Peel -- talented amateur; otherwise known as "The Avengers."
INTERNET: leh@ufl.edu  UUCP: ...!gatech!uflorida!leh  BITNET: vishnu@UFPINE

carolyn@cbmvax.commodore.com (Carolyn Scheppner - CATS) (05/21/91)

In article <28630@uflorida.cis.ufl.EDU> leh@otter.cis.ufl.edu (Les Hill) writes:
>I have run into a situation which is not clearly documented (to me anyways) in the
>RKM's (v1.2 ?).  Below I have included the relevant fragments of code:
>...
>   struct MsgPort *read_port, *write_port;
>   struct IOExtSer *read_req, *write_req;
>...
>   BYTE dev_error;
>   struct Message *read_msg;
>...
>   /* Clean up */
>   if (!CheckIO(read_req)) {
>      AbortIO(read_req);
>      if (dev_error = WaitIO(read_req)) {
>         printf("Error waiting for aborted read -- %d\n", dev_error);
>         goto cleanup_8;
>      }
>      read_msg = GetMsg(read_port); // not necessary?
>   }
>...
>
>The situation is this: a CMD_READ request *should* be queued at the device
>(the CheckIO() should confirm this), the CMD_READ request is then aborted and
>a WaitIO() follows as recommended in the RKMs; the WaitIO() returns a -2
>(aborted request.)
>
>The question that comes to mind is: does WaitIO() dequeue the reply at read_port (read_port is the reply port for read_req) regardless of the error?
>Additionally, do I need the GetMsg()?

   NAME
        WaitIO -- wait for completion of an I/O request

   SYNOPSIS
        error = WaitIO(iORequest)
        D0             A1

        BYTE WaitIO(struct IORequest *);

   FUNCTION
        This function waits for the specified I/O request to complete, then
        removes it from the replyport.  If the I/O has already completed,
	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        this function will return immediately.


If you KNOW there is an outstanding request, I believe the best
action is:

if(!CheckIO(ioreq))	AbortIO(ioreq);
WaitIO(ioreq);

Then regardless of whether the request had already completed, it
any signal it generated will be cleared and it will be removed
from the port.

-- 
==========================================================================
 Carolyn Scheppner -- Tech. Mgr. CATS - Commodore Amiga Technical Support
 PHONE 215-431-9180 {uunet,rutgers}!cbmvax!carolyn  carolyn@commodore.com

 Spice up old code with a dazzling array of pointers to void functions.
==========================================================================

efp90@ecs.soton.ac.uk (Pritchard EF) (05/21/91)

leh@otter.cis.ufl.edu (Les Hill) writes:

>I have run into a situation which is not clearly documented (to me anyways) in the
>RKM's (v1.2 ?).  Below I have included the relevant fragments of code:
>...
>   struct MsgPort *read_port, *write_port;
>   struct IOExtSer *read_req, *write_req;
>...
>   BYTE dev_error;
>   struct Message *read_msg;
>...
>   /* Clean up */
>   if (!CheckIO(read_req)) {
>      AbortIO(read_req);
>      if (dev_error = WaitIO(read_req)) {
>         printf("Error waiting for aborted read -- %d\n", dev_error);
>         goto cleanup_8;
>      }
>      read_msg = GetMsg(read_port); // not necessary?
>   }
>...

>The situation is this: a CMD_READ request *should* be queued at the device
>(the CheckIO() should confirm this), the CMD_READ request is then aborted and
>a WaitIO() follows as recommended in the RKMs; the WaitIO() returns a -2
>(aborted request.)

>The question that comes to mind is: does WaitIO() dequeue the reply at 
>read_port (read_port is the reply port for read_req) regardless of the error?
>Additionally, do I need the GetMsg()?


Look in the Revised and Updated RKM Libraries and Devices, page 292
under AbortIO(), it states that:

The AbortIO() command may fail; if it succeeds, the device will stop
processing the IORequest, and 
** reply to it earlier than it may have done otherwise. AbortIO() does not  
** remove the IORequest from your replyport... your program must wait for the
** reply message before actually reusing the IORequest...
** If a request has already completed... no action is taken.

So YES, GetMsg() is required
Hope that helps!

>Thanks in advance,

>Les
>-- 
>Extraordinary crimes against the people and the state have to be avenged by
>agents extraordinary.  Two such people are John Steed -- top professional, and
>his partner, Emma Peel -- talented amateur; otherwise known as "The Avengers."
>INTERNET: leh@ufl.edu  UUCP: ...!gatech!uflorida!leh  BITNET: vishnu@UFPINE

E.F.Pritchard.
efp90@uk.ac.soton.ecs
Department of Computer Science,
Southampton University,
Southampton,
Hampshire,
England.

bj@cbmvax.commodore.com (Brian Jackson) (05/22/91)

In article <7753@ecs.soton.ac.uk> efp90@ecs.soton.ac.uk (Pritchard EF) writes:
>leh@otter.cis.ufl.edu (Les Hill) writes:
>
>>I have run into a situation which is not clearly documented (to me anyways) in the
>>RKM's (v1.2 ?).  Below I have included the relevant fragments of code:
>>...
>>   struct MsgPort *read_port, *write_port;
>>   struct IOExtSer *read_req, *write_req;
>>...
>>   BYTE dev_error;
>>   struct Message *read_msg;
>>...
>>   /* Clean up */
>>   if (!CheckIO(read_req)) {
>>      AbortIO(read_req);
>>      if (dev_error = WaitIO(read_req)) {
                        ^^^^^^^^^^^^^^^^^
>>         printf("Error waiting for aborted read -- %d\n", dev_error);
>>         goto cleanup_8;
>>      }
>>      read_msg = GetMsg(read_port); // not necessary?
>>   }
>>...
>
>>The situation is this: a CMD_READ request *should* be queued at the device
>>(the CheckIO() should confirm this), the CMD_READ request is then aborted and
>>a WaitIO() follows as recommended in the RKMs; the WaitIO() returns a -2
>>(aborted request.)
>
>>The question that comes to mind is: does WaitIO() dequeue the reply at 
>>read_port (read_port is the reply port for read_req) regardless of the error?
>>Additionally, do I need the GetMsg()?
>
>Look in the Revised and Updated RKM Libraries and Devices, page 292
>under AbortIO(), it states that:
>
>The AbortIO() command may fail; if it succeeds, the device will stop
>processing the IORequest, and 
>** reply to it earlier than it may have done otherwise. AbortIO() does not  
>** remove the IORequest from your replyport... your program must wait for the
>** reply message before actually reusing the IORequest...
>** If a request has already completed... no action is taken.
>
>So YES, GetMsg() is required
>Hope that helps!

The GetMsg() is *not* required. He is (properly) doing a WaitIO()
after the AbortIO() call and WaitIO() *does* remove the message.

>E.F.Pritchard.

Brian

 -----------------------------------------------------------------------
 | Brian Jackson  Software Engineer, Commodore-Amiga Inc.  GEnie: B.J. |
 | bj@cbmvax.cbm.commodore.com    or  ...{uunet|rutgers}!cbmvax!bj     |
 | "Sometimes the hamster falls asleep inside the little wheel..."     |
 -----------------------------------------------------------------------

dillon@overload.Berkeley.CA.US (Matthew Dillon) (05/23/91)

In article <7753@ecs.soton.ac.uk> efp90@ecs.soton.ac.uk (Pritchard EF) writes:
>leh@otter.cis.ufl.edu (Les Hill) writes:
>
>>I have run into a situation which is not clearly documented (to me anyways) in the
>>..
>>
>>The question that comes to mind is: does WaitIO() dequeue the reply at
>>read_port (read_port is the reply port for read_req) regardless of the error?
>>Additionally, do I need the GetMsg()?

    AbortIO():

	Request IO device to abort an IO.  The IO device will attempt to
	abort the IO as soon as possible.  The result is that, sometime
	in the future, the IO device will return the IO request normally.

	If the IO request has already been returned no action will occur

    WaitIO():

	This call WAITs for the IO request to be returned to its replyport,
	THEN REMOVES THE REQUEST FROM THE REPLY PORT.


    Thus, you do NOT MIX GetMsg() and WaitIO().  WaitIO() automatically
    removes the request from the replyport after waiting for it to be
    returned to the reply port.  WaitIO() correctly handles the case where
    the request might have already been returned to the port and the case
    where the signal state may be random.

    The proper method to abort a queued IO request is:

	AbortIO(io);
	WaitIO(io);

    You do NOT need to CheckIO() before AbortIO()ing, though this does not
    hurt.  I.E.

	if (!CheckIO(io))       // CheckIO() is unnecessary
	    AbortIO(io);

    There are generally two methods to handle returned IO requests in
    your main loop:

    (1) Use Wait() and GetMsg():

	mask = Wait(signals);

	if (mask & MyMsgPortSignalMask) {
	    IORequest *io;
	    while (io = GetMsg(MyMsgPort)) {
		if (io == (IORequest *)&MySerReadReq) {
		    MySerReadReqInProgress = 0;
		    ...
		} else if (io == (IORequest *)&MyTimerReq) {
		    MyTimerReqInProgress = 0;
		    ...
		}
		...
	    }
	}

	...  somewhere in your code ...

	SendIO(&MyTimerReq);
	MyTimerReqInProgress = 1;

	...  in your exit routine ...

	if (MyTimerReqInProgress) {
	    AbortIO(&MyTimerReq);
	    WaitIO(&MyTimerReq);
	    MyTimerReqInProgress = 0;
	}

	This case assumes that you drain MyMsgPort completely before
	looping back to the Wait().  Note that in this case you DO NOT USE
	CHECKIO() OR WAITIO() on the messages returned by GetMsg(), since
	GetMsg() returning an IO request both unlinks it from the replyport
	and guarentees that the request had completed (by virtue of it
	having been returned to the replyport).

	If you are waiting on only one port, you can use WaitPort() instead
	of Wait(), in which case you can loop back up to the WaitPort()
	without having to drain *all* the messages on the message port
	(WaitPort() does not wait if there are messages already on the
	port).

    (2) Use Wait(), CheckIO(), and WaitIO()

	mask = Wait(signals);

	if (mask & MyMsgPortSignalMask) {

	    /*
	     *	If in your loop certain requests are not always 'in progress',
	     *	you need another variable to tell your main loop whether
	     *	a given request is in progress or not, i.e. queued.
	     */

	    if (MySerWriteReqIsInProgress) {
		if (CheckIO(&MySerWriteReq)) {
		    WaitIO(&MySerWriteReq);
		    MySerWriteReqIsInProgress = 0;
		    ...
		}
	    }

	    /*
	     *	note, no else-if, must check ALL possible pending IO's.
	     *
	     *	If the request is always in progress... say you ALWAYS
	     *	have your timer request queued so you get interval times
	     *	(e.g. once a second or something like that), then you
	     *	do not need a flag.
	     */

	    if (CheckIO(&MyTimerReq)) {
		WaitIO(&MyTimerReq);

		...

		MyTimerReq.tr_time.tv_secs = 1;
		MyTimerReq.tr_time.tv_micro= 0;
		SendIO(&MyTimerReq);
	    }
	}
	...


	In this case, you can also use WaitPort() instead of Wait() if
	you are waiting on only one signal.  Here, we almost entirely
	ignore the message port itself.  However, IO requests are still
	returned to the port and queued to its list so after we CheckIO()
	that it has been returned, we must WaitIO() to remove it from
	the message port's list.

    In the case of AbortIO(), if you know you previously queued a request,
    say our timer request above, then you can AbortIO() it as follows:

	AbortIO(io);
	WaitIO(io);

    Again, remember that AbortIO() is really only a 'hurry-up' request
    to the IO device and does NOT guarentee that the IO request will
    be immediately returned.

    WARNING:  Many people make the mistake of using WaitIO() and AbortIO()
    on requests THEY HAVE ALREADY DEQUEUED OR NEVER SENT IN THE FIRST
    PLACE.  THIS IS ILLEGAL.  You can ONLY use WaitIO() and AbortIO() on
    requests that are currently in-progress or have been returned (but not
    dequeued) to the reply port.

    If you have an IO request -- say an asynchronous CMD_WRITE request to
    the serial.device that you do not always have queued, you need some
    kind of flag in your program to indicate its state so, for example,
    your myexit() routine doesn't attempt to AbortIO()/WaitIO() a request
    that was never queued or already dequeued via GetMsg() or WaitIO().

					    -Matt

--

    Matthew Dillon	    dillon@Overload.Berkeley.CA.US
    891 Regal Rd.	    uunet.uu.net!overload!dillon
    Berkeley, Ca. 94708
    USA

valentin@public.BTR.COM (Valentin Pepelea) (05/23/91)

In article <28630@uflorida.cis.ufl.EDU> leh@otter.cis.ufl.edu (Les Hill)
writes:
>
>   /* Clean up */
>   if (!CheckIO(read_req)) {
>      AbortIO(read_req);
>      if (dev_error = WaitIO(read_req)) {
>         printf("Error waiting for aborted read -- %d\n", dev_error);
>         goto cleanup_8;
>      }
>      read_msg = GetMsg(read_port); // not necessary?
>   }
>...
>
>The situation is this: a CMD_READ request *should* be queued at the device
>(the CheckIO() should confirm this),

Not really. The IO request could have been processed between the time ChechIO
was called and AbortIO is about to be.

>The question that comes to mind is: does WaitIO() dequeue the reply at
>read_port (read_port is the reply port for read_req) regardless of the error?

Yes, WaitIO() makes sure the message is dequeued.

>Additionally, do I need the GetMsg()?

No you don't. This is a bug. The line:

>      read_msg = GetMsg(read_port); // not necessary?

should have read	> else read_msg = GetMsg(read_port)

However, you should note the the best method to perform the given operation
is simply:

	AbortIO(IORequest);
	WaitIO(IORequest);

If the IORequest had already completed, then AbortIO does nothing.

Valentin
-- 
"An operating system without virtual memory      Name:      Valentin Pepelea
 is an operating system without virtue."         Phone:     (408) 985-1700
                                                 Usenet:    mips!btr!valentin
                     - Ancient Inca Proverb      Internet:  valentin@btr.com

efp90@ecs.soton.ac.uk (Pritchard EF) (05/23/91)

In <21785@cbmvax.commodore.com> bj@cbmvax.commodore.com (Brian Jackson) writes:


>The GetMsg() is *not* required. He is (properly) doing a WaitIO()
>after the AbortIO() call and WaitIO() *does* remove the message.

Oops! Thanks for picking me up on that, Brain!

>Brian

> -----------------------------------------------------------------------
> | Brian Jackson  Software Engineer, Commodore-Amiga Inc.  GEnie: B.J. |
> | bj@cbmvax.cbm.commodore.com    or  ...{uunet|rutgers}!cbmvax!bj     |
> | "Sometimes the hamster falls asleep inside the little wheel..."     |
> -----------------------------------------------------------------------

E.F.Pritchard.
efp90

oliphant@telepro.UUCP (Mike Oliphant) (05/24/91)

In article <21757@cbmvax.commodore.com> carolyn@cbmvax.commodore.com (Carolyn Scheppner - CATS) writes:

>If you KNOW there is an outstanding request, I believe the best
>action is:
>
>if(!CheckIO(ioreq))	AbortIO(ioreq);
>WaitIO(ioreq);

The CheckIO() is  EXTREMELY important with the A2232 serial card - it doesn't
like you aborting requests that have been satisfied.  In fact, it seems that
even the CheckIO() safety measure is not enough with this card.  I've found
this method solves the problem:

  NiceAbort(ioreq)
  struct IORequest *ioreq;
  {
    Forbid();
    if(!CheckIO(ioreq)) AbortIO(ioreq);
    Permit();
    WaitIO(ioreq);
  }

A program called 'A2232Patch' by Reid Bishop uses SetFunction() to turn
all AbortIO() calls into NiceAborts.  Without this patch, doing complex
things with the serial port (such as spawning a BBS from a front-end
FidoNet mailer) is likely to fail miserably on the A2232 (unless the software
in question does NiceAborts itself).

Hopefully, this bug in the A2232 will be fixed (the standard serial.device
has no such problem) and these contortions will be rendered unneccesary.

--
Mike Oliphant	telepro!oliphant@herald.usask.ca or herald!telepro!oliphant
		FidoNet: (1:140/91) - ZMH only
*
* Call TelePro, the development system for DLG Professional
*
*   Phone: +1 306 249 2352	2400/9600/14400 bps HST - FidoNet: (1:140/90)
*	   +1 306 652 2084	300/1200/2400 bps
*

valentin@public.BTR.COM (Valentin Pepelea) (05/25/91)

In article <oliphant.8324@telepro.UUCP> oliphant@telepro.UUCP (Mike Oliphant)
writes:
>
>The CheckIO() is  EXTREMELY important with the A2232 serial card - it doesn't
>like you aborting requests that have been satisfied.

Definitely a bug in the A2232 device driver. It seems like every other CBM
device driver has a problem with AbortIO(). Make sure you report the bug to
bugs@cbmvax.commodore.com. With luck and prayers, you will even receive an
acknowledgement.

Valentin
-- 
"An operating system without virtual memory      Name:      Valentin Pepelea
 is an operating system without virtue."         Phone:     (408) 985-1700
                                                 Usenet:    mips!btr!valentin
                     - Ancient Inca Proverb      Internet:  valentin@btr.com

dillon@overload.Berkeley.CA.US (Matthew Dillon) (05/29/91)

In article <oliphant.8324@telepro.UUCP> oliphant@telepro.UUCP (Mike Oliphant) writes:
>In article <21757@cbmvax.commodore.com> carolyn@cbmvax.commodore.com (Carolyn Scheppner - CATS) writes:
>..
>>If you KNOW there is an outstanding request, I believe the best
>>action is:
>>
>>if(!CheckIO(ioreq))   AbortIO(ioreq);
>>WaitIO(ioreq);
>
>The CheckIO() is  EXTREMELY important with the A2232 serial card - it doesn't
>like you aborting requests that have been satisfied.  In fact, it seems that

    This is a bug in the A2232 serial.device

    It *has* been fixed in alphas of the next release, along with a few
    other bugs.

>even the CheckIO() safety measure is not enough with this card.  I've found
>this method solves the problem:
>
>  NiceAbort(ioreq)
>  struct IORequest *ioreq;
>  {
>    Forbid();
>    if(!CheckIO(ioreq)) AbortIO(ioreq);
>    Permit();
>    WaitIO(ioreq);
>  }

    I'm not sure this will work.  If the A2232 serial.device uses a SoftInt
    instead of a process to handle returning requests, then all the
    Forbid()/Permit() does is reduce the window of oportunity.

    But it does sound like a good temporary solution to the problem!  You
    need to use Disable/Enable though, however bad that may sound.

>--
>Mike Oliphant	telepro!oliphant@herald.usask.ca or herald!telepro!oliphant
>		FidoNet: (1:140/91) - ZMH only
>*
>* Call TelePro, the development system for DLG Professional
>*
>*   Phone: +1 306 249 2352	2400/9600/14400 bps HST - FidoNet: (1:140/90)
>*	   +1 306 652 2084	300/1200/2400 bps
>*

				-Matt

--

    Matthew Dillon	    dillon@Overload.Berkeley.CA.US
    891 Regal Rd.	    uunet.uu.net!overload!dillon
    Berkeley, Ca. 94708
    USA

oliphant@telepro.UUCP (Mike Oliphant) (05/30/91)

In article <dillon.8069@overload.Berkeley.CA.US> dillon@overload.Berkeley.CA.US (Matthew Dillon) writes:

>>The CheckIO() is  EXTREMELY important with the A2232 serial card - it doesn't
>>like you aborting requests that have been satisfied.  In fact, it seems that
>
>    This is a bug in the A2232 serial.device
>
>    It *has* been fixed in alphas of the next release, along with a few
>    other bugs.

Great!  We've been living with this bug for over 6 months now...

>>even the CheckIO() safety measure is not enough with this card.  I've found
>>this method solves the problem:
>>
>>  NiceAbort(ioreq)
>>  struct IORequest *ioreq;
>>  {
>>    Forbid();
>>    if(!CheckIO(ioreq)) AbortIO(ioreq);
>>    Permit();
>>    WaitIO(ioreq);
>>  }
>
>    I'm not sure this will work.  If the A2232 serial.device uses a SoftInt
>    instead of a process to handle returning requests, then all the
>    Forbid()/Permit() does is reduce the window of oportunity.

It seems to work fairly well - well enough to keep things held together until
we can get our hands on the fixed device.

--
Mike Oliphant	telepro!oliphant@herald.usask.ca or herald!telepro!oliphant
		FidoNet: (1:140/91) - ZMH only
*
* Call TelePro, the development system for DLG Professional
*
*   Phone: +1 306 249 2352	2400/9600/14400 bps HST - FidoNet: (1:140/90)
*	   +1 306 652 2084	300/1200/2400 bps
*