From c0acfc01186c095559b6577efc5ef715d9719a96 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 23 Sep 2004 06:45:36 +0000 Subject: [PATCH] Initial structure for replacable allocator work. --- archivers/zip.c | 46 +++++++++++++++++++++++-- physfs.c | 39 +++++++++++++++++++++ physfs.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++ physfs_internal.h | 33 ++++++++++++++++++ platform/posix.c | 31 +++++++++++++++++ 5 files changed, 233 insertions(+), 2 deletions(-) diff --git a/archivers/zip.c b/archivers/zip.c index 5cc2f7eb..ee3792e4 100644 --- a/archivers/zip.c +++ b/archivers/zip.c @@ -182,6 +182,47 @@ const DirFunctions __PHYSFS_DirFunctions_ZIP = }; + +/* + * Bridge physfs allocation functions to zlib's format... + */ +static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size) +{ + /* must lock the whole time, since zlib doesn't deal with that. :( */ + PHYSFS_allocator *allocator = __PHYSFS_getAllocator(); + size_t total = (items * size) + sizeof (PHYSFS_memhandle); + PHYSFS_memhandle h = allocator->malloc(total); + char *ptr = (char *) allocator->lock(h); + PHYSFS_memhandle *ph = (PHYSFS_memhandle *) ptr; + *ph = h; /* tuck the memhandle in front of the memory block... */ + return(ptr + sizeof (PHYSFS_memhandle)); +} /* zlibPhysfsAlloc */ + + +/* + * Bridge physfs allocation functions to zlib's format... + */ +static void zlibPhysfsFree(voidpf opaque, voidpf address) +{ + char *ptr = ((char *) address) - (sizeof (PHYSFS_memhandle)); + PHYSFS_allocator *allocator = __PHYSFS_getAllocator(); + PHYSFS_memhandle *ph = (PHYSFS_memhandle *) ptr; + allocator->unlock(*ph); + allocator->free(*ph); +} /* zlibPhysfsFree */ + + +/* + * Construct a new z_stream to a sane state. + */ +static void initializeZStream(z_stream *pstr) +{ + memset(pstr, '\0', sizeof (z_stream)); + pstr->zalloc = zlibPhysfsAlloc; + pstr->zfree = zlibPhysfsFree; +} /* initializeZStream */ + + static const char *zlib_error_string(int rc) { switch (rc) @@ -360,7 +401,7 @@ static int ZIP_seek(FileHandle *handle, PHYSFS_uint64 offset) { /* we do a copy so state is sane if inflateInit2() fails. */ z_stream str; - memset(&str, '\0', sizeof (z_stream)); + initializeZStream(&str); if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK) return(0); @@ -728,7 +769,7 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry) { if (__PHYSFS_platformRead(in, compressed, compsize, 1) == 1) { - memset(&stream, '\0', sizeof (z_stream)); + initializeZStream(&stream); stream.next_in = compressed; stream.avail_in = compsize; stream.next_out = (unsigned char *) path; @@ -1404,6 +1445,7 @@ static FileHandle *ZIP_openRead(DirHandle *h, const char *fnm, int *fileExists) memset(finfo, '\0', sizeof (ZIPfileinfo)); finfo->handle = in; finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry); + initializeZStream(&finfo->stream); if (finfo->entry->compression_method != COMPMETH_NONE) { if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK) diff --git a/physfs.c b/physfs.c index ad2599a0..f11a511f 100644 --- a/physfs.c +++ b/physfs.c @@ -171,6 +171,10 @@ static int allowSymLinks = 0; static void *errorLock = NULL; /* protects error message list. */ static void *stateLock = NULL; /* protects other PhysFS static state. */ +/* allocator ... */ +static int externalAllocator = 0; +static PHYSFS_allocator allocator; + /* functions ... */ @@ -752,11 +756,17 @@ static int initializeMutexes(void) } /* initializeMutexes */ +static void setDefaultAllocator(void); + int PHYSFS_init(const char *argv0) { char *ptr; BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); + + if (!externalAllocator) + setDefaultAllocator(); + BAIL_IF_MACRO(!__PHYSFS_platformInit(), NULL, 0); BAIL_IF_MACRO(!initializeMutexes(), NULL, 0); @@ -1995,5 +2005,34 @@ LinkedStringList *__PHYSFS_addToLinkedStringList(LinkedStringList *retval, return(retval); } /* __PHYSFS_addToLinkedStringList */ + +int PHYSFS_setAllocator(PHYSFS_allocator *a) +{ + BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); + externalAllocator = (a != NULL); + if (externalAllocator) + memcpy(&allocator, a, sizeof (PHYSFS_allocator)); + + return(1); +} /* PHYSFS_setAllocator */ + + +static void setDefaultAllocator(void) +{ + assert(!externalAllocator); + allocator.malloc = __PHYSFS_platformMalloc; + allocator.realloc = __PHYSFS_platformRealloc; + allocator.free = __PHYSFS_platformFree; + allocator.lock = __PHYSFS_platformLock; + allocator.unlock = __PHYSFS_platformUnlock; +} /* setDefaultAllocator */ + + +PHYSFS_allocator *__PHYSFS_getAllocator(void) +{ + return(&allocator); +} /* __PHYFS_getAllocator */ + + /* end of physfs.c ... */ diff --git a/physfs.h b/physfs.h index 478702a4..5b13ece8 100644 --- a/physfs.h +++ b/physfs.h @@ -1820,6 +1820,92 @@ __EXPORT__ int PHYSFS_writeSBE64(PHYSFS_file *file, PHYSFS_sint64 val); __EXPORT__ int PHYSFS_writeUBE64(PHYSFS_file *file, PHYSFS_uint64 val); +/* Everything above this line is part of the PhysicsFS 1.0 API. */ + + +/** + * \typedef PHYSFS_memhandle + * \brief Used to represent memory blocks. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * The allocator routines will pass these around. They are void pointers + * because it's convenient for systems to have handles be the same size + * as a pointer, but they shouldn't be assumed to point to valid memory + * (or to memory at all). The allocator in use will convert from memhandles + * to valid pointers to allocated memory. + * + * \sa PHYSFS_allocator + * \sa PHYSFS_setAllocator + */ +typedef void *PHYSFS_memhandle; + + +/** + * \struct PHYSFS_allocator + * \brief PhysicsFS allocation function pointers. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * You create one of these structures for use with PHYSFS_setAllocator. + * It should be noted that, in order to accomodate platforms like PalmOS, + * we don't just ask for a block of memory and get a pointer. We work on + * a "handle" system, which requires PhysicsFS to "lock" before accessing, + * and "unlock" when not using. This is also useful for systems that are + * concerned about memory fragmentation; you can rearrange unlocked memory + * blocks in your address space, since PhysicsFS will re-request the pointer + * by relocking the block. + * + * Locked memory is assumed to be non-reentrant, and locking an already-locked + * handle (and unlocking an unlocked handle) has undefined results. Use + * mutexes if not sure. + * + * \sa PHYSFS_memhandle + * \sa PHYSFS_setAllocator + */ +typedef struct +{ + PHYSFS_memhandle (*malloc)(size_t); + PHYSFS_memhandle (*realloc)(PHYSFS_memhandle, size_t); + void (*free)(PHYSFS_memhandle); + void *(*lock)(PHYSFS_memhandle); + void *(*unlock)(PHYSFS_memhandle); +} PHYSFS_allocator; + + +/** + * \fn int PHYSFS_setAllocator(PHYSFS_allocator *allocator) + * \brief Hook your own allocation routines into PhysicsFS. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * By default, PhysicsFS will use ANSI C malloc/realloc/calloc/free calls + * to manage dynamic memory, but in some uncommon cases, the app might want + * more control over the library's memory management. This lets you redirect + * physfs to use your own allocation routines instead. You can only call this + * function before PHYSFS_init(); if the library is initialized, it'll + * reject your efforts to change the allocator mid-stream. You may call this + * function after PHYSFS_deinit() if you are willing to shutdown the library + * and restart it with a new allocator; this is a safe and supported + * operation. The allocator remains intact between deinit/init calls. + * If you want to return to the default allocator, pass a NULL in here. + * + * If you aren't immediately sure what to do with this function, you can + * safely ignore it altogether. + * + * \param allocator Structure containing your allocator's entry points. + * \return zero on failure, non-zero on success. This call only fails + * when used between PHYSFS_init() and PHYSFS_deinit() calls. + */ +__EXPORT__ int PHYSFS_setAllocator(PHYSFS_allocator *allocator); + + +/* Everything above this line is part of the PhysicsFS 2.0 API. */ + + #ifdef __cplusplus } #endif diff --git a/physfs_internal.h b/physfs_internal.h index 1fb0f166..bebcbe3f 100644 --- a/physfs_internal.h +++ b/physfs_internal.h @@ -1295,6 +1295,10 @@ void __PHYSFS_sort(void *entries, PHYSFS_uint32 max, #define BAIL_IF_MACRO_MUTEX(c, e, m, r) if (c) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } +/* + * Get the current allocator. Not valid before PHYSFS_init is called! + */ +PHYSFS_allocator *__PHYSFS_getAllocator(void); /*--------------------------------------------------------------------------*/ @@ -1694,6 +1698,35 @@ int __PHYSFS_platformGrabMutex(void *mutex); */ void __PHYSFS_platformReleaseMutex(void *mutex); +/* + * Implement malloc. It's safe to just pass through from the C runtime. + */ +PHYSFS_memhandle __PHYSFS_platformMalloc(size_t s); + +/* + * Implement realloc. It's safe to just pass through from the C runtime. + */ +PHYSFS_memhandle __PHYSFS_platformRealloc(PHYSFS_memhandle h, size_t s); + +/* + * Implement free. It's safe to just pass through from the C runtime. + */ +void __PHYSFS_platformFree(PHYSFS_memhandle h); + +/* + * Lock a memhandle. If you are just passing through from the C runtime, + * it is safe to make this a no-op. Otherwise, convert to a real pointer + * in the address space and return it. + */ +void *__PHYSFS_platformLock(PHYSFS_memhandle h); + +/* + * Unlock a memhandle. If you are just passing through from the C runtime, + * it is safe to make this a no-op. Otherwise, you can consider the data in + * the address space safe to move around until the handle is relocked. + */ +void __PHYSFS_platformUnlock(PHYSFS_memhandle h); + #ifdef __cplusplus } #endif diff --git a/platform/posix.c b/platform/posix.c index 5530b9a6..82ad13f8 100644 --- a/platform/posix.c +++ b/platform/posix.c @@ -500,6 +500,37 @@ PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) return statbuf.st_mtime; } /* __PHYSFS_platformGetLastModTime */ + +PHYSFS_memhandle __PHYSFS_platformMalloc(size_t s) +{ + assert(sizeof (h) == sizeof (void *)); + return((PHYSFS_memhandle) malloc(s)); +} /* __PHYSFS_platformMalloc */ + + +PHYSFS_memhandle __PHYSFS_platformRealloc(PHYSFS_memhandle h, size_t s) +{ + return((PHYSFS_memhandle) realloc((void *) h, s)); +} /* __PHYSFS_platformRealloc */ + + +void __PHYSFS_platformFree(PHYSFS_memhandle h) +{ + free((void *) h); +} /* __PHYSFS_platformFree */ + + +void *__PHYSFS_platformLock(PHYSFS_memhandle h) +{ + return((void *) h); +} /* __PHYSFS_platformLock */ + + +void __PHYSFS_platformUnlock(PHYSFS_memhandle h) +{ + /* no-op. */ +} /* __PHYSFS_platformUnlock */ + #endif /* !defined WIN32 */ /* end of posix.c ... */