/* * ======== GIO_reclaim ======== */ Int GIO_reclaim(GIO_Object *obj, Ptr *pBuf, SizeT *pSize, UArg *pArg) { IOM_Packet *packet; Queue_Handle doneList; Queue_Handle freeList; UInt key; Int status; Error_Block eb; doneList = GIO_Instance_State_doneList(obj); freeList = GIO_Instance_State_freeList(obj); Error_init(&eb); while (obj->doneCount == 0) { if (Sync_wait(obj->sync, obj->timeout, &eb) == Sync_WaitStatus_TIMEOUT) { return (IOM_ETIMEOUT); } } key = Hwi_disable(); obj->doneCount--; packet = Queue_dequeue(doneList); Hwi_restore(key); if (pArg != NULL) { *pArg = packet->arg; } /* pBuf is set to NULL by GIO_read() and GIO_write() */ if (pBuf != NULL) { *pBuf = packet->addr; } if (pSize != NULL) { *pSize = packet->size; } status = packet->status; /* * re-signal if more buffers are ready * This is required in the case of ISyncEvent and ISyncSwi to allow * clients to reclaim a single buffer and not force them to bleed the * stream. */ if (obj->doneCount > 0) { Sync_signal(obj->sync); } /* recycle packet back onto free list */ key = Hwi_disable(); obj->freeCount++; Queue_enqueue(freeList, (Queue_Elem *)packet); Hwi_restore(key); return (status); }
/* * ======== GIO_submit ======== */ Int GIO_submit(GIO_Object *obj, Uns cmd, Ptr buf, SizeT *pSize, GIO_AppCallback *appCallback) { IOM_Packet syncPacket; IOM_Packet *packet; SizeT nullSize; Int status; UInt key; Queue_Handle list; Error_Block eb; IOM_Fxns *iomFxns; iomFxns = (IOM_Fxns *)obj->fxns; if (appCallback == NULL) { packet = &syncPacket; } else { list = GIO_Instance_State_freeList(obj); if (obj->freeCount == 0) { return (IOM_ENOPACKETS); } key = Hwi_disable(); obj->freeCount--; packet = Queue_dequeue(list); Hwi_restore(key); } if (pSize == NULL) { nullSize = 0; pSize = &nullSize; } packet->cmd = cmd; packet->addr = buf; packet->size = *pSize; packet->status = IOM_COMPLETED; /* * 'appCallback' will be NULL for synchronous calls. * 'packet->misc' is used in the callback to call asynch callback * or post semaphore (sync). */ packet->misc = (UArg)appCallback; status = iomFxns->mdSubmitChan(obj->mdChan, packet); if ((status == IOM_COMPLETED) || (status < 0)) { if (status == IOM_COMPLETED) { *pSize = packet->size; status = packet->status; } /* if asynch, put packet back on freeList */ if (appCallback != NULL) { key = Hwi_disable(); obj->freeCount++; Queue_enqueue(list, (Queue_Elem *)packet); Hwi_restore(key); } return (status); } /* * call Sync_wait only if synchronous I/O and mdSubmitChan did not * return an error (status < 0) */ if (appCallback == NULL) { Error_init(&eb); if (Sync_wait(obj->sync, obj->timeout, &eb) == Sync_WaitStatus_SUCCESS) { *pSize = packet->size; status = packet->status; } else { *pSize = 0; /* * NOTE: A channel timeout needs special handling. Timeouts are * usually due to some serious underlying device or system state * and may require the channel, or possibly the device,to be reset. * Because the mini-driver may still own the IOM_Packet here * driver's will need to perform timeout processing. We will call * the mini-driver's control fxn with the IOM_CHAN_TIMEDOUT command * code. */ status = iomFxns->mdControlChan(obj->mdChan, IOM_CHAN_TIMEDOUT, NULL); if (status != IOM_COMPLETED) { return (IOM_ETIMEOUTUNREC); /* fatal, may have lost packet */ } return (IOM_ETIMEOUT); } } return (status); }
/* * ======== Stream_reclaim ======== */ SizeT Stream_reclaim(Stream_Object *obj, Ptr *bufp, UInt timeout, UArg *arg, Error_Block *eb) { DriverTypes_Packet *packet = NULL; List_Handle freeList; UInt key; if (obj->issued == 0) { Error_raise(eb, Stream_E_noBuffersIssued, 0, 0); return (0); } while (obj->ready == 0) { if (!Sync_wait(obj->complete, timeout, eb)) { if (timeout != 0) { Error_raise(eb, Stream_E_timeout, timeout, 0); } return (0); } }; IConverter_reclaim(obj->convHandle, &packet, eb); if (arg != NULL) { *arg = packet->arg; } /* bufp is NULL in Stream_read and Stream_write. */ if (bufp != NULL) { *bufp = packet->addr; } key = Hwi_disable(); obj->ready--; Hwi_restore(key); obj->issued--; /* * re-signal if more buffers are ready * This is required in the case of ISyncEvent and ISyncSwi to allow * clients to reclaim a single buffer and not force them to bleed the * Stream. In the case of ISyncSem , this re-signal is an overhead */ if (obj->ready > 0) { Sync_signal(obj->complete); } freeList = Stream_Instance_State_freeList(obj); /* recycle packet back onto free list */ List_put(freeList, (List_Elem *)packet); if ((packet->error != NULL) && (packet->error != DriverTypes_EABORTED)) { Error_raise(eb, packet->error, packet->status, 0); return (0); } else { return (packet->size); } }