1
0
forked from 0ad/0ad

no message

This was SVN commit r167.
This commit is contained in:
janwas 2004-03-03 15:16:20 +00:00
parent 805328d2bd
commit a8d448ad19
11 changed files with 267 additions and 162 deletions

View File

@ -27,6 +27,7 @@ extern "C" {
// useful for choosing a video mode. not called by detect(). // 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); extern void get_cur_resolution(int& xres, int& yres);

View File

@ -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) if(raw_ofs >= f->size)
return ERR_EOF; return ERR_EOF;
size_t bytes_left = f->size - raw_ofs; // > 0 raw_size = MIN(f->size - raw_ofs, raw_size);
size_t max_size = MIN(bytes_left, raw_size);
} }
// writing: make sure buffer is valid // writing: make sure buffer is valid
else else

View File

@ -138,19 +138,19 @@ static int Font_reload(Font* f, const char* fn)
Handle err = vfs_load(fn, tmp_file, file_size); Handle err = vfs_load(fn, tmp_file, file_size);
if(err <= 0) if(err <= 0)
return (int)err; return (int)err;
void* p = mem_alloc(file_size + 1); void* file = mem_alloc(file_size + 1);
if(!p) if(!file)
return ERR_NO_MEM; return ERR_NO_MEM;
memcpy(p, tmp_file, file_size); memcpy(file, tmp_file, file_size);
((char*)p)[file_size] = 0; // 0-terminate for sscanf ((char*)file)[file_size] = 0; // 0-terminate for sscanf
int pos; // current position in the file int pos; // current position in the file
const char* file = (const char*)p; const char* p = (const char*)file;
// read header // read header
char tex_filename[PATH_MAX]; char tex_filename[PATH_MAX];
int x_stride, y_stride; // glyph spacing in texture 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); debug_out("Font_reload: \"%s\": header is invalid", fn);
return -1; return -1;
@ -160,15 +160,15 @@ static int Font_reload(Font* f, const char* fn)
int adv[128]; int adv[128];
for(int i = 32; i < 128; i++) for(int i = 32; i < 128; i++)
{ {
file += pos; p += pos;
if(sscanf(file, "%d %n", &adv[i], &pos) != 1) if(sscanf(p, "%d %n", &adv[i], &pos) != 1)
{ {
debug_out("Font_reload: \"%s\": glyph width array is invalid", fn); debug_out("Font_reload: \"%s\": glyph width array is invalid", fn);
return -1; return -1;
} }
} }
mem_free(p); mem_free(file);
// load glyph texture // load glyph texture
const Handle ht = tex_load(tex_filename); const Handle ht = tex_load(tex_filename);

View File

