mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-12 08:14:22 +00:00
317f98a6c0
archive: pretty much done except for trace and archive_builder IO: io_manager still needs to be fixed/revised (especially WRT buffer and alignment management) posix: done vfs: need to complete vfs_mount and tie it in to vfs.cpp dir_util: needs further revisions (VFS interface changed since then) This was SVN commit r5475.
200 lines
4.6 KiB
C++
200 lines
4.6 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : io_posix.cpp
|
|
* Project : 0 A.D.
|
|
* Description : lightweight POSIX aio wrapper
|
|
* =========================================================================
|
|
*/
|
|
|
|
// license: GPL; see lib/license.txt
|
|
|
|
#include "precompiled.h"
|
|
#include "io_posix.h"
|
|
|
|
#include "lib/file/filesystem.h"
|
|
#include "lib/file/path.h"
|
|
#include "lib/file/file_stats.h"
|
|
#include "lib/posix/posix_aio.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
File_Posix::File_Posix()
|
|
{
|
|
}
|
|
|
|
|
|
File_Posix::~File_Posix()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
|
|
LibError File_Posix::Open(const char* P_pathname, char mode)
|
|
{
|
|
debug_assert(mode == 'w' || mode == 'r');
|
|
|
|
m_pathname = path_Pool()->UniqueCopy(P_pathname);
|
|
m_mode = mode;
|
|
|
|
char N_pathname[PATH_MAX];
|
|
(void)path_MakeAbsolute(P_pathname, N_pathname);
|
|
|
|
int oflag = (mode == 'r')? O_RDONLY : O_WRONLY|O_CREAT|O_TRUNC;
|
|
m_fd = open(N_pathname, oflag, S_IRWXO|S_IRWXU|S_IRWXG);
|
|
if(m_fd < 0)
|
|
WARN_RETURN(ERR::FILE_ACCESS);
|
|
|
|
stats_open(m_pathname, Size());
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
void File_Posix::Close()
|
|
{
|
|
close(m_fd);
|
|
m_fd = 0;
|
|
}
|
|
|
|
|
|
LibError File_Posix::Validate() const
|
|
{
|
|
if(path_Pool()->UniqueCopy(m_pathname) != m_pathname)
|
|
WARN_RETURN(ERR::_1);
|
|
if((m_mode != 'w' && m_mode != 'r'))
|
|
WARN_RETURN(ERR::_2);
|
|
// >= 0x100 is not necessarily bogus, but suspicious.
|
|
if(!(3 <= m_fd && m_fd < 0x100))
|
|
WARN_RETURN(ERR::_3);
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class Io_Posix::Impl
|
|
{
|
|
public:
|
|
Impl()
|
|
{
|
|
memset(&m_aiocb, 0, sizeof(m_aiocb));
|
|
}
|
|
|
|
LibError Issue(File_Posix& file, off_t ofs, IoBuf buf, size_t size)
|
|
{
|
|
debug_printf("FILE| Issue ofs=0x%X size=0x%X\n", ofs, size);
|
|
|
|
m_aiocb.aio_lio_opcode = (file.Mode() == 'w')? LIO_WRITE : LIO_READ;
|
|
m_aiocb.aio_buf = (volatile void*)buf;
|
|
m_aiocb.aio_fildes = file.Handle();
|
|
m_aiocb.aio_offset = ofs;
|
|
m_aiocb.aio_nbytes = size;
|
|
struct sigevent* sig = 0; // no notification signal
|
|
if(lio_listio(LIO_NOWAIT, (aiocb**)&m_aiocb, 1, sig) != 0)
|
|
return LibError_from_errno();
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
LibError Validate() const
|
|
{
|
|
if(debug_is_pointer_bogus((void*)m_aiocb.aio_buf))
|
|
WARN_RETURN(ERR::_2);
|
|
const int opcode = m_aiocb.aio_lio_opcode;
|
|
if(opcode != LIO_WRITE && opcode != LIO_READ && opcode != LIO_NOP)
|
|
WARN_RETURN(ERR::_3);
|
|
// all other aiocb fields have no invariants we could check.
|
|
return INFO::OK;
|
|
}
|
|
|
|
LibError Status() const
|
|
{
|
|
debug_assert(Validate() == INFO::OK);
|
|
|
|
errno = 0;
|
|
int ret = aio_error(&m_aiocb);
|
|
if(ret == EINPROGRESS)
|
|
return INFO::IO_PENDING;
|
|
if(ret == 0)
|
|
return INFO::IO_COMPLETE;
|
|
|
|
return LibError_from_errno();
|
|
}
|
|
|
|
LibError WaitUntilComplete(IoBuf& buf, size_t& size)
|
|
{
|
|
debug_printf("FILE| Wait io=%p\n", this);
|
|
debug_assert(Validate() == INFO::OK);
|
|
|
|
// wait for transfer to complete.
|
|
while(aio_error(&m_aiocb) == EINPROGRESS)
|
|
aio_suspend((aiocb**)&m_aiocb, 1, (timespec*)0); // wait indefinitely
|
|
|
|
// query number of bytes transferred (-1 if the transfer failed)
|
|
const ssize_t bytes_transferred = aio_return(&m_aiocb);
|
|
debug_printf("FILE| bytes_transferred=%d aio_nbytes=%u\n", bytes_transferred, m_aiocb.aio_nbytes);
|
|
|
|
buf = (IoBuf)m_aiocb.aio_buf; // cast from volatile void*
|
|
size = bytes_transferred;
|
|
return INFO::OK;
|
|
}
|
|
|
|
private:
|
|
aiocb m_aiocb;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Io_Posix::Io_Posix()
|
|
: impl(new Impl)
|
|
{
|
|
}
|
|
|
|
Io_Posix::~Io_Posix()
|
|
{
|
|
}
|
|
|
|
LibError Io_Posix::Issue(File_Posix& file, off_t ofs, IoBuf buf, size_t size)
|
|
{
|
|
return impl.get()->Issue(file, ofs, buf, size);
|
|
}
|
|
|
|
LibError Io_Posix::Status() const
|
|
{
|
|
return impl.get()->Status();
|
|
}
|
|
|
|
LibError Io_Posix::WaitUntilComplete(IoBuf& buf, size_t& size)
|
|
{
|
|
return impl.get()->WaitUntilComplete(buf, size);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
LibError io_posix_Synchronous(File_Posix& file, off_t ofs, IoBuf buf, size_t size)
|
|
{
|
|
const int fd = file.Handle();
|
|
const bool isWrite = (file.Mode() == 'w');
|
|
|
|
ScopedIoMonitor monitor;
|
|
|
|
lseek(fd, ofs, SEEK_SET);
|
|
|
|
errno = 0;
|
|
void* dst = (void*)buf;
|
|
const ssize_t ret = isWrite? write(fd, dst, size) : read(fd, dst, size);
|
|
if(ret < 0)
|
|
return LibError_from_errno();
|
|
|
|
const size_t totalTransferred = (size_t)ret;
|
|
if(totalTransferred != size)
|
|
WARN_RETURN(ERR::IO);
|
|
|
|
monitor.NotifyOfSuccess(FI_LOWIO, isWrite? FO_WRITE : FO_READ, totalTransferred);
|
|
return INFO::OK;
|
|
}
|