forked from 0ad/0ad
no message
This was SVN commit r167.
This commit is contained in:
parent
805328d2bd
commit
a8d448ad19
@ -27,6 +27,7 @@ extern "C" {
|
||||
|
||||
|
||||
// useful for choosing a video mode. not called by detect().
|
||||
// if we fail, don't change the outputs (assumed initialized to defaults)
|
||||
extern void get_cur_resolution(int& xres, int& yres);
|
||||
|
||||
|
||||
|
@ -728,8 +728,7 @@ ssize_t file_io(File* const f, const size_t raw_ofs, size_t raw_size, void** con
|
||||
{
|
||||
if(raw_ofs >= f->size)
|
||||
return ERR_EOF;
|
||||
size_t bytes_left = f->size - raw_ofs; // > 0
|
||||
size_t max_size = MIN(bytes_left, raw_size);
|
||||
raw_size = MIN(f->size - raw_ofs, raw_size);
|
||||
}
|
||||
// writing: make sure buffer is valid
|
||||
else
|
||||
|
@ -138,19 +138,19 @@ static int Font_reload(Font* f, const char* fn)
|
||||
Handle err = vfs_load(fn, tmp_file, file_size);
|
||||
if(err <= 0)
|
||||
return (int)err;
|
||||
void* p = mem_alloc(file_size + 1);
|
||||
if(!p)
|
||||
void* file = mem_alloc(file_size + 1);
|
||||
if(!file)
|
||||
return ERR_NO_MEM;
|
||||
memcpy(p, tmp_file, file_size);
|
||||
((char*)p)[file_size] = 0; // 0-terminate for sscanf
|
||||
memcpy(file, tmp_file, file_size);
|
||||
((char*)file)[file_size] = 0; // 0-terminate for sscanf
|
||||
|
||||
int pos; // current position in the file
|
||||
const char* file = (const char*)p;
|
||||
const char* p = (const char*)file;
|
||||
|
||||
// read header
|
||||
char tex_filename[PATH_MAX];
|
||||
int x_stride, y_stride; // glyph spacing in texture
|
||||
if(sscanf(file, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3)
|
||||
if(sscanf(p, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3)
|
||||
{
|
||||
debug_out("Font_reload: \"%s\": header is invalid", fn);
|
||||
return -1;
|
||||
@ -160,15 +160,15 @@ static int Font_reload(Font* f, const char* fn)
|
||||
int adv[128];
|
||||
for(int i = 32; i < 128; i++)
|
||||
{
|
||||
file += pos;
|
||||
if(sscanf(file, "%d %n", &adv[i], &pos) != 1)
|
||||
p += pos;
|
||||
if(sscanf(p, "%d %n", &adv[i], &pos) != 1)
|
||||
{
|
||||
debug_out("Font_reload: \"%s\": glyph width array is invalid", fn);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mem_free(p);
|
||||
mem_free(file);
|
||||
|
||||
// load glyph texture
|
||||
const Handle ht = tex_load(tex_filename);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// handle-based resource manager
|
||||
// handle manager
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
@ -33,28 +33,50 @@
|
||||
// handle
|
||||
//
|
||||
|
||||
// TODO: explain handle scheme, how it solves problems
|
||||
// handles are an indirection layer between client code and resources.
|
||||
// they allow an important check not possible with a direct pointer:
|
||||
// guaranteeing the handle references a given resource /instance/.
|
||||
//
|
||||
// problem: code C1 allocates a resource, and receives a pointer p to its
|
||||
// control block. C1 passes p on to C2, and later frees it.
|
||||
// now other code allocates a resource, and happens to reuse the free slot
|
||||
// pointed to by p (also possible if simply allocating from the heap).
|
||||
// when C2 accesses p, the pointer is valid, but we cannot tell that
|
||||
// it is referring to a resource that had already been freed. big trouble.
|
||||
//
|
||||
// solution: each allocation receives a unique tag (a global counter that
|
||||
// is large enough to never overflow). Handles include this tag, as well
|
||||
// as a reference (array index) to the control block, which isn't directly
|
||||
// accessible. when dereferencing the handle, we check if the handle's tag
|
||||
// matches the copy stored in the control block. this protects against stale
|
||||
// handle reuse, double-free, and accidentally referencing other resources.
|
||||
//
|
||||
// type: each handle has an associated type. these must be checked to prevent
|
||||
// using textures as sounds, for example. with the manual vtbl scheme,
|
||||
// this type is actually a pointer to the resource object's vtbl, and is
|
||||
// set up via H_TYPE_DEFINE. see header for rationale. this means that
|
||||
// types are private to the module that declared the handle; knowledge
|
||||
// of the type ensures the caller actually declared, and owns the resource.
|
||||
|
||||
// 0 = invalid handle value
|
||||
// < 0 is an error code (we assume < 0 <==> MSB is set -
|
||||
// true for 1s and 2s complement and sign-magnitude systems)
|
||||
//
|
||||
// tag = 1-based; index = 0-based
|
||||
//
|
||||
// shift value = # bits between LSB and field LSB.
|
||||
// may be larger than the field type - only shift Handle vars!
|
||||
|
||||
// fields:
|
||||
// - allows checking if the resource has been freed
|
||||
// determines maximum unambiguous resource allocs
|
||||
// (shift value = # bits between LSB and field LSB.
|
||||
// may be larger than the field type - only shift Handle vars!)
|
||||
|
||||
// - tag (1-based) ensures the handle references a certain resource instance.
|
||||
// (field width determines maximum unambiguous resource allocs)
|
||||
#define TAG_BITS 32
|
||||
const uint TAG_SHIFT = 0;
|
||||
const Handle TAG_MASK = (((Handle)1) << TAG_BITS) - 1;
|
||||
// - index into data array
|
||||
// determines maximum (currently open) handles
|
||||
const u32 TAG_MASK = 0xffffffff; // safer than (1 << 32) - 1
|
||||
|
||||
// - index (0-based) points to control block in our array.
|
||||
// (field width determines maximum currently open handles)
|
||||
#define IDX_BITS 16
|
||||
const uint IDX_SHIFT = 32;
|
||||
const u32 IDX_MASK = (((Handle)1) << IDX_BITS) - 1;
|
||||
const i32 IDX_MASK = (1l << IDX_BITS) - 1;
|
||||
|
||||
cassert(IDX_BITS + TAG_BITS <= sizeof(Handle)*CHAR_BIT);
|
||||
|
||||
@ -156,17 +178,11 @@ static HDATA* h_data(const i32 idx)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int h_data_tag = 0;
|
||||
|
||||
// get HDATA for the given handle. verifies the handle
|
||||
// isn't invalid or an error code, and checks the tag field.
|
||||
// used by the few functions callable for any handle type, e.g. h_filename.
|
||||
static HDATA* h_data_any_type(const Handle h)
|
||||
{
|
||||
h_data_tag++;
|
||||
|
||||
#ifdef PARANOIA
|
||||
check_heap();
|
||||
#endif
|
||||
@ -222,7 +238,7 @@ static void cleanup(void)
|
||||
if(hd)
|
||||
{
|
||||
// somewhat messy, but this only happens on cleanup.
|
||||
// better, i think, than an additional h_free(i32 idx) version.
|
||||
// better than an additional h_free(i32 idx) version though.
|
||||
Handle h = handle(i, hd->tag);
|
||||
h_free(h, hd->type);
|
||||
}
|
||||
@ -239,15 +255,10 @@ static void cleanup(void)
|
||||
|
||||
|
||||
|
||||
static int alloc_idx(i32* pidx, HDATA** phd)
|
||||
// idx and hd are undefined if we fail.
|
||||
// called by h_alloc only.
|
||||
static int alloc_idx(i32& idx, HDATA*& hd)
|
||||
{
|
||||
assert(pidx && phd && "alloc_idx: invalid param");
|
||||
*pidx = 0;
|
||||
*phd = 0;
|
||||
|
||||
i32 idx;
|
||||
HDATA* hd;
|
||||
|
||||
// we already know the first free entry
|
||||
if(first_free != -1)
|
||||
{
|
||||
@ -297,8 +308,6 @@ have_idx:;
|
||||
if(idx > last_in_use)
|
||||
last_in_use = idx;
|
||||
|
||||
*pidx = idx;
|
||||
*phd = hd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -319,9 +328,14 @@ int h_free(Handle& h, H_Type type)
|
||||
if(!hd)
|
||||
return ERR_INVALID_HANDLE;
|
||||
|
||||
// not the last reference
|
||||
if(--hd->refs)
|
||||
return 0;
|
||||
// have valid refcount (don't decrement if alread 0)
|
||||
if(hd->refs > 0)
|
||||
{
|
||||
hd->refs--;
|
||||
// not the last reference
|
||||
if(hd->refs > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: keep this handle open (cache)
|
||||
|
||||
@ -345,7 +359,9 @@ int h_free(Handle& h, H_Type type)
|
||||
// any further params are passed to type's init routine
|
||||
Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
|
||||
{
|
||||
// ONCE(atexit(cleanup))
|
||||
ONCE(atexit(cleanup))
|
||||
|
||||
Handle err;
|
||||
|
||||
i32 idx;
|
||||
HDATA* hd;
|
||||
@ -400,13 +416,15 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
|
||||
*/
|
||||
}
|
||||
|
||||
if(alloc_idx(&idx, &hd) < 0)
|
||||
return 0;
|
||||
err = alloc_idx(idx, hd);
|
||||
if(err < 0)
|
||||
return err;
|
||||
|
||||
static u32 tag;
|
||||
if(++tag >= TAG_MASK)
|
||||
{
|
||||
assert(!"h_alloc: tag overflow - may not notice stale handle reuse (increase TAG_BITS)");
|
||||
assert(0 && "h_alloc: tag overflow - allocations are no longer unique."\
|
||||
"may not notice stale handle reuse. increase TAG_BITS.");
|
||||
tag = 1;
|
||||
}
|
||||
|
||||
@ -427,11 +445,11 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
|
||||
|
||||
if(vtbl->reload)
|
||||
{
|
||||
int err = vtbl->reload(hd->user, fn);
|
||||
err = vtbl->reload(hd->user, fn);
|
||||
if(err < 0)
|
||||
{
|
||||
h_free(h, type);
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// handle based caching resource manager
|
||||
// handle manager
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
@ -16,8 +16,8 @@
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __RES_H__
|
||||
#define __RES_H__
|
||||
#ifndef H_MGR_H__
|
||||
#define H_MGR_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -71,14 +71,14 @@ but- has to handle variable params, a bit ugly
|
||||
// - class (difficult to compare type, handle manager needs to know of all users)
|
||||
//
|
||||
// checked in h_alloc:
|
||||
// - user_size must fit in what res.cpp is offering (currently 44 bytes)
|
||||
// - user_size must fit in what the handle manager provides
|
||||
// - name must not be 0
|
||||
//
|
||||
// init: user data is initially zeroed
|
||||
// dtor: user data is zeroed automatically afterwards
|
||||
// dtor: user data is zeroed afterwards
|
||||
// reload: if this resource type is opened by another resource's reload,
|
||||
// our reload routine MUST check if already opened! This is relevant when
|
||||
// a file is invalidated: if e.g. a sound object opens a file, the handle
|
||||
// a file is reloaded: if e.g. a sound object opens a file, the handle
|
||||
// manager calls the reload routines for the 2 handles in unspecified order.
|
||||
// ensuring the order would require a tag field that can't overflow -
|
||||
// not really guaranteed with 32-bit handles. it'd also be more work
|
||||
@ -96,17 +96,24 @@ struct H_VTbl
|
||||
typedef H_VTbl* H_Type;
|
||||
|
||||
#define H_TYPE_DEFINE(t)\
|
||||
static void t##_init(t*, va_list);\
|
||||
static int t##_reload(t*, const char*);\
|
||||
static void t##_dtor(t*);\
|
||||
static H_VTbl V_##t = {\
|
||||
(void(*)(void*, va_list))t##_init,\
|
||||
(int(*)(void*, const char*))t##_reload,\
|
||||
(void(*)(void*))t##_dtor,\
|
||||
sizeof(t),\
|
||||
#t\
|
||||
};\
|
||||
static H_Type H_##t = &V_##t;
|
||||
/* forward decls */\
|
||||
static void t##_init(t*, va_list);\
|
||||
static int t##_reload(t*, const char*);\
|
||||
static void t##_dtor(t*);\
|
||||
static H_VTbl V_##t =\
|
||||
{\
|
||||
(void(*)(void*, va_list))t##_init,\
|
||||
(int(*)(void*, const char*))t##_reload,\
|
||||
(void(*)(void*))t##_dtor,\
|
||||
sizeof(t), /* control block size */\
|
||||
#t /* name */\
|
||||
};\
|
||||
static H_Type H_##t = &V_##t;
|
||||
|
||||
// note: we cast to void* pointers so the functions can be declared to
|
||||
// take the control block pointers, instead of requiring a cast in each.
|
||||
// the forward decls ensure the function signatures are correct.
|
||||
|
||||
|
||||
// <type>* <var> = H_USER_DATA(<h_var>, <type>)
|
||||
#define H_USER_DATA(h, type) (type*)h_user_data(h, H_##type);
|
||||
@ -185,4 +192,4 @@ extern int res_cur_scope;
|
||||
#endif
|
||||
|
||||
|
||||
#endif // #ifndef __RES_H__
|
||||
#endif // #ifndef H_MGR_H__
|
||||
|
@ -24,7 +24,6 @@ extern void* mem_alloc(size_t size, uint align = 1, uint flags = 0, Handle* ph =
|
||||
#define mem_free(p) mem_free_p((void*&)p)
|
||||
extern int mem_free_p(void*& p);
|
||||
|
||||
// faster than mem_free(void*) - no scan of open handles for the pointer
|
||||
extern int mem_free_h(Handle& hm);
|
||||
|
||||
// create a H_MEM handle of type MEM_USER,
|
||||
|
@ -577,7 +577,7 @@ Handle vfs_load(const char* fn, void*& p, size_t& size)
|
||||
|
||||
size = vf->size;
|
||||
{ // VC6 goto fix
|
||||
size_t nread = vfs_io(hf, 0, size, p);
|
||||
ssize_t nread = vfs_io(hf, 0, size, p);
|
||||
if(nread > 0)
|
||||
hm = mem_assign(p, size);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ ssize_t zip_inflate(uintptr_t ctx, void* in, size_t in_size)
|
||||
size_t avail_out = stream->avail_out;
|
||||
assert(avail_out <= prev_avail_out);
|
||||
// make sure output buffer size didn't magically increase
|
||||
size_t nread = prev_avail_out - avail_out;
|
||||
ssize_t nread = (ssize_t)(prev_avail_out - avail_out);
|
||||
if(!nread)
|
||||
return (err < 0)? err : 0;
|
||||
// try to pass along the ZLib error code, but make sure
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// AioHandles
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -54,8 +54,6 @@ private:
|
||||
uint size;
|
||||
};
|
||||
|
||||
static AioHandles* aio_hs;
|
||||
|
||||
|
||||
AioHandles::~AioHandles()
|
||||
{
|
||||
@ -76,6 +74,14 @@ AioHandles::~AioHandles()
|
||||
}
|
||||
|
||||
|
||||
bool is_valid_file_handle(HANDLE h)
|
||||
{
|
||||
SetLastError(0);
|
||||
bool valid = (GetFileSize(h, 0) != INVALID_FILE_SIZE);
|
||||
assert(valid);
|
||||
return valid;
|
||||
}
|
||||
|
||||
// get async capable handle to file <fd>
|
||||
HANDLE AioHandles::get(int fd)
|
||||
{
|
||||
@ -85,6 +91,11 @@ HANDLE AioHandles::get(int fd)
|
||||
|
||||
if((unsigned)fd < size)
|
||||
h = hs[fd];
|
||||
else
|
||||
assert(0);
|
||||
|
||||
if(!is_valid_file_handle(h))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
win_unlock(WAIO_CS);
|
||||
|
||||
@ -110,10 +121,20 @@ int AioHandles::set(int fd, HANDLE h)
|
||||
size = size2;
|
||||
}
|
||||
|
||||
if(hs[fd] != INVALID_HANDLE_VALUE)
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
;
|
||||
else
|
||||
{
|
||||
assert("set_aio_h: handle already set!");
|
||||
goto fail;
|
||||
if(hs[fd] != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
assert("AioHandles::set: handle already set!");
|
||||
goto fail;
|
||||
}
|
||||
if(!is_valid_file_handle(h))
|
||||
{
|
||||
assert("AioHandles::set: setting invalid handle");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hs[fd] = h;
|
||||
@ -123,79 +144,14 @@ int AioHandles::set(int fd, HANDLE h)
|
||||
|
||||
fail:
|
||||
win_unlock(WAIO_CS);
|
||||
assert(0 && "AioHandles::set failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int aio_assign_handle(uintptr_t handle)
|
||||
{
|
||||
//
|
||||
// CRT stores osfhandle. if we pass an invalid handle (say, 0),
|
||||
// we get an exception when closing the handle if debugging.
|
||||
// events can be created relatively quickly (~1800 clocks = 1µs),
|
||||
// and are also freed with CloseHandle, so just pass that.
|
||||
HANDLE h = CreateEvent(0,0,0,0);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
int fd = _open_osfhandle((intptr_t)h, 0);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
return aio_hs->set(fd, (HANDLE)handle);
|
||||
}
|
||||
|
||||
static void init();
|
||||
|
||||
// open fn in async mode; associate with fd (retrieve via aio_h(fd))
|
||||
int aio_open(const char* fn, int mode, int fd)
|
||||
{
|
||||
WIN_ONCE(init()); // TODO: need to do this elsewhere in case other routines called first?
|
||||
|
||||
// interpret mode
|
||||
DWORD access = GENERIC_READ; // assume O_RDONLY
|
||||
DWORD share = 0;
|
||||
if(mode & O_WRONLY)
|
||||
access = GENERIC_WRITE;
|
||||
else if(mode & O_RDWR)
|
||||
access = GENERIC_READ|GENERIC_WRITE;
|
||||
else
|
||||
share = FILE_SHARE_READ;
|
||||
DWORD create = OPEN_EXISTING;
|
||||
if(mode & O_CREAT)
|
||||
create = (mode & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
|
||||
DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
|
||||
// open file
|
||||
HANDLE h = CreateFile(fn, access, share, 0, create, flags, 0);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if(aio_hs->set(fd, h) < 0)
|
||||
{
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int aio_close(int fd)
|
||||
{
|
||||
HANDLE h = aio_hs->get(fd);
|
||||
if(h == INVALID_HANDLE_VALUE) // out of bounds or already closed
|
||||
return -1;
|
||||
|
||||
CloseHandle(h);
|
||||
aio_hs->set(fd, INVALID_HANDLE_VALUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// Req
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -206,7 +162,7 @@ struct Req
|
||||
aiocb* cb;
|
||||
|
||||
OVERLAPPED ovl;
|
||||
// hEvent signals when transfer complete
|
||||
// hEvent signals when transfer complete
|
||||
|
||||
// read into a separate align buffer if necessary
|
||||
// (note: unaligned writes aren't supported. see aio_rw)
|
||||
@ -269,6 +225,7 @@ Req* Reqs::find(const aiocb* cb)
|
||||
if(r->cb == cb)
|
||||
return r;
|
||||
|
||||
assert(0 && "Reqs::find failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -292,17 +249,27 @@ Req* Reqs::alloc(const aiocb* cb)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// init / cleanup
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AioHandles* aio_hs;
|
||||
static Reqs* reqs;
|
||||
|
||||
|
||||
// Win32 functions require sector aligned transfers.
|
||||
// max of all drives' size is checked in init().
|
||||
static size_t sector_size = 4096; // minimum: one page
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static Reqs* reqs;
|
||||
static void cleanup(void)
|
||||
{
|
||||
delete aio_hs;
|
||||
delete reqs;
|
||||
}
|
||||
|
||||
|
||||
// caller ensures this is not re-entered!
|
||||
@ -311,6 +278,8 @@ static void init()
|
||||
reqs = new Reqs;
|
||||
aio_hs = new AioHandles;
|
||||
|
||||
atexit(cleanup);
|
||||
|
||||
// Win32 requires transfers to be sector aligned.
|
||||
// find maximum of all drive's sector sizes, then use that.
|
||||
// (it's good to know this up-front, and checking every open() is slow).
|
||||
@ -339,6 +308,92 @@ static void init()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int aio_assign_handle(uintptr_t handle)
|
||||
{
|
||||
//
|
||||
// CRT stores osfhandle. if we pass an invalid handle (say, 0),
|
||||
// we get an exception when closing the handle if debugging.
|
||||
// events can be created relatively quickly (~1800 clocks = 1µs),
|
||||
// and are also freed with CloseHandle, so just pass that.
|
||||
HANDLE h = CreateEvent(0,0,0,0);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
assert(0 && "aio_assign_handle failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = _open_osfhandle((intptr_t)h, 0);
|
||||
if(fd < 0)
|
||||
{
|
||||
assert(0 && "aio_assign_handle failed");
|
||||
return fd;
|
||||
}
|
||||
|
||||
return aio_hs->set(fd, (HANDLE)handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// open fn in async mode; associate with fd (retrieve via aio_h(fd))
|
||||
int aio_open(const char* fn, int mode, int fd)
|
||||
{
|
||||
WIN_ONCE(init()); // TODO: need to do this elsewhere in case other routines called first?
|
||||
|
||||
// interpret mode
|
||||
DWORD access = GENERIC_READ; // assume O_RDONLY
|
||||
DWORD share = 0;
|
||||
if(mode & O_WRONLY)
|
||||
access = GENERIC_WRITE;
|
||||
else if(mode & O_RDWR)
|
||||
access = GENERIC_READ|GENERIC_WRITE;
|
||||
else
|
||||
share = FILE_SHARE_READ;
|
||||
DWORD create = OPEN_EXISTING;
|
||||
if(mode & O_CREAT)
|
||||
create = (mode & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
|
||||
DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
|
||||
// open file
|
||||
HANDLE h = CreateFile(fn, access, share, 0, create, flags, 0);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
assert(0 && "aio_open failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(aio_hs->set(fd, h) < 0)
|
||||
{
|
||||
assert(0 && "aio_open failed");
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int aio_close(int fd)
|
||||
{
|
||||
HANDLE h = aio_hs->get(fd);
|
||||
if(h == INVALID_HANDLE_VALUE) // out of bounds or already closed
|
||||
{
|
||||
assert(0 && "aio_close failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetLastError(0);
|
||||
if(!CloseHandle(h))
|
||||
assert(0);
|
||||
aio_hs->set(fd, INVALID_HANDLE_VALUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// called by aio_read, aio_write, and lio_listio
|
||||
// cb->aio_lio_opcode specifies desired operation
|
||||
//
|
||||
@ -347,9 +402,15 @@ static void init()
|
||||
static int aio_rw(struct aiocb* cb)
|
||||
{
|
||||
if(!cb)
|
||||
{
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
if(cb->aio_lio_opcode == LIO_NOP)
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE h = aio_hs->get(cb->aio_fildes);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
@ -360,7 +421,10 @@ static int aio_rw(struct aiocb* cb)
|
||||
|
||||
Req* r = reqs->alloc(cb);
|
||||
if(!r)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t ofs = 0;
|
||||
size_t size = cb->aio_nbytes;
|
||||
@ -406,6 +470,8 @@ static int aio_rw(struct aiocb* cb)
|
||||
}
|
||||
}
|
||||
|
||||
r->ovl.Internal = r->ovl.InternalHigh = 0;
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
r->ovl.Pointer = (void*)ofs;
|
||||
#else
|
||||
@ -414,6 +480,8 @@ static int aio_rw(struct aiocb* cb)
|
||||
|
||||
assert(cb->aio_buf != 0);
|
||||
|
||||
SetLastError(0);
|
||||
|
||||
DWORD size32 = (DWORD)(size & 0xffffffff);
|
||||
ResetEvent(r->ovl.hEvent);
|
||||
BOOL ok = (cb->aio_lio_opcode == LIO_READ)?
|
||||
@ -443,11 +511,20 @@ int lio_listio(int mode, struct aiocb* const cbs[], int n, struct sigevent* se)
|
||||
{
|
||||
UNUSED(se)
|
||||
|
||||
int err = 0;
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
aio_rw(cbs[i]); // aio_rw checks for 0 param
|
||||
{
|
||||
int ret = aio_rw(cbs[i]); // aio_rw checks for 0 param
|
||||
if(ret < 0)
|
||||
err = ret;
|
||||
}
|
||||
|
||||
if(err < 0)
|
||||
return err;
|
||||
|
||||
if(mode == LIO_WAIT)
|
||||
aio_suspend(cbs, n, 0);
|
||||
return aio_suspend(cbs, n, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,13 +30,20 @@
|
||||
#endif
|
||||
|
||||
|
||||
// useful for choosing a video mode. not called by detect().
|
||||
// if we fail, don't change the outputs (assumed initialized to defaults)
|
||||
void get_cur_resolution(int& xres, int& yres)
|
||||
{
|
||||
static DEVMODE dm;
|
||||
DEVMODEA dm;
|
||||
memset(&dm, 0, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
||||
xres = dm.dmPelsWidth;
|
||||
yres = dm.dmPelsHeight;
|
||||
// dm.dmDriverExtra already set to 0 by memset
|
||||
|
||||
if(EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm))
|
||||
{
|
||||
xres = dm.dmPelsWidth;
|
||||
yres = dm.dmPelsHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,15 +20,12 @@
|
||||
#include <Xlib.h>
|
||||
|
||||
// useful for choosing a video mode. not called by detect().
|
||||
// if we fail, don't change the outputs (assumed initialized to defaults)
|
||||
void get_cur_resolution(int& xres, int& yres)
|
||||
{
|
||||
Display* disp = XOpenDisplay(NULL);
|
||||
Display* disp = XOpenDisplay(0);
|
||||
if(!disp)
|
||||
{
|
||||
xres = 1024;
|
||||
yres = 768;
|
||||
return;
|
||||
}
|
||||
|
||||
int screen = XDefaultScreen(disp);
|
||||
xres = XDisplayWidth (disp, screen);
|
||||
|
Loading…
Reference in New Issue
Block a user