mirror of
https://github.com/encounter/aurora.git
synced 2025-12-17 17:05:27 +00:00
Use asynchronous I/O for Card access
This commit is contained in:
47
include/kabufuda/AsyncIO.hpp
Normal file
47
include/kabufuda/AsyncIO.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef __KABU_ASYNCIO_HPP__
|
||||
#define __KABU_ASYNCIO_HPP__
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <aio.h>
|
||||
using SizeReturn = ssize_t;
|
||||
#else
|
||||
#include <windows.h>
|
||||
using SizeReturn = SSIZE_T;
|
||||
#endif
|
||||
|
||||
#include "Util.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace kabufuda
|
||||
{
|
||||
|
||||
class AsyncIO
|
||||
{
|
||||
#ifndef _WIN32
|
||||
int m_fd = -1;
|
||||
std::vector<std::pair<struct aiocb, SizeReturn>> m_queue;
|
||||
#else
|
||||
#endif
|
||||
size_t m_maxBlock = 0;
|
||||
public:
|
||||
AsyncIO() = default;
|
||||
AsyncIO(SystemStringView filename, bool truncate = false);
|
||||
~AsyncIO();
|
||||
AsyncIO(AsyncIO&& other);
|
||||
AsyncIO& operator=(AsyncIO&& other);
|
||||
AsyncIO(const AsyncIO* other) = delete;
|
||||
AsyncIO& operator=(const AsyncIO& other) = delete;
|
||||
void resizeQueue(size_t queueSz) { m_queue.resize(queueSz); }
|
||||
SizeReturn syncRead(void* buf, size_t length, off_t offset);
|
||||
bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset);
|
||||
SizeReturn syncWrite(const void* buf, size_t length, off_t offset);
|
||||
bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset);
|
||||
ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const;
|
||||
ECardResult pollStatus() const;
|
||||
void waitForCompletion() const;
|
||||
operator bool() const { return m_fd != -1; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __KABU_ASYNCIO_HPP__
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Directory.hpp"
|
||||
#include "File.hpp"
|
||||
#include "Util.hpp"
|
||||
#include "AsyncIO.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -12,7 +13,6 @@
|
||||
|
||||
#define CARD_FILENAME_MAX 32
|
||||
#define CARD_ICON_MAX 8
|
||||
#undef NOFILE
|
||||
|
||||
namespace kabufuda
|
||||
{
|
||||
@@ -29,24 +29,6 @@ public:
|
||||
operator bool() const { return getFileNo() != -1; }
|
||||
};
|
||||
|
||||
enum class ECardResult
|
||||
{
|
||||
CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */
|
||||
FATAL_ERROR = -128,
|
||||
ENCODING = -13,
|
||||
NAMETOOLONG = -12,
|
||||
INSSPACE = -9,
|
||||
NOENT = -8,
|
||||
EXIST = -7,
|
||||
BROKEN = -6,
|
||||
IOERROR = -5,
|
||||
NOFILE = -4,
|
||||
NOCARD = -3,
|
||||
WRONGDEVICE = -2,
|
||||
BUSY = -1,
|
||||
READY = 0
|
||||
};
|
||||
|
||||
struct ProbeResults
|
||||
{
|
||||
ECardResult x0_error;
|
||||
@@ -102,31 +84,35 @@ struct CardStat
|
||||
class Card
|
||||
{
|
||||
#pragma pack(push, 4)
|
||||
struct CardHeader
|
||||
{
|
||||
uint8_t m_serial[12];
|
||||
uint64_t m_formatTime;
|
||||
int32_t m_sramBias;
|
||||
uint32_t m_sramLanguage;
|
||||
uint32_t m_unknown;
|
||||
uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */
|
||||
uint16_t m_sizeMb;
|
||||
uint16_t m_encoding;
|
||||
uint8_t __padding[468];
|
||||
uint16_t m_updateCounter;
|
||||
uint16_t m_checksum;
|
||||
uint16_t m_checksumInv;
|
||||
void _swapEndian();
|
||||
};
|
||||
union {
|
||||
struct
|
||||
{
|
||||
uint8_t m_serial[12];
|
||||
uint64_t m_formatTime;
|
||||
int32_t m_sramBias;
|
||||
uint32_t m_sramLanguage;
|
||||
uint32_t m_unknown;
|
||||
uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */
|
||||
uint16_t m_sizeMb;
|
||||
uint16_t m_encoding;
|
||||
uint8_t __padding[468];
|
||||
uint16_t m_updateCounter;
|
||||
uint16_t m_checksum;
|
||||
uint16_t m_checksumInv;
|
||||
};
|
||||
CardHeader m_ch;
|
||||
uint8_t __raw[BlockSize];
|
||||
};
|
||||
|
||||
CardHeader m_tmpCh;
|
||||
#pragma pack(pop)
|
||||
|
||||
SystemString m_filename;
|
||||
FILE* m_fileHandle = nullptr;
|
||||
AsyncIO m_fileHandle;
|
||||
Directory m_dirs[2];
|
||||
BlockAllocationTable m_bats[2];
|
||||
Directory m_tmpDirs[2];
|
||||
BlockAllocationTable m_tmpBats[2];
|
||||
uint8_t m_currentDir;
|
||||
uint8_t m_currentBat;
|
||||
|
||||
@@ -134,12 +120,15 @@ class Card
|
||||
char m_game[5] = {'\0'};
|
||||
char m_maker[3] = {'\0'};
|
||||
|
||||
void _swapEndian();
|
||||
void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat);
|
||||
void _updateChecksum();
|
||||
File* _fileFromHandle(const FileHandle& fh) const;
|
||||
void _deleteFile(File& f, BlockAllocationTable& bat);
|
||||
|
||||
bool m_dirty = false;
|
||||
bool m_opened = false;
|
||||
ECardResult _pumpOpen();
|
||||
|
||||
public:
|
||||
Card();
|
||||
/**
|
||||
@@ -157,7 +146,7 @@ public:
|
||||
* @param game
|
||||
* @param maker
|
||||
*/
|
||||
Card(SystemStringView filepath, const char* game = nullptr, const char* maker = nullptr);
|
||||
Card(const char* game = nullptr, const char* maker = nullptr);
|
||||
~Card();
|
||||
|
||||
/**
|
||||
@@ -237,7 +226,7 @@ public:
|
||||
* @param buf
|
||||
* @param size
|
||||
*/
|
||||
ECardResult write(FileHandle& fh, const void* buf, size_t size);
|
||||
ECardResult asyncWrite(FileHandle& fh, const void* buf, size_t size);
|
||||
|
||||
/**
|
||||
* @brief read
|
||||
@@ -245,7 +234,7 @@ public:
|
||||
* @param dst
|
||||
* @param size
|
||||
*/
|
||||
ECardResult read(FileHandle& fh, void* dst, size_t size);
|
||||
ECardResult asyncRead(FileHandle& fh, void* dst, size_t size);
|
||||
|
||||
/**
|
||||
* @brief seek
|
||||
@@ -336,6 +325,7 @@ public:
|
||||
*/
|
||||
ECardResult setStatus(uint32_t fileNo, const CardStat& stat);
|
||||
|
||||
#if 0 // TODO: Async-friendly implementations
|
||||
/**
|
||||
* @brief Copies a file from the current Card instance to a specified Card instance
|
||||
* @param fh The file to copy
|
||||
@@ -351,6 +341,7 @@ public:
|
||||
* @return
|
||||
*/
|
||||
bool moveFileTo(FileHandle& fh, Card& dest);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sets the current game, if not null any openFile requests will only return files that match this game
|
||||
@@ -417,6 +408,11 @@ public:
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* @brief Opens card image (does nothing if currently open path matches)
|
||||
*/
|
||||
bool open(SystemStringView filepath);
|
||||
|
||||
/**
|
||||
* @brief Commits changes to disk and closes host file
|
||||
*/
|
||||
|
||||
@@ -250,71 +250,6 @@ typedef struct stat Sstat;
|
||||
|
||||
uint64_t getGCTime();
|
||||
|
||||
enum class FileLockType
|
||||
{
|
||||
None = 0,
|
||||
Read,
|
||||
Write
|
||||
};
|
||||
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None)
|
||||
{
|
||||
#if CARD_UCS2
|
||||
FILE* fp = _wfopen(path, mode);
|
||||
if (!fp)
|
||||
return nullptr;
|
||||
#else
|
||||
FILE* fp = fopen(path, mode);
|
||||
if (!fp)
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
if (lock != FileLockType::None)
|
||||
{
|
||||
#if _WIN32
|
||||
OVERLAPPED ov = {};
|
||||
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1,
|
||||
&ov);
|
||||
#else
|
||||
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
|
||||
fprintf(stderr, "flock %s: %s", path, strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static inline int FSeek(FILE* fp, int64_t offset, int whence)
|
||||
{
|
||||
#if _WIN32
|
||||
return _fseeki64(fp, offset, whence);
|
||||
#elif __APPLE__ || __FreeBSD__
|
||||
return fseeko(fp, offset, whence);
|
||||
#else
|
||||
return fseeko64(fp, offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int64_t FTell(FILE* fp)
|
||||
{
|
||||
#if _WIN32
|
||||
return _ftelli64(fp);
|
||||
#elif __APPLE__ || __FreeBSD__
|
||||
return ftello(fp);
|
||||
#else
|
||||
return ftello64(fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int Rename(const SystemChar* oldpath, const SystemChar* newpath)
|
||||
{
|
||||
#if CARD_UCS2
|
||||
//return _wrename(oldpath, newpath);
|
||||
return MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0;
|
||||
#else
|
||||
return rename(oldpath, newpath);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
@@ -349,6 +284,26 @@ static inline int Stat(const SystemChar* path, Sstat* statOut)
|
||||
* @param checksumInv
|
||||
*/
|
||||
void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
||||
|
||||
#undef NOFILE
|
||||
|
||||
enum class ECardResult
|
||||
{
|
||||
CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */
|
||||
FATAL_ERROR = -128,
|
||||
ENCODING = -13,
|
||||
NAMETOOLONG = -12,
|
||||
INSSPACE = -9,
|
||||
NOENT = -8,
|
||||
EXIST = -7,
|
||||
BROKEN = -6,
|
||||
IOERROR = -5,
|
||||
NOFILE = -4,
|
||||
NOCARD = -3,
|
||||
WRONGDEVICE = -2,
|
||||
BUSY = -1,
|
||||
READY = 0
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __KABU_UTIL_HPP__
|
||||
|
||||
Reference in New Issue
Block a user