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().
|
// 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);
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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__
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user