forked from 0ad/0ad
150 lines
5.1 KiB
C++
150 lines
5.1 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : file_io.h
|
|
* Project : 0 A.D.
|
|
* Description : provide fast I/O via POSIX aio and splitting into blocks.
|
|
* =========================================================================
|
|
*/
|
|
|
|
// license: GPL; see lib/license.txt
|
|
|
|
#ifndef INCLUDED_FILE_IO
|
|
#define INCLUDED_FILE_IO
|
|
|
|
struct FileProvider_VTbl;
|
|
struct File;
|
|
|
|
|
|
namespace ERR
|
|
{
|
|
const LibError IO = -110100;
|
|
const LibError IO_EOF = -110101;
|
|
}
|
|
|
|
|
|
extern void file_io_init();
|
|
extern void file_io_shutdown();
|
|
|
|
|
|
//
|
|
// asynchronous IO
|
|
//
|
|
|
|
// this is a thin wrapper on top of the system AIO calls.
|
|
// IOs are carried out exactly as requested - there is no caching or
|
|
// alignment done here. rationale: see source.
|
|
|
|
// again chosen for nice alignment; each user checks if big enough.
|
|
const size_t FILE_IO_OPAQUE_SIZE = 28;
|
|
|
|
struct FileIo
|
|
{
|
|
const FileProvider_VTbl* type;
|
|
u8 opaque[FILE_IO_OPAQUE_SIZE];
|
|
};
|
|
|
|
// queue the IO; it begins after the previous ones (if any) complete.
|
|
//
|
|
// rationale: this interface is more convenient than implicitly advancing a
|
|
// file pointer because archive.cpp often accesses random offsets.
|
|
extern LibError file_io_issue(File* f, off_t ofs, size_t size, void* buf, FileIo* io);
|
|
|
|
// indicates if the given IO has completed.
|
|
// return value: 0 if pending, 1 if complete, < 0 on error.
|
|
extern int file_io_has_completed(FileIo* io);
|
|
|
|
// wait for the given IO to complete. passes back its buffer and size.
|
|
extern LibError file_io_wait(FileIo* io, void*& p, size_t& size);
|
|
|
|
// indicates the IO's buffer is no longer needed and frees that memory.
|
|
extern LibError file_io_discard(FileIo* io);
|
|
|
|
extern LibError file_io_validate(const FileIo* io);
|
|
|
|
|
|
//
|
|
// synchronous IO
|
|
//
|
|
|
|
extern size_t file_sector_size;
|
|
|
|
// called by file_io after a block IO has completed.
|
|
// *bytes_processed must be set; file_io will return the sum of these values.
|
|
// example: when reading compressed data and decompressing in the callback,
|
|
// indicate #bytes decompressed.
|
|
// return value: INFO::CB_CONTINUE to continue calling; anything else:
|
|
// abort immediately and return that.
|
|
// note: in situations where the entire IO is not split into blocks
|
|
// (e.g. when reading from cache or not using AIO), this is still called but
|
|
// for the entire IO. we do not split into fake blocks because it is
|
|
// advantageous (e.g. for decompressors) to have all data at once, if available
|
|
// anyway.
|
|
typedef LibError (*FileIOCB)(uintptr_t ctx, const void* block, size_t size, size_t* bytes_processed);
|
|
|
|
|
|
typedef const u8* FileIOBuf;
|
|
|
|
FileIOBuf* const FILE_BUF_TEMP = (FileIOBuf*)1;
|
|
const FileIOBuf FILE_BUF_ALLOC = (FileIOBuf)2;
|
|
|
|
|
|
enum FileBufFlags
|
|
{
|
|
// indicates the buffer will not be freed immediately
|
|
// (i.e. before the next buffer alloc) as it normally should.
|
|
// this flag serves to suppress a warning and better avoid fragmentation.
|
|
// caller sets this when FILE_LONG_LIVED is specified.
|
|
//
|
|
// also used by file_cache_retrieve because it may have to
|
|
// 'reactivate' the buffer (transfer from cache to extant list),
|
|
// which requires knowing whether the buffer is long-lived or not.
|
|
FB_LONG_LIVED = 1,
|
|
|
|
// statistics (e.g. # buffer allocs) should not be updated.
|
|
// (useful for simulation, e.g. trace_entry_causes_io)
|
|
FB_NO_STATS = 2,
|
|
|
|
// file_cache_retrieve should not update item credit.
|
|
// (useful when just looking up buffer given atom_fn)
|
|
FB_NO_ACCOUNTING = 4,
|
|
|
|
// memory will be allocated from the heap, not the (limited) file cache.
|
|
// this makes sense for write buffers that are never used again,
|
|
// because we avoid having to displace some other cached items.
|
|
FB_FROM_HEAP = 8
|
|
};
|
|
|
|
// allocate a new buffer of <size> bytes (possibly more due to internal
|
|
// fragmentation). never returns 0.
|
|
// <atom_fn>: owner filename (buffer is intended to be used for data from
|
|
// this file).
|
|
extern FileIOBuf file_buf_alloc(size_t size, const char* atom_fn, uint fb_flags = 0);
|
|
|
|
// mark <buf> as no longer needed. if its reference count drops to 0,
|
|
// it will be removed from the extant list. if it had been added to the
|
|
// cache, it remains there until evicted in favor of another buffer.
|
|
extern LibError file_buf_free(FileIOBuf buf, uint fb_flags = 0);
|
|
|
|
|
|
// transfer <size> bytes, starting at <ofs>, to/from the given file.
|
|
// (read or write access was chosen at file-open time).
|
|
//
|
|
// if non-NULL, <cb> is called for each block transferred, passing <ctx>.
|
|
// it returns how much data was actually transferred, or a negative error
|
|
// code (in which case we abort the transfer and return that value).
|
|
// the callback mechanism is useful for user progress notification or
|
|
// processing data while waiting for the next I/O to complete
|
|
// (quasi-parallel, without the complexity of threads).
|
|
//
|
|
// return number of bytes transferred (see above), or a negative error code.
|
|
extern ssize_t file_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb = 0, uintptr_t ctx = 0);
|
|
|
|
extern ssize_t file_read_from_cache(const char* atom_fn, off_t ofs, size_t size,
|
|
FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
|
|
|
|
|
|
extern LibError file_io_get_buf(FileIOBuf* pbuf, size_t size,
|
|
const char* atom_fn, uint file_flags, FileIOCB cb);
|
|
|
|
#endif // #ifndef INCLUDED_FILE_IO
|