@ -1,4 +1,4 @@
// handle-based resource manager // handle manager
// //
// Copyright (c) 2003 Jan Wassenberg // Copyright (c) 2003 Jan Wassenberg
// //
@ -33,28 +33,50 @@
// handle // 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 = invalid handle value
// < 0 is an error code (we assume < 0 <==> MSB is set - // < 0 is an error code (we assume < 0 <==> MSB is set -
// true for 1s and 2s complement and sign-magnitude systems) // 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: // fields:
// - allows checking if the resource has been freed // (shift value = # bits between LSB and field LSB.
// determines maximum unambiguous resource allocs // 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 #define TAG_BITS 32
const uint TAG_SHIFT = 0; const uint TAG_SHIFT = 0;
const Handle TAG_MASK = (((Handle)1) << TAG_BITS) - 1; const u32 TAG_MASK = 0xffffffff; // safer than (1 << 32) - 1
// - index into data array
// determines maximum (currently open) handles // - index (0-based) points to control block in our array.
// (field width determines maximum currently open handles)
#define IDX_BITS 16 #define IDX_BITS 16
const uint IDX_SHIFT = 32; 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); 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 // get HDATA for the given handle. verifies the handle
// isn't invalid or an error code, and checks the tag field. // 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. // used by the few functions callable for any handle type, e.g. h_filename.
static HDATA* h_data_any_type(const Handle h) static HDATA* h_data_any_type(const Handle h)
{ {
h_data_tag++;
#ifdef PARANOIA #ifdef PARANOIA
check_heap(); check_heap();
#endif #endif
@ -222,7 +238,7 @@ static void cleanup(void)
if(hd) if(hd)
{ {
// somewhat messy, but this only happens on cleanup. // 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); Handle h = handle(i, hd->tag);
h_free(h, hd->type); 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 // we already know the first free entry
if(first_free != -1) if(first_free != -1)
{ {
@ -297,8 +308,6 @@ have_idx:;
if(idx > last_in_use) if(idx > last_in_use)
last_in_use = idx; last_in_use = idx;
*pidx = idx;
*phd = hd;
return 0; return 0;
} }
@ -319,9 +328,14 @@ int h_free(Handle& h, H_Type type)
if(!hd) if(!hd)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
// not the last reference // have valid refcount (don't decrement if alread 0)
if(--hd->refs) if(hd->refs > 0)
return 0; {
hd->refs--;
// not the last reference
if(hd->refs > 0)
return 0;
}
// TODO: keep this handle open (cache) // 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 // any further params are passed to type's init routine
Handle h_alloc(H_Type type, const char* fn, uint flags, ...) Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
{ {
// ONCE(atexit(cleanup)) ONCE(atexit(cleanup))
Handle err;
i32 idx; i32 idx;
HDATA* hd; HDATA* hd;
@ -400,13 +416,15 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
*/ */
} }
if(alloc_idx(&idx, &hd) < 0) err = alloc_idx(idx, hd);
return 0; if(err < 0)
return err;
static u32 tag; static u32 tag;
if(++tag >= TAG_MASK) 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; tag = 1;
} }
@ -427,11 +445,11 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
if(vtbl->reload) if(vtbl->reload)
{ {
int err = vtbl->reload(hd->user, fn); err = vtbl->reload(hd->user, fn);
if(err < 0) if(err < 0)
{ {
h_free(h, type); h_free(h, type);
return 0; return err;
} }
} }

View File

@ -1,4 +1,4 @@
// handle based caching resource manager // handle manager
// //
// Copyright (c) 2003 Jan Wassenberg // Copyright (c) 2003 Jan Wassenberg
// //
@ -16,8 +16,8 @@
// Jan.Wassenberg@stud.uni-karlsruhe.de // Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/ // http://www.stud.uni-karlsruhe.de/~urkt/
#ifndef __RES_H__ #ifndef H_MGR_H__
#define __RES_H__ #define H_MGR_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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) // - class (difficult to compare type, handle manager needs to know of all users)
// //
// checked in h_alloc: // 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 // - name must not be 0
// //
// init: user data is initially zeroed // 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, // reload: if this resource type is opened by another resource's reload,
// our reload routine MUST check if already opened! This is relevant when // 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. // manager calls the reload routines for the 2 handles in unspecified order.
// ensuring the order would require a tag field that can't overflow - // 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 // 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; typedef H_VTbl* H_Type;
#define H_TYPE_DEFINE(t)\ #define H_TYPE_DEFINE(t)\
static void t##_init(t*, va_list);\ /* forward decls */\
static int t##_reload(t*, const char*);\ static void t##_init(t*, va_list);\
static void t##_dtor(t*);\ static int t##_reload(t*, const char*);\
static H_VTbl V_##t = {\ static void t##_dtor(t*);\
(void(*)(void*, va_list))t##_init,\ static H_VTbl V_##t =\
(int(*)(void*, const char*))t##_reload,\ {\
(void(*)(void*))t##_dtor,\ (void(*)(void*, va_list))t##_init,\
sizeof(t),\ (int(*)(void*, const char*))t##_reload,\
#t\ (void(*)(void*))t##_dtor,\
};\ sizeof(t), /* control block size */\
static H_Type H_##t = &V_##t; #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>) // <type>* <var> = H_USER_DATA(<h_var>, <type>)
#define H_USER_DATA(h, type) (type*)h_user_data(h, H_##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
#endif // #ifndef __RES_H__ #endif // #ifndef H_MGR_H__

View File

@ -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) #define mem_free(p) mem_free_p((void*&)p)
extern int 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); extern int mem_free_h(Handle& hm);
// create a H_MEM handle of type MEM_USER, // create a H_MEM handle of type MEM_USER,

View File

@ -577,7 +577,7 @@ Handle vfs_load(const char* fn, void*& p, size_t& size)
size = vf->size; size = vf->size;
{ // VC6 goto fix { // VC6 goto fix
size_t nread = vfs_io(hf, 0, size, p); ssize_t nread = vfs_io(hf, 0, size, p);
if(nread > 0) if(nread > 0)
hm = mem_assign(p, size); hm = mem_assign(p, size);
} }

View File

@ -82,7 +82,7 @@ ssize_t zip_inflate(uintptr_t ctx, void* in, size_t in_size)
size_t avail_out = stream->avail_out; size_t avail_out = stream->avail_out;
assert(avail_out <= prev_avail_out); assert(avail_out <= prev_avail_out);
// make sure output buffer size didn't magically increase // 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) if(!nread)
return (err < 0)? err : 0; return (err < 0)? err : 0;
// try to pass along the ZLib error code, but make sure // try to pass along the ZLib error code, but make sure

View File

