From 4feeab8c61334ec73172fa01cda951dafde2505f Mon Sep 17 00:00:00 2001 From: blacksirius Date: Sun, 3 Jun 2012 18:53:02 +0000 Subject: feature merge bs-coreoptimize->trunk: Atomic Operations, Threading, Spinlock implemnetation. [commit 1/2, windows will followup] - Added Abstractions for Atomic Operations (lock instructions.. windows guy's may now this as Interlocked* stuff ..) - Added Threading api abstraction for Pthread based OS's and Windows - Added Spinlock Implementation (uses CAS / if you need more informations - just read the source - its simple.) - Due to Interlocked(Compare)Exchange64 .. we now require at least i686 (Pentium Pro) for 32Bit Builds :) youll also may feel some performance improvements when using 32bit builsd due to "newer" minimal arch the compiler is now able to use CMOV's .... ================================================================ = Important Warning: ================================================================ Dont use threading at the moment athena is not threadsafe! you'll mess up everthing when accessing data from other threads .., no synchronization is provided. A way to process tasks asynchronously will come up after / with the new socket system. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16221 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/spinlock.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/common/spinlock.h (limited to 'src/common/spinlock.h') diff --git a/src/common/spinlock.h b/src/common/spinlock.h new file mode 100644 index 000000000..3419bfdd5 --- /dev/null +++ b/src/common/spinlock.h @@ -0,0 +1,104 @@ +#pragma once +#ifndef _rA_SPINLOCK_H_ +#define _rA_SPINLOCK_H_ + +// +// CAS based Spinlock Implementation +// +// CamelCase names are choosen to be consistent with microsofts winapi +// which implements CriticalSection by this naming... +// +// Author: Florian Wilkemeyer +// +// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// +// + +#ifdef WIN32 +#include "../common/winapi.h" +#endif + +#include "../common/cbasetypes.h" +#include "../common/atomic.h" +#include "../common/thread.h" + +#ifdef WIN32 + +typedef struct __declspec( align(64) ) SPIN_LOCK{ + volatile LONG lock; + volatile LONG nest; + volatile LONG sync_lock; +} SPIN_LOCK, *PSPIN_LOCK; +#else +typedef struct SPIN_LOCK{ + volatile int32 lock; + volatile int32 nest; // nesting level. + + volatile int32 sync_lock; +} __attribute__((aligned(64))) SPIN_LOCK, *PSPIN_LOCK; +#endif + + + +static forceinline void InitializeSpinLock(PSPIN_LOCK lck){ + lck->lock = 0; + lck->nest = 0; + lck->sync_lock = 0; +} + +static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){ + return; +} + + +#define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } } +#define dropsynclock(l) { InterlockedExchange(l, 0); } + +static forceinline void EnterSpinLock(PSPIN_LOCK lck){ + int tid = rathread_get_tid(); + + // Get Sync Lock && Check if the requester thread already owns the lock. + // if it owns, increase nesting level + getsynclock(&lck->sync_lock); + if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ + InterlockedIncrement(&lck->nest); + dropsynclock(&lck->sync_lock); + return; // Got Lock + } + // drop sync lock + dropsynclock(&lck->sync_lock); + + + // Spin until we've got it ! + while(1){ + + if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){ + + InterlockedIncrement(&lck->nest); + return; // Got Lock + } + + rathread_yield(); // Force ctxswitch to another thread. + } + +} + + +static forceinline void LeaveSpinLock(PSPIN_LOCK lck){ + int tid = rathread_get_tid(); + + getsynclock(&lck->sync_lock); + + if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock. + if(InterlockedDecrement(&lck->nest) == 0) + InterlockedExchange(&lck->lock, 0); // Unlock! + } + + dropsynclock(&lck->sync_lock); +} + + + + +#endif -- cgit v1.2.3-70-g09d2