-static void PrintError(LPCSTR lpszFunction)
-{
- // Retrieve the system error message for the last-error code
-
- LPSTR lpMsgBuf;
- DWORD dw = GetLastError();
-
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- dw,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)&lpMsgBuf,
- 0, NULL );
-
- log_err("%s - %s", lpszFunction, lpMsgBuf);
- LocalFree(lpMsgBuf);
-}
-
-static int fio_windowsaio_cancel(struct thread_data *td,
- struct io_u *io_u)
-{
- int rc = 0;
-
- struct windowsaio_data *wd = td->io_ops->data;
-
- /* If we're running on Vista, we can cancel individual IO requests */
- if (wd->have_cancelioex) {
- FIO_OVERLAPPED *ovl = io_u->engine_data;
- if (!CancelIoEx(io_u->file->hFile, &ovl->o))
- rc = 1;
- } else
- rc = 1;
-
- return rc;
-}
-
-static BOOL TimedOut(DWORD start_count, DWORD end_count)
-{
- BOOL expired = FALSE;
- DWORD current_time;
-
- current_time = GetTickCount();
-
- if ((end_count > start_count) && current_time >= end_count)
- expired = TRUE;
- else if (current_time < start_count && current_time > end_count)
- expired = TRUE;
-
- return expired;
-}
-
-static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
- unsigned int max, struct timespec *t)
-{
- struct windowsaio_data *wd = td->io_ops->data;
- struct flist_head *entry;
- unsigned int dequeued = 0;
- struct io_u *io_u;
- DWORD start_count = 0, end_count = 0;
- BOOL timedout = FALSE;
- unsigned int mswait = 100;
-
- if (t != NULL) {
- mswait = (t->tv_sec * 1000) + (t->tv_nsec / 1000000);
- start_count = GetTickCount();
- end_count = start_count + (t->tv_sec * 1000) + (t->tv_nsec / 1000000);
- }
-
- while (dequeued < min && !timedout) {
- flist_for_each(entry, &td->io_u_busylist) {
- io_u = flist_entry(entry, struct io_u, list);
-
- if (io_u->seen == 1) {
- io_u->seen = 2;
- wd->aio_events[dequeued] = io_u;
- dequeued++;
- }
-
- if (dequeued == max)
- break;
- }
-
- if (dequeued < min) {
- WaitForSingleObject(wd->iocomplete_event, mswait);
- }
-
- if (t != NULL && TimedOut(start_count, end_count))
- timedout = TRUE;
- }
-
- return dequeued;
-}
-
-static struct io_u *fio_windowsaio_event(struct thread_data *td, int event)
-{
- struct windowsaio_data *wd = td->io_ops->data;
- return wd->aio_events[event];
-}
-
-static int fio_windowsaio_queue(struct thread_data *td,
- struct io_u *io_u)
-{
- struct windowsaio_data *wd;
- DWORD iobytes;
- BOOL success = TRUE;
- int ind;
- int rc;
-
- fio_ro_check(td, io_u);
-
- wd = td->io_ops->data;
- ind = wd->io_index;
-
- ResetEvent(wd->io_handles[ind]);
- wd->ovls[ind].o.Internal = 0;
- wd->ovls[ind].o.InternalHigh = 0;
- wd->ovls[ind].o.Offset = io_u->offset & 0xFFFFFFFF;
- wd->ovls[ind].o.OffsetHigh = io_u->offset >> 32;
- wd->ovls[ind].o.hEvent = wd->io_handles[ind];
- wd->ovls[ind].io_u = io_u;
-
- io_u->engine_data = &wd->ovls[ind];
- io_u->seen = 0;
-
- if (io_u->ddir == DDIR_WRITE) {
- success = WriteFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &iobytes, &wd->ovls[ind].o);
- } else if (io_u->ddir == DDIR_READ) {
- success = ReadFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &iobytes, &wd->ovls[ind].o);
- } else if (io_u->ddir == DDIR_SYNC ||
- io_u->ddir == DDIR_DATASYNC ||
- io_u->ddir == DDIR_SYNC_FILE_RANGE)
- {
- FlushFileBuffers(io_u->file->hFile);
- return FIO_Q_COMPLETED;
- } else if (io_u->ddir == DDIR_TRIM) {
- log_info("explicit TRIM isn't supported on Windows");
- return FIO_Q_COMPLETED;
- } else
- assert(0);
-
- if (success) {
- io_u->seen = 1;
- io_u->resid = io_u->xfer_buflen - iobytes;
- io_u->error = 0;
- rc = FIO_Q_COMPLETED;
- } else if (!success && GetLastError() == ERROR_IO_PENDING) {
- wd->io_index = (wd->io_index + 1) % (2 * td->o.iodepth);
- rc = FIO_Q_QUEUED;
- } else {
- PrintError(__func__);
- io_u->error = GetLastError();
- io_u->resid = io_u->xfer_buflen;
- rc = FIO_Q_COMPLETED;
- }
-
- return rc;
-}
-
-static void fio_windowsaio_cleanup(struct thread_data *td)
-{
- int i;
- struct windowsaio_data *wd;
-
- wd = td->io_ops->data;
-
- WaitForSingleObject(wd->iothread_stopped, INFINITE);
-
- if (wd != NULL) {
- CloseHandle(wd->iothread);
- CloseHandle(wd->iothread_stopped);
- CloseHandle(wd->iocomplete_event);
-
- for (i = 0; i < 2 * td->o.iodepth; i++) {
- CloseHandle(wd->io_handles[i]);
- }
-
- free(wd->aio_events);
- free(wd->io_handles);
- free(wd->ovls);
- free(wd);
-
- td->io_ops->data = NULL;
- }
-}
-
-/* Runs as a thread and waits for queued IO to complete */
-static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter)
-{
- OVERLAPPED *ovl;
- FIO_OVERLAPPED *fov;
- struct io_u *io_u;
- struct windowsaio_data *wd;
- struct thread_ctx *ctx;
- ULONG_PTR ulKey = 0;
- DWORD bytes;
-
- ctx = (struct thread_ctx*)lpParameter;
- wd = ctx->wd;
-
- while (ctx->wd->iothread_running) {
- if (!GetQueuedCompletionStatus(ctx->iocp, &bytes, &ulKey, &ovl, 250))
- continue;
-
- fov = CONTAINING_RECORD(ovl, FIO_OVERLAPPED, o);
- io_u = fov->io_u;
-
- if (io_u->seen != 0)
- continue;
-
- if (ovl->Internal == ERROR_SUCCESS) {
- io_u->resid = io_u->xfer_buflen - ovl->InternalHigh;
- io_u->error = 0;
- } else {
- io_u->resid = io_u->xfer_buflen;
- io_u->error = ovl->Internal;
- }
-
- io_u->seen = 1;
- SetEvent(wd->iocomplete_event);
- }
-
- CloseHandle(ctx->iocp);
- SetEvent(ctx->wd->iothread_stopped);
- free(ctx);
-
- return 0;
-}
-