@ -30,7 +30,7 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// // AioHandles
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -54,8 +54,6 @@ private:
uint size; uint size;
}; };
static AioHandles* aio_hs;
AioHandles::~AioHandles() 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> // get async capable handle to file <fd>
HANDLE AioHandles::get(int fd) HANDLE AioHandles::get(int fd)
{ {
@ -85,6 +91,11 @@ HANDLE AioHandles::get(int fd)
if((unsigned)fd < size) if((unsigned)fd < size)
h = hs[fd]; h = hs[fd];
else
assert(0);
if(!is_valid_file_handle(h))
return INVALID_HANDLE_VALUE;
win_unlock(WAIO_CS); win_unlock(WAIO_CS);
@ -110,10 +121,20 @@ int AioHandles::set(int fd, HANDLE h)
size = size2; size = size2;
} }
if(hs[fd] != INVALID_HANDLE_VALUE) if(h == INVALID_HANDLE_VALUE)
;
else
{ {
assert("set_aio_h: handle already set!"); if(hs[fd] != INVALID_HANDLE_VALUE)
goto fail; {
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; hs[fd] = h;
@ -123,79 +144,14 @@ int AioHandles::set(int fd, HANDLE h)
fail: fail:
win_unlock(WAIO_CS); win_unlock(WAIO_CS);
assert(0 && "AioHandles::set failed");
return -1; 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; aiocb* cb;
OVERLAPPED ovl; OVERLAPPED ovl;
// hEvent signals when transfer complete // hEvent signals when transfer complete
// read into a separate align buffer if necessary // read into a separate align buffer if necessary
// (note: unaligned writes aren't supported. see aio_rw) // (note: unaligned writes aren't supported. see aio_rw)
@ -269,6 +225,7 @@ Req* Reqs::find(const aiocb* cb)
if(r->cb == cb) if(r->cb == cb)
return r; return r;
assert(0 && "Reqs::find failed");
return 0; return 0;
} }
@ -292,17 +249,27 @@ Req* Reqs::alloc(const aiocb* cb)
return r; return r;
} }
//////////////////////////////////////////////////////////////////////////////
//
// init / cleanup
//
//////////////////////////////////////////////////////////////////////////////
static AioHandles* aio_hs;
static Reqs* reqs;
// Win32 functions require sector aligned transfers. // Win32 functions require sector aligned transfers.
// max of all drives' size is checked in init(). // max of all drives' size is checked in init().
static size_t sector_size = 4096; // minimum: one page 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! // caller ensures this is not re-entered!
@ -311,6 +278,8 @@ static void init()
reqs = new Reqs; reqs = new Reqs;
aio_hs = new AioHandles; aio_hs = new AioHandles;
atexit(cleanup);
// Win32 requires transfers to be sector aligned. // Win32 requires transfers to be sector aligned.
// find maximum of all drive's sector sizes, then use that. // 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). // (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 // called by aio_read, aio_write, and lio_listio
// cb->aio_lio_opcode specifies desired operation // cb->aio_lio_opcode specifies desired operation
// //
@ -347,9 +402,15 @@ static void init()
static int aio_rw(struct aiocb* cb) static int aio_rw(struct aiocb* cb)
{ {
if(!cb) if(!cb)
{
assert(0);
return -EINVAL; return -EINVAL;
}
if(cb->aio_lio_opcode == LIO_NOP) if(cb->aio_lio_opcode == LIO_NOP)
{
assert(0);
return 0; return 0;
}
HANDLE h = aio_hs->get(cb->aio_fildes); HANDLE h = aio_hs->get(cb->aio_fildes);
if(h == INVALID_HANDLE_VALUE) if(h == INVALID_HANDLE_VALUE)
@ -360,7 +421,10 @@ static int aio_rw(struct aiocb* cb)
Req* r = reqs->alloc(cb); Req* r = reqs->alloc(cb);
if(!r) if(!r)
{
assert(0);
return -1; return -1;
}
size_t ofs = 0; size_t ofs = 0;
size_t size = cb->aio_nbytes; 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 #if _MSC_VER >= 1300
r->ovl.Pointer = (void*)ofs; r->ovl.Pointer = (void*)ofs;
#else #else
@ -414,6 +480,8 @@ static int aio_rw(struct aiocb* cb)
assert(cb->aio_buf != 0); assert(cb->aio_buf != 0);
SetLastError(0);
DWORD size32 = (DWORD)(size & 0xffffffff); DWORD size32 = (DWORD)(size & 0xffffffff);
ResetEvent(r->ovl.hEvent); ResetEvent(r->ovl.hEvent);
BOOL ok = (cb->aio_lio_opcode == LIO_READ)? 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) UNUSED(se)
int err = 0;
for(int i = 0; i < n; i++) 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) if(mode == LIO_WAIT)
aio_suspend(cbs, n, 0); return aio_suspend(cbs, n, 0);
return 0; return 0;
} }

View File

@ -30,13 +30,20 @@
#endif #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) void get_cur_resolution(int& xres, int& yres)
{ {
static DEVMODE dm; DEVMODEA dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm); dm.dmSize = sizeof(dm);
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm); // dm.dmDriverExtra already set to 0 by memset
xres = dm.dmPelsWidth;
yres = dm.dmPelsHeight; if(EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm))
{
xres = dm.dmPelsWidth;
yres = dm.dmPelsHeight;
}
} }

View File

@ -20,15 +20,12 @@
#include <Xlib.h> #include <Xlib.h>
// useful for choosing a video mode. not called by detect(). // 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) void get_cur_resolution(int& xres, int& yres)
{ {
Display* disp = XOpenDisplay(NULL); Display* disp = XOpenDisplay(0);
if(!disp) if(!disp)
{
xres = 1024;
yres = 768;
return; return;
}
int screen = XDefaultScreen(disp); int screen = XDefaultScreen(disp);
xres = XDisplayWidth (disp, screen); xres = XDisplayWidth (disp, screen);