Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add overlapped (asynchronous file read/writes) to WinAPI #664

Merged
merged 2 commits into from
May 4, 2024

Conversation

Ryzee119
Copy link
Contributor

@Ryzee119 Ryzee119 commented Feb 13, 2024

Asynchronous fileio has some limitations ref
https://learn.microsoft.com/en-US/previous-versions/troubleshoot/windows/win32/asynchronous-disk-io-synchronous and
JayFoxRox#45

Asynchronous file read/writes have these requirements generally:

  • They must use FILE_FLAG_NO_BUFFERING which has size and alignemnt requirements of the buffer (DWORD alignment and multiple of sector size)
  • Writes that increase the file size must preallocate the space.

If these are not met the request will either fail or complete synchronously

Overlapped structure members seemed a bit odd to me when I initially looked at this but this was my reference
https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped

Some test code below which demonstrates async read and write as per win32 docs

#include <hal/debug.h>
#include <hal/video.h>
#include <windows.h>
#include <nxdk/mount.h>
#include <assert.h>

// Async buffer should be DWORD aligned and a multiple of the sector size (512 bytes for HDD, 2048 bytes for DVD normally)
__attribute__((aligned(sizeof(DWORD)))) CHAR buffer[32 * 1024 * 1024];

int main(void)
{
    CONST CHAR *lpFileName = "E:\\test.bin";
    DWORD lpNumberOfBytesTransferred;
    HANDLE hFile;

    XVideoSetMode(640, 480, 32, REFRESH_DEFAULT);
    nxMountDrive('E', "\\Device\\Harddisk0\\Partition1\\");

    OVERLAPPED overlapped = {
        .Offset = 0,
        .OffsetHigh = 0,
        .hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)};

    /* ASYNC WRITE */
    hFile = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
    assert(hFile != INVALID_HANDLE_VALUE);

    // Any write operation to a file that extends its length will be synchronous, so pre-allocate its length to ensure it is asynchronous
    assert(SetFilePointer(hFile, sizeof(buffer), NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER);
    assert(SetEndOfFile(hFile));
    assert(SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER);

    // An asynchronous write will return false, but the error code will be ERROR_IO_PENDING.
    assert(WriteFile(hFile, (LPCVOID)buffer, sizeof(buffer), NULL, &overlapped) == FALSE);
    assert(GetLastError() == ERROR_IO_PENDING);
    debugPrint("Async write started to %s\n", lpFileName);

    // Wait for the write to complete asynchronously
    assert(GetOverlappedResult(hFile, &overlapped, &lpNumberOfBytesTransferred, TRUE));
    debugPrint("WriteFile completed successfully. Wrote %lu bytes\n", lpNumberOfBytesTransferred);

    CloseHandle(hFile);

    /* ASYNC READ */
    hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
    assert(hFile != INVALID_HANDLE_VALUE);

    // An asynchronous read will return false, but the error code will be ERROR_IO_PENDING.
    assert(ReadFile(hFile, (LPVOID)buffer, sizeof(buffer), NULL, &overlapped) == FALSE);
    assert(GetLastError() == ERROR_IO_PENDING);
    debugPrint("Async read started to %s\n", lpFileName);

    // Wait for the read to complete asynchronously
    assert(GetOverlappedResult(hFile, &overlapped, &lpNumberOfBytesTransferred, TRUE));
    debugPrint("ReadFile completed successfully. Read %lu bytes\n", lpNumberOfBytesTransferred);

    while (1)
    {
        Sleep(2000);
    }

    return 0;
}

image

Copy link
Member

@thrimbor thrimbor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the extremely late review.
Code looks almost perfect, left two small comments.

lib/winapi/fileio.c Show resolved Hide resolved
lib/winapi/ioapi.c Show resolved Hide resolved
@thrimbor thrimbor merged commit 6ef8288 into XboxDev:master May 4, 2024
5 of 6 checks passed
@Ryzee119 Ryzee119 deleted the overlapped1 branch May 26, 2024 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants