1
0
forked from 0ad/0ad

- add vfs_io_complete (wasn't in header) and vfs_size (convenience function)

- have vfs_load allocate the buffer, so mem_assign is no longer needed.
exposes buffer alignment requirement to VFS, but hey. simplifies things
a good bit.
- moved performance measuring crap to vfs_timed_io, a wrapper function
- various fixes for streaming code

This was SVN commit r1159.
This commit is contained in:
janwas 2004-09-19 15:42:32 +00:00
parent b3a5bad377
commit d3f452cd80
2 changed files with 82 additions and 48 deletions

View File

@ -49,7 +49,7 @@
// *: the add_watch code would need to iterate through subdirs and watch
// each one, because the monitor API (e.g. FAM) may only be able to
// watch single directories, instead of a whole subdirectory tree.
#define NO_DIR_WATCH
//#define NO_DIR_WATCH
// rationale for no forcibly-close support:
@ -1295,6 +1295,14 @@ static int VFile_reload(VFile* vf, const char* v_fn, Handle)
}
// return the size of an already opened file, or a negative error code.
ssize_t vfs_size(Handle hf)
{
H_DEREF(hf, VFile, vf);
return vf_size(vf);
}
// open the file for synchronous or asynchronous IO. write access is
// requested via FILE_WRITE flag, and is not possible for files in archives.
Handle vfs_open(const char* v_fn, uint file_flags /* = 0 */)
@ -1391,27 +1399,42 @@ void dump()
debug_out("TOTAL TIME IN VFS_IO: %f\nthroughput: %f MB/s\n\n", dt, totaldata/dt/1e6);
}
static ssize_t vfs_timed_io(const Handle hf, const size_t size, void** p, FileIOCB cb = 0, uintptr_t ctx = 0)
{
ONCE(atexit(dump));
double t1=get_time();
totaldata += size;
ssize_t nread = vfs_io(hf, size, p, cb, ctx);
double t2=get_time();
if(t2-t1 < 1.0)
dt += t2-t1;
return nread;
}
// load the entire file <fn> into memory; return a handle to the memory
// and the buffer address/size. output parameters are zeroed on failure.
// in addition to the regular file cache, the entire buffer is kept in memory
// if flags & FILE_CACHE.
//
// note: we need the Handle return value for Tex.hm - the data pointer
// must be protected against being accidentally free-d in that case.
Handle vfs_load(const char* const v_fn, void*& p, size_t& size, uint flags /* default 0 */)
{
ONCE(atexit(dump));
#ifdef PARANOIA
debug_out("vfs_load fn=%s\n", fn);
#endif
p = 0; // vfs_io needs initial 0 value
size = 0; // in case open or deref fails
p = 0; size = 0; // zeroed in case vfs_open or H_DEREF fails
Handle hf = vfs_open(v_fn, flags);
if(hf <= 0)
return hf; // error code
H_DEREF(hf, VFile, vf);
Handle hm = 0;
Handle hm = 0; // return value - handle to memory or error code
size = vf_size(vf);
// already read into mem - return existing mem handle
@ -1423,51 +1446,36 @@ debug_out("vfs_load fn=%s\n", fn);
{
assert(vf_size(vf) == (off_t)size && "vfs_load: mismatch between File and Mem size");
hm = vf->hm;
goto skip_read;
goto ret;
}
else
debug_warn("vfs_load: invalid MEM attached to vfile (0 pointer)");
// happens if someone frees the pointer. not an error!
}
{ // VC6 goto fix
double t1=get_time();
totaldata += size;
ssize_t nread = vfs_io(hf, size, &p);
double t2=get_time();
if(t2-t1 > 1.0)
;
else
dt += t2-t1;
if(nread > 0)
// allocate memory. does expose implementation details of File
// (padding), but it greatly simplifies returning the Handle
// (if we allow File to alloc, have to make sure the Handle references
// the actual data address, not that of the padding).
const size_t BLOCK_SIZE = 64*KB;
p = mem_alloc(size, BLOCK_SIZE, 0, &hm);
if(!p)
goto ret;
ssize_t nread = vfs_timed_io(hf, size, &p);
// failed
if(nread < 0)
{
mem_free_h(hm);
hm = nread; // error code
}
else
{
// one case where we need the handle return value is Tex.hm;
// we can't have the pointer freed behind our back there.
// if someone calls mem_get_ptr or mem_size, it must return the
// real memory range (p+size), disregarding padding added by File.
// hence, mem_assign finds the actual allocation to which p belongs
// (not necessarily starting at p); we mem_assign_user a subrange.
hm = mem_assign(p, size);
assert(hm > 0);
if(mem_assign_user(hm, p, size) < 0)
debug_warn("vfs_load: mem_assign_user failed");
// sanity check: handle returns correct info
#ifndef NDEBUG
size_t test_size;
void* test_p = mem_get_ptr(hm, &test_size);
assert(test_p == p && test_size == size);
#endif
if(flags & FILE_CACHE)
{
vf->hm = hm;
// add ref to hm for VFile
}
}
}
skip_read:
ret:
vfs_close(hf);
// if FILE_CACHE, it's kept open
@ -1505,7 +1513,14 @@ int vfs_store(const char* const v_fn, void* p, const size_t size, uint flags /*
struct IO
{
FileIO io;
union
{
FileIO fio;
ZipIO zio;
};
bool is_zip; // necessary if we have separate File and Zip IO structures
// default is false, since control block is 0-initialized
};
H_TYPE_DEFINE(IO);
@ -1521,7 +1536,10 @@ static void IO_init(IO*, va_list)
static void IO_dtor(IO* io)
{
file_discard_io(io->io);
if(io->is_zip)
zip_discard_io(&io->zio);
else
file_discard_io(&io->fio);
}
@ -1545,8 +1563,11 @@ Handle vfs_start_io(Handle hf, off_t ofs, size_t size, void* buf)
H_DEREF(hf, VFile, vf);
if(vf_flags(vf) & VF_ZIP)
return zip_start_io(&vf->zf, ofs, size, buf, &io->io);
return file_start_io(&vf->f, ofs, size, buf, &io->io);
{
io->is_zip = true;
return zip_start_io(&vf->zf, ofs, size, buf, &io->zio);
}
return file_start_io(&vf->f, ofs, size, buf, &io->fio);
}
@ -1555,7 +1576,10 @@ Handle vfs_start_io(Handle hf, off_t ofs, size_t size, void* buf)
inline int vfs_io_complete(Handle hio)
{
H_DEREF(hio, IO, io);
return file_io_complete(io->io);
if(io->is_zip)
return zip_io_complete(&io->zio);
else
return file_io_complete(&io->fio);
}
@ -1564,7 +1588,10 @@ inline int vfs_io_complete(Handle hio)
inline int vfs_wait_io(Handle hio, void*& p, size_t& size)
{
H_DEREF(hio, IO, io);
return file_wait_io(io->io, p, size);
if(io->is_zip)
return zip_wait_io(&io->zio, p, size);
else
return file_wait_io(&io->fio, p, size);
}

View File

@ -111,6 +111,9 @@ extern bool vfs_exists(const char* fn);
// get file status (currently only size). output param is zeroed on error.
extern int vfs_stat(const char* fn, struct stat*);
// return the size of an already opened file, or a negative error code.
extern ssize_t vfs_size(Handle hf);
// open the file for synchronous or asynchronous IO. write access is
// requested via FILE_WRITE flag, and is not possible for files in archives.
// flags defined in file.h
@ -131,6 +134,10 @@ extern int vfs_close(Handle& h);
// with vfs_wait_read; when no longer needed, free via vfs_discard_io.
extern Handle vfs_start_io(Handle hf, off_t ofs, size_t size, void* buf);
// indicates if the given IO has completed.
// return value: 0 if pending, 1 if complete, < 0 on error.
extern int vfs_io_complete(Handle hio);
// wait until the transfer <hio> completes, and return its buffer.
// output parameters are zeroed on error.
extern int vfs_wait_io(Handle hio, void*& p, size_t& size);