// // CloseHandle() has a slightly different interface from the NT call. It takes an // additional input parameter to determine the object type. The object can be either // a FILE_ELEMENT or a CQ_ELEMENT. // // CloseHandle() closes the file handle or the completion queue handle and frees all // the allocated memory. It does an additional check to ensure that all the queued // Asynch I/Os that have not yet completed are cancelled before actually closing the // handle. This helps clean up the kernel queues of any pending requests. // // Although it takes longer, this is acceptable since the code is not in the performance // critical region. // BOOL CloseHandle(HANDLE object, int object_type) { struct File *filep; struct IOCQ *cqid; int retval, i; #ifdef _DEBUG cout << "CloseHandle() freeing : handle = " << object << " objecttype = " << object_type << endl; #endif switch (object_type) { case FILE_ELEMENT: filep = (struct File *)object; cqid = filep->iocq; // cancel any pending aio requests. retval = aio_cancel64(filep->fd, NULL); while (retval == AIO_NOTCANCELED) { retval = aio_cancel64(filep->fd, NULL); } if (cqid != NULL && cqid->element_list != NULL && cqid->aiocb_list != NULL) { for (i = 0; i < cqid->size; i++) { if (cqid->element_list[i].aiocbp.aio_fildes != filep->fd) continue; // We are not interested in the return values of aio_error() and aio_return(). // only have to dequeue all the requests. if (!cqid->aiocb_list[i]) continue; retval = aio_error64(cqid->aiocb_list[i]); retval = aio_return64(cqid->aiocb_list[i]); } } #if defined(IOMTR_OS_LINUX) || defined(IOMTR_OS_OSX) || defined(IOMTR_OS_SOLARIS) close(filep->fd); #elif defined(IOMTR_OS_NETWARE) if (IsType(filep->type, LogicalDiskType)) NXClose(filep->fd); else if (IsType(filep->type, PhysicalDiskType)) MM_ReleaseIOObject(filep->fd); #else #warning ===> WARNING: You have to do some coding here to get the port done! #endif break; case CQ_ELEMENT: cqid = (struct IOCQ *)object; // cancel any pending aio requests. for (i = 0; i < cqid->size; i++) { if (!cqid->aiocb_list[i]) continue; #if defined(IOMTR_OS_LINUX) || defined(IOMTR_OS_OSX) || defined(IOMTR_OS_NETWARE) /* * In Linux, you crash (!) if the aiocpb isn't in your queue. :-( * This code seems to occasionally do this...so I just cancel all * AIOs for the queue, thus avoiding the problem of cancelling a * message not in the queue. */ retval = aio_cancel64(cqid->element_list[i].aiocbp.aio_fildes, NULL); #elif defined(IOMTR_OS_SOLARIS) retval = aio_cancel64(cqid->element_list[i].aiocbp.aio_fildes, cqid->aiocb_list[i]); #else #warning ===> WARNING: You have to do some coding here to get the port done! #endif if (retval == AIO_NOTCANCELED) { retval = aio_error64(cqid->aiocb_list[i]); retval = aio_return64(cqid->aiocb_list[i]); } } #if defined(IOMTR_OS_LINUX) || defined(IOMTR_OS_OSX) || defined(IOMTR_OS_SOLARIS) free(cqid->aiocb_list); #elif defined(IOMTR_OS_NETWARE) NXMemFree(cqid->aiocb_list); #else #warning ===> WARNING: You have to do some coding here to get the port done! #endif // Something strange here. If I free the element_list, the next round // of aio_write() and aio_read() calls fail. If I dont free this, then they // succeed. But then, there is a memory leak equal to the max number of outstanding // I/Os * sizeof(CQ_Element). Does that mean that the above aio_cancel() calls // are broken ??? It should be mentioned here that the element_list holds the // actual aiocb structures. // // It suddenly seems to be working now. // Remember to turn this "free" off when you hit the problem again. // NEED TO LOOK INTO THIS. #if defined(IOMTR_OS_LINUX) || defined(IOMTR_OS_OSX) || defined(IOMTR_OS_SOLARIS) free(cqid->element_list); free(cqid); #elif defined(IOMTR_OS_NETWARE) NXMemFree(cqid->element_list); NXMemFree(cqid); #else #warning ===> WARNING: You have to do some coding here to get the port done! #endif break; default: break; } return (TRUE); }
int TargetDisk::NWCloseDevice(HNDL handle) { return MM_ReleaseIOObject(handle); }