Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!crdgw1!uunet!overload!dillon From: dillon@overload.Berkeley.CA.US (Matthew Dillon) Newsgroups: comp.sys.amiga.programmer Subject: Re: Question on AbortIO() and WaitIO() Message-ID: Date: 23 May 91 01:17:52 GMT References: <28630@uflorida.cis.ufl.EDU> <7753@ecs.soton.ac.uk> Organization: Not an Organization Lines: 167 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