From a7ce178eecefb04daf4b402c07dcfc2c356e9d2f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 6 Aug 2017 09:21:38 -0400 Subject: [PATCH] Add basic atomic operations for refcounting, etc. --- src/physfs.c | 38 ++++++++++++++++++++++++++------------ src/physfs_internal.h | 16 ++++++++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/physfs.c b/src/physfs.c index 2834d873..612162a0 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -96,6 +96,30 @@ static int externalAllocator = 0; PHYSFS_Allocator allocator; +#ifdef PHYSFS_NEED_ATOMIC_OP_FALLBACK +static inline int __PHYSFS_atomicAdd(int *ptrval, const int val) +{ + int retval; + __PHYSFS_platformGrabMutex(stateLock); + retval = *ptrval; + *ptrval = retval + val; + __PHYSFS_platformReleaseMutex(stateLock); + return retval; +} /* __PHYSFS_atomicAdd */ + +int __PHYSFS_ATOMIC_INCR(int *ptrval) +{ + return __PHYSFS_atomicAdd(ptrval, 1); +} /* __PHYSFS_ATOMIC_INCR */ + +int __PHYSFS_ATOMIC_DECR(int *ptrval) +{ + return __PHYSFS_atomicAdd(ptrval, -1); +} /* __PHYSFS_ATOMIC_DECR */ +#endif + + + /* PHYSFS_Io implementation for i/o to physical filesystem... */ /* !!! FIXME: maybe refcount the paths in a string pool? */ @@ -292,10 +316,7 @@ static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io) BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL); } /* if */ - /* !!! FIXME: want lockless atomic increment. */ - __PHYSFS_platformGrabMutex(stateLock); - info->refcount++; - __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_ATOMIC_INCR(&info->refcount); memset(newinfo, '\0', sizeof (*info)); newinfo->buf = info->buf; @@ -316,7 +337,6 @@ static void memoryIo_destroy(PHYSFS_Io *io) { MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; PHYSFS_Io *parent = info->parent; - int should_die = 0; if (parent != NULL) { @@ -333,13 +353,7 @@ static void memoryIo_destroy(PHYSFS_Io *io) /* we _are_ the parent. */ assert(info->refcount > 0); /* even in a race, we hold a reference. */ - /* !!! FIXME: want lockless atomic decrement. */ - __PHYSFS_platformGrabMutex(stateLock); - info->refcount--; - should_die = (info->refcount == 0); - __PHYSFS_platformReleaseMutex(stateLock); - - if (should_die) + if (__PHYSFS_ATOMIC_DECR(&info->refcount) == 0) { void (*destruct)(void *) = info->destruct; void *buf = (void *) info->buf; diff --git a/src/physfs_internal.h b/src/physfs_internal.h index b60acfee..1deb9669 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -104,6 +104,22 @@ const void *__PHYSFS_winrtCalcBaseDir(void); const void *__PHYSFS_winrtCalcPrefDir(void); #endif +/* atomic operations. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#include +PHYSFS_COMPILE_TIME_ASSERT(LongEqualsInt, sizeof (int) == sizeof (long)); +#define __PHYSFS_ATOMIC_INCR(ptrval) _InterlockedIncrement((long*)ptrval) +#define __PHYSFS_ATOMIC_INCR(ptrval) _InterlockedDecrement((long*)ptrval) +#elif defined(__clang__) || (defined(__GNUC__) && (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100)) >= 40100)) +#define __PHYSFS_ATOMIC_INCR(ptrval) __sync_fetch_and_add(ptrval, 1) +#define __PHYSFS_ATOMIC_DECR(ptrval) __sync_fetch_and_add(ptrval, -1) +#else +#define PHYSFS_NEED_ATOMIC_OP_FALLBACK 1 +int __PHYSFS_ATOMIC_INCR(int *ptrval); +int __PHYSFS_ATOMIC_DECR(int *ptrval); +#endif + + /* * Interface for small allocations. If you need a little scratch space for * a throwaway buffer or string, use this. It will make small allocations