From: <hv...@us...> - 2011-04-28 14:36:10
|
Revision: 52832 http://firebird.svn.sourceforge.net/firebird/?rev=52832&view=rev Author: hvlad Date: 2011-04-28 14:35:58 +0000 (Thu, 28 Apr 2011) Log Message: ----------- Preparing for the shared page cache : new sync objects ported from Vulcan Modified Paths: -------------- firebird/trunk/builds/win32/msvc10/common.vcxproj firebird/trunk/builds/win32/msvc10/common.vcxproj.filters firebird/trunk/builds/win32/msvc8/common.vcproj firebird/trunk/builds/win32/msvc9/common.vcproj firebird/trunk/src/common/ThreadStart.cpp firebird/trunk/src/common/classes/alloc.h firebird/trunk/src/common/classes/fb_atomic.h Added Paths: ----------- firebird/trunk/src/common/classes/SyncObject.cpp firebird/trunk/src/common/classes/SyncObject.h firebird/trunk/src/common/classes/Synchronize.cpp firebird/trunk/src/common/classes/Synchronize.h Modified: firebird/trunk/builds/win32/msvc10/common.vcxproj =================================================================== --- firebird/trunk/builds/win32/msvc10/common.vcxproj 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/builds/win32/msvc10/common.vcxproj 2011-04-28 14:35:58 UTC (rev 52832) @@ -35,6 +35,8 @@ <ClCompile Include="..\..\..\src\common\classes\SafeArg.cpp" /> <ClCompile Include="..\..\..\src\common\classes\semaphore.cpp" /> <ClCompile Include="..\..\..\src\common\classes\Switches.cpp" /> + <ClCompile Include="..\..\..\src\common\classes\Synchronize.cpp" /> + <ClCompile Include="..\..\..\src\common\classes\SyncObject.cpp" /> <ClCompile Include="..\..\..\src\common\classes\TempFile.cpp" /> <ClCompile Include="..\..\..\src\common\classes\timestamp.cpp" /> <ClCompile Include="..\..\..\src\common\classes\UserBlob.cpp" /> @@ -102,7 +104,6 @@ <ClInclude Include="..\..\..\src\common\classes\Hash.h" /> <ClInclude Include="..\..\..\src\common\classes\ImplementHelper.h" /> <ClInclude Include="..\..\..\src\common\classes\init.h" /> - <ClInclude Include="..\..\..\src\common\classes\Interface.h" /> <ClInclude Include="..\..\..\src\common\classes\Interlock.h" /> <ClInclude Include="..\..\..\src\common\classes\locks.h" /> <ClInclude Include="..\..\..\src\common\classes\MetaName.h" /> @@ -119,6 +120,8 @@ <ClInclude Include="..\..\..\src\common\classes\sparse_bitmap.h" /> <ClInclude Include="..\..\..\src\common\classes\stack.h" /> <ClInclude Include="..\..\..\src\common\classes\Switches.h" /> + <ClInclude Include="..\..\..\src\common\classes\Synchronize.h" /> + <ClInclude Include="..\..\..\src\common\classes\SyncObject.h" /> <ClInclude Include="..\..\..\src\common\classes\TempFile.h" /> <ClInclude Include="..\..\..\src\common\classes\timestamp.h" /> <ClInclude Include="..\..\..\src\common\classes\tree.h" /> Modified: firebird/trunk/builds/win32/msvc10/common.vcxproj.filters =================================================================== --- firebird/trunk/builds/win32/msvc10/common.vcxproj.filters 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/builds/win32/msvc10/common.vcxproj.filters 2011-04-28 14:35:58 UTC (rev 52832) @@ -186,6 +186,12 @@ <ClCompile Include="..\..\..\src\common\StatementMetadata.cpp"> <Filter>common</Filter> </ClCompile> + <ClCompile Include="..\..\..\src\common\classes\Synchronize.cpp"> + <Filter>common</Filter> + </ClCompile> + <ClCompile Include="..\..\..\src\common\classes\SyncObject.cpp"> + <Filter>common</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\src\common\xdr_proto.h"> @@ -365,9 +371,6 @@ <ClInclude Include="..\..\..\src\common\classes\init.h"> <Filter>headers</Filter> </ClInclude> - <ClInclude Include="..\..\..\src\common\classes\Interface.h"> - <Filter>headers</Filter> - </ClInclude> <ClInclude Include="..\..\..\src\common\classes\Interlock.h"> <Filter>headers</Filter> </ClInclude> @@ -482,5 +485,11 @@ <ClInclude Include="..\..\..\src\common\StatementMetadata.h"> <Filter>headers</Filter> </ClInclude> + <ClInclude Include="..\..\..\src\common\classes\SyncObject.h"> + <Filter>headers</Filter> + </ClInclude> + <ClInclude Include="..\..\..\src\common\classes\Synchronize.h"> + <Filter>headers</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file Modified: firebird/trunk/builds/win32/msvc8/common.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc8/common.vcproj 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/builds/win32/msvc8/common.vcproj 2011-04-28 14:35:58 UTC (rev 52832) @@ -281,7 +281,7 @@ </File> <File RelativePath="..\..\..\src\common\config\os\win32\config_root.cpp" - > + > </File> <File RelativePath="..\..\..\src\common\config\ConfigCache.cpp" @@ -317,7 +317,7 @@ </File> <File RelativePath="..\..\..\src\common\dllinst.cpp" - > + > </File> <File RelativePath="..\..\..\src\common\dsc.cpp" @@ -496,6 +496,14 @@ > </File> <File + RelativePath="..\..\..\src\common\classes\Synchronize.cpp" + > + </File> + <File + RelativePath="..\..\..\src\common\classes\SyncObject.cpp" + > + </File> + <File RelativePath="..\..\..\src\common\classes\TempFile.cpp" > </File> @@ -689,10 +697,6 @@ > </File> <File - RelativePath="..\..\..\src\common\classes\Interface.h" - > - </File> - <File RelativePath="..\..\..\src\common\classes\Interlock.h" > </File> @@ -845,6 +849,14 @@ > </File> <File + RelativePath="..\..\..\src\common\classes\Synchronize.h" + > + </File> + <File + RelativePath="..\..\..\src\common\classes\SyncObject.h" + > + </File> + <File RelativePath="..\..\..\src\common\classes\TempFile.h" > </File> Modified: firebird/trunk/builds/win32/msvc9/common.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc9/common.vcproj 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/builds/win32/msvc9/common.vcproj 2011-04-28 14:35:58 UTC (rev 52832) @@ -496,6 +496,14 @@ > </File> <File + RelativePath="..\..\..\src\common\classes\Synchronize.cpp" + > + </File> + <File + RelativePath="..\..\..\src\common\classes\SyncObject.cpp" + > + </File> + <File RelativePath="..\..\..\src\common\classes\TempFile.cpp" > </File> @@ -689,10 +697,6 @@ > </File> <File - RelativePath="..\..\..\src\common\classes\Interface.h" - > - </File> - <File RelativePath="..\..\..\src\common\classes\Interlock.h" > </File> @@ -845,6 +849,14 @@ > </File> <File + RelativePath="..\..\..\src\common\classes\Synchronize.h" + > + </File> + <File + RelativePath="..\..\..\src\common\classes\SyncObject.h" + > + </File> + <File RelativePath="..\..\..\src\common\classes\TempFile.h" > </File> Modified: firebird/trunk/src/common/ThreadStart.cpp =================================================================== --- firebird/trunk/src/common/ThreadStart.cpp 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/src/common/ThreadStart.cpp 2011-04-28 14:35:58 UTC (rev 52832) @@ -48,6 +48,7 @@ #include "../common/classes/locks.h" #include "../common/classes/rwlock.h" +#include "../common/classes/Synchronize.h" namespace @@ -57,6 +58,7 @@ THREAD_ENTRY_DECLARE threadStart(THREAD_ENTRY_PARAM arg) { fb_assert(arg); + Firebird::ThreadSync thread("threadStart"); MemoryPool::setContextPool(getDefaultMemoryPool()); { ThreadPriorityScheduler* tps = static_cast<ThreadPriorityScheduler*>(arg); @@ -107,6 +109,7 @@ THREAD_ENTRY_DECLARE threadStart(THREAD_ENTRY_PARAM arg) { fb_assert(arg); + Firebird::ThreadSync thread("threadStart"); MemoryPool::setContextPool(getDefaultMemoryPool()); ThreadArgs localArgs(*static_cast<ThreadArgs*>(arg)); delete static_cast<ThreadArgs*>(arg); Added: firebird/trunk/src/common/classes/SyncObject.cpp =================================================================== --- firebird/trunk/src/common/classes/SyncObject.cpp (rev 0) +++ firebird/trunk/src/common/classes/SyncObject.cpp 2011-04-28 14:35:58 UTC (rev 52832) @@ -0,0 +1,490 @@ +/* + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/idpl.html. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The contents of this file or any work derived from this file + * may not be distributed under any other license whatsoever + * without the express prior written permission of the original + * author. + * + * + * The Original Code was created by James A. Starkey for IBPhoenix. + * + * Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey + * Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc. + * All Rights Reserved. + * + * The \xD1ode was ported into Firebird Open Source RDBMS project by + * Vladyslav Khorsun at 2010 + * + * Contributor(s): + */ + +#include "../../common/common.h" +#include "../../common/gdsassert.h" +#include "fb_exception.h" + +#include "SyncObject.h" +#include "Synchronize.h" +#include "Interlock.h" + +namespace Firebird { + + +void SyncObject::lock(Sync *sync, LockType type) +{ + ThreadSync *thread = NULL; + + if (type == Shared) + { + //while (true) + while (waiters == 0) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState < 0) + break; + + const AtomicCounter::counter_type newState = oldState + 1; + if (lockState.compareExchange(oldState, newState)) + { + WAIT_FOR_FLUSH_CACHE + return; + } + } + + mutex.enter(); + ++waiters; + + //while (true) + while (waitingThreads == NULL) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState < 0) + break; + + const AtomicCounter::counter_type newState = oldState + 1; + if (lockState.compareExchange(oldState, newState)) + { + --waiters; + mutex.leave(); + return; + } + } + + thread = ThreadSync::findThread(); + fb_assert(thread); + } + else + { + thread = ThreadSync::findThread(); + fb_assert(thread); + + if (thread == exclusiveThread) + { + ++monitorCount; + return; + } + + while (waiters == 0) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState != 0) + break; + + if (lockState.compareExchange(oldState, -1)) + { + exclusiveThread = thread; + WAIT_FOR_FLUSH_CACHE + return; + } + } + + mutex.enter(); + ++waiters; + + while (waitingThreads == NULL) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState != 0) + break; + + if (lockState.compareExchange(oldState, -1)) + { + exclusiveThread = thread; + --waiters; + mutex.leave(); + return; + } + } + } + + wait(type, thread, sync); +} + +bool SyncObject::lockConditional(LockType type) +{ + if (waitingThreads) + return false; + + if (type == Shared) + { + while (true) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState < 0) + break; + + const AtomicCounter::counter_type newState = oldState + 1; + if (lockState.compareExchange(oldState, newState)) + { + WAIT_FOR_FLUSH_CACHE + return true; + } + } + + return false; + } + else + { + ThreadSync *thread = ThreadSync::findThread(); + fb_assert(thread); + + if (thread == exclusiveThread) + { + ++monitorCount; + return true; + } + + while (waiters == 0) + { + const AtomicCounter::counter_type oldState = lockState; + if (oldState != 0) + break; + + if (lockState.compareExchange(oldState, -1)) + { + WAIT_FOR_FLUSH_CACHE + exclusiveThread = thread; + return true; + } + } + + return false; + } +} + +void SyncObject::unlock(Sync *sync, LockType type) +{ + fb_assert((type == Shared && lockState > 0) || + (type == Exclusive && lockState == -1)); + + if (monitorCount) + { + fb_assert(monitorCount > 0); + --monitorCount; + return; + } + + while (true) + { + const AtomicCounter::counter_type oldState = lockState; + const AtomicCounter::counter_type newState = (type == Shared) ? oldState - 1 : 0; + exclusiveThread = NULL; + + FLUSH_CACHE + + if (lockState.compareExchange(oldState, newState)) + { + if (waiters) { + grantLocks(); + } + return; + } + } +} + +void SyncObject::unlock() +{ + if (lockState > 0) { + unlock(NULL, Shared); + } + else if (lockState == -1) { + unlock(NULL, Exclusive); + } + else { + fb_assert(false); + } +} + +void SyncObject::downGrade(LockType type) +{ + fb_assert(monitorCount == 0); + fb_assert(type == Shared); + fb_assert(lockState == -1); + fb_assert(exclusiveThread); + fb_assert(exclusiveThread == ThreadSync::findThread()); + + FLUSH_CACHE + + while (true) + { + if (lockState.compareExchange(-1, 1)) + { + if (waiters) { + grantLocks(); + } + return; + } + } +} + +void SyncObject::wait(LockType type, ThreadSync *thread, Sync *sync) +{ +/* + ThreadSync *volatile *ptr = &waitingThreads; + + for (; *ptr; ptr = &(*ptr)->nextWaiting) + { + if (*ptr == thread) + { + LOG_DEBUG ("Apparent single thread deadlock for thread %d (%x)\n", thread->threadId, thread); + //for (ThreadSync *thread = que; thread; thread = thread->que) + // thread->print(); + mutex.leave(); + fatal_exception::raise("single thread deadlock"); + } + } +*/ + if (thread->nextWaiting) + { + mutex.leave(); + fatal_exception::raise("single thread deadlock"); + } + + if (waitingThreads) + { + thread->prevWaiting = waitingThreads->prevWaiting; + thread->nextWaiting = waitingThreads; + + waitingThreads->prevWaiting->nextWaiting = thread; + waitingThreads->prevWaiting = thread; + } + else + { + thread->prevWaiting = thread->nextWaiting = thread; + waitingThreads = thread; + } + +// thread->nextWaiting = NULL; + thread->lockType = type; +// *ptr = thread; + thread->lockGranted = false; + thread->lockPending = sync; + mutex.leave(); + + while (!thread->lockGranted) + { + const bool wakeup = thread->sleep(10000); + if (thread->lockGranted) + break; + + if (!wakeup) + { + // stalled(thread); + break; + } + } + + while (!thread->lockGranted) + thread->sleep(); +} + + +/** +void SyncObject::grantLocks(void) +{ + mutex.enter(); + fb_assert((waiters && waitingThreads) || (!waiters && !waitingThreads)); + + ThreadSync *volatile *ptr = &waitingThreads; + ThreadSync *thread = *ptr; + while (thread = *ptr) + { + bool granted = false; + + if (thread->lockType == Shared) + { + AtomicCounter::counter_type oldState = lockState; + while (oldState >= 0) + { + const AtomicCounter::counter_type newState = oldState + 1; + if (lockState.compareExchange(oldState, newState)) + { + *ptr = thread->nextWaiting; + granted = true; + --waiters; + thread->grantLock(this); + break; + } + oldState = lockState; + } + } + else + { + while (lockState == 0) + { + if (lockState.compareExchange(0, -1)) + { + *ptr = thread->nextWaiting; + granted = true; + exclusiveThread = thread; + --waiters; + thread->grantLock(this); + break; + } + } + } + + if (!granted) { + break; + ptr = &thread->nextWaiting; + } + } + + mutex.leave(); +} +**/ + +ThreadSync* SyncObject::grantThread(ThreadSync *thread) +{ + ThreadSync* next = NULL; + if (thread == thread->nextWaiting) + { + thread->nextWaiting = thread->prevWaiting = NULL; + waitingThreads = NULL; + } + else + { + next = thread->nextWaiting; + + thread->prevWaiting->nextWaiting = next; + next->prevWaiting = thread->prevWaiting; + + thread->nextWaiting = thread->prevWaiting = NULL; + if (waitingThreads == thread) + waitingThreads = next; + } + + --waiters; + thread->grantLock(this); + return next; +} + +void SyncObject::grantLocks(void) +{ + mutex.enter(); + fb_assert((waiters && waitingThreads) || (!waiters && !waitingThreads)); + + ThreadSync *thread = waitingThreads; + while (thread) + { + bool granted = false; + + if (thread->lockType == Shared) + { + AtomicCounter::counter_type oldState = lockState; + while (oldState >= 0) + { + const AtomicCounter::counter_type newState = oldState + 1; + if (lockState.compareExchange(oldState, newState)) + { + granted = true; + thread = grantThread(thread); + break; + } + oldState = lockState; + } + } + else + { + while (lockState == 0) + { + if (lockState.compareExchange(0, -1)) + { + granted = true; + exclusiveThread = thread; + thread = grantThread(thread); + break; + } + } + } + + if (!granted) { + break; + //thread = thread->nextWaiting; + //if (thread == waitingThreads) + // break; + } + } + + mutex.leave(); +} + + +void SyncObject::validate(LockType lockType) +{ + switch (lockType) + { + case None: + fb_assert(lockState == 0); + break; + + case Shared: + fb_assert(lockState > 0); + break; + + case Exclusive: + fb_assert(lockState == -1); + break; + } +} + + +bool SyncObject::ourExclusiveLock(void) const +{ + if (lockState != -1) + return false; + +// fb_assert(exclusiveThread); + return (exclusiveThread == ThreadSync::findThread()); +} + +/** +void SyncObject::sysServiceFailed(const char* service, int code) +{ + throw OSRIException (isc_sys_request, + isc_arg_string, service, + SYS_ARG, code, + isc_arg_end); +} + +void SyncObject::assertionFailed(void) +{ + throw OSRIException (isc_sys_request, + isc_arg_string, "SyncObject assertion failed", + SYS_ARG, lockState, + isc_arg_end); +} +**/ + + +} // namespace Firebird Property changes on: firebird/trunk/src/common/classes/SyncObject.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: firebird/trunk/src/common/classes/SyncObject.h =================================================================== --- firebird/trunk/src/common/classes/SyncObject.h (rev 0) +++ firebird/trunk/src/common/classes/SyncObject.h 2011-04-28 14:35:58 UTC (rev 52832) @@ -0,0 +1,478 @@ +/* + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/idpl.html. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The contents of this file or any work derived from this file + * may not be distributed under any other license whatsoever + * without the express prior written permission of the original + * author. + * + * + * The Original Code was created by James A. Starkey for IBPhoenix. + * + * Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey + * Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc. + * All Rights Reserved. + * + * The \xD1ode was ported into Firebird Open Source RDBMS project by + * Vladyslav Khorsun at 2010 + * + * Contributor(s): + */ + +#ifndef CLASSES_SYNCOBJECT_H +#define CLASSES_SYNCOBJECT_H + +#include "../../common/classes/fb_atomic.h" +#include "../../common/classes/locks.h" + +namespace Firebird { + +#define LOG_DEBUG +#define ASSERT fb_assert + +enum LockType { + None, + Exclusive, + Shared, + Invalid +}; + +class Sync; +class ThreadSync; + +class SynchronizationObject +{ +public: + virtual void lock(Sync *sync, LockType type) = 0; + virtual void unlock(Sync *sync, LockType type) = 0; + virtual void downGrade(LockType type) = 0; +}; + +class SyncObject : public SynchronizationObject +{ +public: + SyncObject() + { + waiters = 0; + monitorCount = 0; + exclusiveThread = NULL; + waitingThreads = NULL; + } + + virtual ~SyncObject() + {} + + virtual void lock(Sync *sync, LockType type); + bool lockConditional(LockType type); + + virtual void unlock(Sync *sync, LockType type); + void unlock(void); + + virtual void downGrade(LockType type); + + LockType getState(void) const + { + if (lockState.value() == 0) + return None; + + if (lockState.value() < 0) + return Exclusive; + + return Shared; + } + + bool isLocked() const + { + return lockState.value() != 0; + } + + bool hasContention() const + { + return (waiters.value() > 0); + } + + bool ourExclusiveLock(void) const; + + void sysServiceFailed(const char* service, int code); + void assertionFailed(void); + +protected: + void wait(LockType type, ThreadSync *thread, Sync *sync); + ThreadSync* grantThread(ThreadSync *thread); + void grantLocks(void); + void validate(LockType lockType); + + AtomicCounter lockState; + AtomicCounter waiters; + //int waiters; + int monitorCount; + Mutex mutex; + ThreadSync *volatile exclusiveThread; + ThreadSync *volatile waitingThreads; +}; + + +class Sync +{ +public: + Sync(SynchronizationObject *obj, const char *fromWhere) + { + ASSERT(obj); + syncObject = obj; + prior = NULL; + where = fromWhere; + state = request = None; + } + + ~Sync() + { + ASSERT(state != Invalid); + + if (syncObject && state != None) + { + syncObject->unlock(this, state); + state = Invalid; + } + } + + void lock(LockType type) + { + request = type; + syncObject->lock(this, type); + state = type; + } + + void lock(LockType type, const char *fromWhere) + { + where = fromWhere; + lock(type); + } + + void unlock() + { + ASSERT(state != None); + syncObject->unlock(this, state); + state = None; + } + + void downGrade(LockType type) + { + ASSERT(state == Exclusive); + syncObject->downGrade(type); + state = Shared; + } + + void setObject(SynchronizationObject *obj) + { + if (syncObject && state != None) + syncObject->unlock(this, state); + + state = None; + syncObject = obj; + } + + +protected: + LockType state; + LockType request; + SynchronizationObject *syncObject; + Sync *prior; // not used + const char *where; + +friend class ThreadSync; +}; + + +class SyncLockGuard : public Sync +{ +public: + SyncLockGuard(SynchronizationObject *obj, LockType type, const char *fromWhere) : + Sync(obj, fromWhere) + { + lock(type); + } + + ~SyncLockGuard() + { + //ASSERT(state != None); + if (state != None) + unlock(); + } +}; + +class SyncUnlockGuard : public Sync +{ +public: + SyncUnlockGuard(SynchronizationObject *obj, const char *fromWhere) : + Sync(obj, fromWhere) + { + oldState = state; + + ASSERT(oldState != None); + if (oldState != None) + unlock(); + } + + ~SyncUnlockGuard() + { + if (oldState != None) + lock(oldState); + } + +private: + LockType oldState; +}; + +} // namespace Firebird + +#endif // CLASSES_SYNCOBJECT_H + +/* + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/idpl.html. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The contents of this file or any work derived from this file + * may not be distributed under any other license whatsoever + * without the express prior written permission of the original + * author. + * + * + * The Original Code was created by James A. Starkey for IBPhoenix. + * + * Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey + * Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc. + * All Rights Reserved. + * + * The \xD1ode was ported into Firebird Open Source RDBMS project by + * Vladyslav Khorsun at 2010 + * + * Contributor(s): + */ + +#ifndef CLASSES_SYNCOBJECT_H +#define CLASSES_SYNCOBJECT_H + +#include "../../common/classes/fb_atomic.h" +#include "../../common/classes/locks.h" + +namespace Firebird { + +#define LOG_DEBUG +#define ASSERT fb_assert + +enum LockType { + None, + Exclusive, + Shared, + Invalid +}; + +class Sync; +class ThreadSync; + +class SynchronizationObject +{ +public: + virtual void lock(Sync *sync, LockType type) = 0; + virtual void unlock(Sync *sync, LockType type) = 0; + virtual void downGrade(LockType type) = 0; +}; + +class SyncObject : public SynchronizationObject +{ +public: + SyncObject() + { + waiters = 0; + monitorCount = 0; + exclusiveThread = NULL; + waitingThreads = NULL; + } + + virtual ~SyncObject() + {} + + virtual void lock(Sync *sync, LockType type); + bool lockConditional(LockType type); + + virtual void unlock(Sync *sync, LockType type); + void unlock(void); + + virtual void downGrade(LockType type); + + LockType getState(void) const + { + if (lockState.value() == 0) + return None; + + if (lockState.value() < 0) + return Exclusive; + + return Shared; + } + + bool isLocked() const + { + return lockState.value() != 0; + } + + bool hasContention() const + { + return (waiters.value() > 0); + } + + bool ourExclusiveLock(void) const; + + void sysServiceFailed(const char* service, int code); + void assertionFailed(void); + +protected: + void wait(LockType type, ThreadSync *thread, Sync *sync); + ThreadSync* grantThread(ThreadSync *thread); + void grantLocks(void); + void validate(LockType lockType); + + AtomicCounter lockState; + AtomicCounter waiters; + //int waiters; + int monitorCount; + Mutex mutex; + ThreadSync *volatile exclusiveThread; + ThreadSync *volatile waitingThreads; +}; + + +class Sync +{ +public: + Sync(SynchronizationObject *obj, const char *fromWhere) + { + ASSERT(obj); + syncObject = obj; + prior = NULL; + where = fromWhere; + state = request = None; + } + + ~Sync() + { + ASSERT(state != Invalid); + + if (syncObject && state != None) + { + syncObject->unlock(this, state); + state = Invalid; + } + } + + void lock(LockType type) + { + request = type; + syncObject->lock(this, type); + state = type; + } + + void lock(LockType type, const char *fromWhere) + { + where = fromWhere; + lock(type); + } + + void unlock() + { + ASSERT(state != None); + syncObject->unlock(this, state); + state = None; + } + + void downGrade(LockType type) + { + ASSERT(state == Exclusive); + syncObject->downGrade(type); + state = Shared; + } + + void setObject(SynchronizationObject *obj) + { + if (syncObject && state != None) + syncObject->unlock(this, state); + + state = None; + syncObject = obj; + } + + +protected: + LockType state; + LockType request; + SynchronizationObject *syncObject; + Sync *prior; // not used + const char *where; + +friend class ThreadSync; +}; + + +class SyncLockGuard : public Sync +{ +public: + SyncLockGuard(SynchronizationObject *obj, LockType type, const char *fromWhere) : + Sync(obj, fromWhere) + { + lock(type); + } + + ~SyncLockGuard() + { + //ASSERT(state != None); + if (state != None) + unlock(); + } +}; + +class SyncUnlockGuard : public Sync +{ +public: + SyncUnlockGuard(SynchronizationObject *obj, const char *fromWhere) : + Sync(obj, fromWhere) + { + oldState = state; + + ASSERT(oldState != None); + if (oldState != None) + unlock(); + } + + ~SyncUnlockGuard() + { + if (oldState != None) + lock(oldState); + } + +private: + LockType oldState; +}; + +} // namespace Firebird + +#endif // CLASSES_SYNCOBJECT_H + Property changes on: firebird/trunk/src/common/classes/SyncObject.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: firebird/trunk/src/common/classes/Synchronize.cpp =================================================================== --- firebird/trunk/src/common/classes/Synchronize.cpp (rev 0) +++ firebird/trunk/src/common/classes/Synchronize.cpp 2011-04-28 14:35:58 UTC (rev 52832) @@ -0,0 +1,327 @@ +/* +* +* The contents of this file are subject to the Initial +* Developer's Public License Version 1.0 (the "License"); +* you may not use this file except in compliance with the +* License. You may obtain a copy of the License at +* http://www.ibphoenix.com/idpl.html. +* +* Software distributed under the License is distributed on +* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either +* express or implied. See the License for the specific +* language governing rights and limitations under the License. +* +* The contents of this file or any work derived from this file +* may not be distributed under any other license whatsoever +* without the express prior written permission of the original +* author. +* +* +* The Original Code was created by James A. Starkey for IBPhoenix. +* +* Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey +* Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc. +* All Rights Reserved. +* +* The \xD1ode was ported into Firebird Open Source RDBMS project by +* Vladyslav Khorsun at 2010 +* +* Contributor(s): +*/ + +#include "../../common/common.h" +#include "fb_tls.h" +#include "../thd.h" + +#include "SyncObject.h" +#include "Synchronize.h" + +#define NANO 1000000000 +#define MICRO 1000000 + +namespace Firebird { + +Synchronize::Synchronize() +{ + shutdownInProgress = false; + sleeping = false; + wakeup = false; + +#ifdef _WIN32 + evnt = CreateEvent(NULL, false, false, NULL); +#endif + +#ifdef _PTHREADS + int ret = pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&condition, NULL); +#endif + +#ifdef SOLARIS_MT + int ret = mutex_init(&mutex, USYNC_THREAD, NULL); + cond_init(&condition, USYNC_THREAD, NULL); +#endif +} + +Synchronize::~Synchronize() +{ +#ifdef _WIN32 + CloseHandle(evnt); +#endif + +#ifdef _PTHREADS + int ret = pthread_mutex_destroy(&mutex); + ret = pthread_cond_destroy(&condition); +#endif + +#ifdef SOLARIS_MT + int ret = mutex_destroy(&mutex); +#endif +} + + +void Synchronize::sleep() +{ + sleeping = true; +#ifdef _WIN32 +#ifdef _DEBUG + for (;;) + { + const int n = WaitForSingleObject(evnt, 10000); + if (n != WAIT_TIMEOUT) + break; + } +#else + sleep (INFINITE); +#endif +#endif + +#ifdef _PTHREADS + int ret = pthread_mutex_lock(&mutex); + CHECK_RET("pthread_mutex_lock failed, errno %d", errno); + + while (!wakeup) + pthread_cond_wait(&condition, &mutex); + + wakeup = false; + ret = pthread_mutex_unlock(&mutex); + CHECK_RET("pthread_mutex_unlock failed, errno %d", errno); +#endif + +#ifdef SOLARIS_MT + int ret = mutex_lock(&mutex); + CHECK_RET("mutex_lock failed, errno %d", errno); + + while (!wakeup) + cond_wait(&condition, &mutex); + + wakeup = false; + ret = mutex_unlock(&mutex); + CHECK_RET("mutex_unlock failed, errno %d", errno); +#endif + + sleeping = false; +} + +bool Synchronize::sleep(int milliseconds) +{ + sleeping = true; + +#ifdef _WIN32 + const int n = WaitForSingleObject(evnt, milliseconds); + sleeping = false; + + return n != WAIT_TIMEOUT; +#endif + +#ifdef _PTHREADS + struct timeval microTime; + int ret = gettimeofday(µTime, NULL); + SINT64 nanos = (SINT64) microTime.tv_sec * NANO + microTime.tv_usec * 1000 + + (SINT64) milliseconds * 1000000; + struct timespec nanoTime; + nanoTime.tv_sec = nanos / NANO; + nanoTime.tv_nsec = nanos % NANO; + ret = pthread_mutex_lock (&mutex); + CHECK_RET("pthread_mutex_lock failed, errno %d", errno); + int seconds = nanoTime.tv_sec - microTime.tv_sec; + + while (!wakeup) + { +#ifdef MVS + ret = pthread_cond_timedwait(&condition, &mutex, &nanoTime); + if (ret == -1 && errno == EAGAIN) + ret = ETIMEDOUT; + break; +#else + ret = pthread_cond_timedwait(&condition, &mutex, &nanoTime); + if (ret == ETIMEDOUT) + break; +#endif + /*** + if (!wakeup) + Log::debug ("Synchronize::sleep(milliseconds): unexpected wakeup, ret %d\n", ret); + ***/ + } + + sleeping = false; + wakeup = false; + pthread_mutex_unlock(&mutex); + return ret != ETIMEDOUT; +#endif + +#ifdef SOLARIS_MT + struct timeval microTime; + int ret = gettimeofday(µTime, NULL); + SINT64 nanos = (SINT64) microTime.tv_sec * NANO + microTime.tv_usec * 1000 + + (SINT64) milliseconds * 1000000; + struct timespec nanoTime; + nanoTime.tv_sec = nanos / NANO; + nanoTime.tv_nsec = nanos % NANO; + ret = mutex_lock (&mutex); + CHECK_RET("mutex_lock failed, errno %d", errno); + int seconds = nanoTime.tv_sec - microTime.tv_sec; + + while (!wakeup) + { + ret = cond_timedwait(&condition, &mutex, &nanoTime); + if (ret == ETIMEDOUT) + break; + /*** + if (!wakeup) + Log::debug ("Synchronize::sleep(milliseconds): unexpected wakeup, ret %d\n", ret); + ***/ + } + + sleeping = false; + wakeup = false; + mutex_unlock(&mutex); + + return ret != ETIMEDOUT; +#endif +} + +void Synchronize::wake() +{ +#ifdef _WIN32 + SetEvent (evnt); +#endif + +#ifdef _PTHREADS + int ret = pthread_mutex_lock(&mutex); + CHECK_RET("pthread_mutex_lock failed, errno %d", errno); + wakeup = true; + pthread_cond_broadcast(&condition); + ret = pthread_mutex_unlock(&mutex); + CHECK_RET("pthread_mutex_unlock failed, errno %d", errno); +#endif + +#ifdef SOLARIS_MT + int ret = mutex_lock(&mutex); + CHECK_RET("mutex_lock failed, errno %d", errno); + wakeup = true; + cond_broadcast(&condition); + ret = mutex_unlock(&mutex); + CHECK_RET("mutex_unlock failed, errno %d", errno); +#endif +} + +void Synchronize::shutdown() +{ + shutdownInProgress = true; + wake(); +} + + + +/// ThreadSync + +TLS_DECLARE (ThreadSync*, threadIndex); + +ThreadSync::ThreadSync(const char *desc) +{ + init(desc); + setThread(this); +} + +void ThreadSync::init(const char *desc) +{ + description = desc; + threadId = getCurrentThreadId(); + prevWaiting = nextWaiting = NULL; + lockType = None; + lockGranted = false; + lockPending = NULL; + locks = NULL; +} + +ThreadSync::~ThreadSync() +{ + setThread (NULL); +} + + +ThreadSync* ThreadSync::findThread() +{ + return TLS_GET(threadIndex); +} + + +ThreadSync* ThreadSync::getThread(const char *desc) +{ + ThreadSync *thread = findThread(); + + if (!thread) + { + thread = new ThreadSync (desc); + setThread(thread); + } + + return thread; +} + +void ThreadSync::setThread(ThreadSync *thread) +{ + TLS_SET(threadIndex, thread); +} + +FB_THREAD_ID ThreadSync::getCurrentThreadId(void) +{ + return getThreadId(); +} + + +const char* ThreadSync::getWhere() +{ + if (lockPending && lockPending->where) + return lockPending->where; + + return ""; +} + + +void ThreadSync::validateLocks() +{ + ThreadSync *thread = getThread("ThreadSync::validateLocks"); + + // hvlad: not worked + if (thread->locks) + { + LOG_DEBUG ("thread %d has active locks:\n", thread->threadId); + for (Sync *sync = thread->locks; sync; sync = sync->prior) + LOG_DEBUG (" %s\n", sync->where); + } +} + + +void ThreadSync::grantLock(SyncObject *lock) +{ + ASSERT(!lockGranted); + ASSERT(!lockPending || lockPending->syncObject == lock); + + lockGranted = true; + lockPending = NULL; + + wake(); +} + +} // namespace Firebird Property changes on: firebird/trunk/src/common/classes/Synchronize.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: firebird/trunk/src/common/classes/Synchronize.h =================================================================== --- firebird/trunk/src/common/classes/Synchronize.h (rev 0) +++ firebird/trunk/src/common/classes/Synchronize.h 2011-04-28 14:35:58 UTC (rev 52832) @@ -0,0 +1,111 @@ +/* + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/idpl.html. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The contents of this file or any work derived from this file + * may not be distributed under any other license whatsoever + * without the express prior written permission of the original + * author. + * + * + * The Original Code was created by James A. Starkey for IBPhoenix. + * + * Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey + * Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc. + * All Rights Reserved. + * + * The \xD1ode was ported into Firebird Open Source RDBMS project by + * Vladyslav Khorsun at 2010 + * + * Contributor(s): + */ + +#ifndef CLASSES_SYNCHRONIZE_H +#define CLASSES_SYNCHRONIZE_H + +#include "../../common/common.h" +#include "../../common/classes/SyncObject.h" + + +namespace Firebird { + +class Synchronize +{ +public: + Synchronize(); + virtual ~Synchronize(); + + virtual void shutdown(); + void wake(); + bool sleep(int milliseconds); + void sleep(); + +protected: + bool shutdownInProgress; + bool sleeping; + volatile bool wakeup; + SINT64 waitTime; + +#ifdef _WIN32 + void *evnt; +#endif + +#ifdef _PTHREADS + pthread_cond_t condition; + pthread_mutex_t mutex; +#endif + +#ifdef SOLARIS_MT + cond_t condition; + mutex_t mutex; +#endif +}; + + +class Sync; +class SyncObject; + +class ThreadSync : public Synchronize +{ +public: + ThreadSync(const char *desc); + virtual ~ThreadSync(); + + void init(const char *description); + + static ThreadSync* findThread(); + static ThreadSync* getThread(const char *desc); + static FB_THREAD_ID getCurrentThreadId(void); + + const char* getWhere(); + + static void validateLocks(); + void grantLock(SyncObject *lock); + + FB_THREAD_ID threadId; + ThreadSync *nextWaiting; // next thread in sleep que (see SyncObject) + ThreadSync *prevWaiting; // previous thread in sleep que (see SyncObject) + LockType lockType; // requested lock type (see SyncObject) + volatile bool lockGranted; + Sync *lockPending; + Sync *locks; + const char *description; + +protected: + static void setThread (ThreadSync *thread); +}; + + +} // namespace Firebird + +#endif // CLASSES_SYNCHRONIZE_H + Property changes on: firebird/trunk/src/common/classes/Synchronize.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Modified: firebird/trunk/src/common/classes/alloc.h =================================================================== --- firebird/trunk/src/common/classes/alloc.h 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/src/common/classes/alloc.h 2011-04-28 14:35:58 UTC (rev 52832) @@ -130,7 +130,7 @@ { for (MemoryStats* statistics = this; statistics; statistics = statistics->mst_parent) { - const size_t temp = statistics->mst_usage += size; + const size_t temp = statistics->mst_usage.exchangeAdd(size) + size; if (temp > statistics->mst_max_usage) statistics->mst_max_usage = temp; } @@ -148,7 +148,7 @@ { for (MemoryStats* statistics = this; statistics; statistics = statistics->mst_parent) { - const size_t temp = statistics->mst_mapped += size; + const size_t temp = statistics->mst_mapped.exchangeAdd(size) + size; if (temp > statistics->mst_max_mapped) statistics->mst_max_mapped = temp; } Modified: firebird/trunk/src/common/classes/fb_atomic.h =================================================================== --- firebird/trunk/src/common/classes/fb_atomic.h 2011-04-28 03:16:44 UTC (rev 52831) +++ firebird/trunk/src/common/classes/fb_atomic.h 2011-04-28 14:35:58 UTC (rev 52832) @@ -35,9 +35,23 @@ typedef SLONG AtomicType; #endif +// IMPORTANT ! +// Most of the interlocked functions returns "old" value of operand (except of +// InterlockedIncrement and InterlockedDecrement on Windows) and this is correct +// as "old" value impossible to restore from "new" value and operation parameters +// and "new" value could be changed at time when code looks at it. +// This (returning of original value) is not how operators such as "=", "+=", +// "&=" etc, usually works. Therefore overloaded operators in AtomicCounter class +// are void and all of them have corresponding equivalent functions returning +// "old" value of operand. +// The only exceptions from this rule is unary increment and decrement (for +// historical reasons). Use it with care ! If one need old value of just +// incremented atomic variable he should use exchangeAdd, not operator++. + #if defined(WIN_NT) #include <windows.h> +#include <intrin.h> namespace Firebird { @@ -55,60 +69,165 @@ explicit AtomicCounter(counter_type val = 0) : counter(val) {} ~AtomicCounter() {} + // returns old value counter_type exchangeAdd(counter_type val) { #ifdef _WIN64 - return InterlockedExchangeAdd64(&counter, val); + return _InterlockedExchangeAdd64(&counter, val); #else - return InterlockedExchangeAdd(&counter, val); + return _InterlockedExchangeAdd(&counter, val); #endif } - counter_type operator +=(counter_type val) + bool compareExchange(counter_type oldVal, counter_type newVal) { - return exchangeAdd(val) + val; +#ifdef _WIN64 + return (_InterlockedCompareExchange64(&counter, newVal, oldVal) == oldVal); +#else + return (_InterlockedCompareExchange(&counter, newVal, oldVal) == oldVal); +#endif } - counter_type operator -=(counter_type val) + void setValue(counter_type val) { - return exchangeAdd(-val) - val; +#ifdef _WIN64 + _InterlockedExchange64(&counter, val); +#else + _InterlockedExchange(&counter, val); +#endif } +// platform-independent code + + counter_type value() const { return counter; } + + // returns old value + counter_type exchangeBitAnd(counter_type val) + { + while (true) + { + volatile counter_type oldVal = counter; + + if (compareExchange(oldVal, oldVal & val)) + return oldVal; + } + } + + // returns old value + counter_type exchangeBitOr(counter_type val) + { + while (true) + { + volatile counter_type oldVal = counter; + + if (compareExchange(oldVal, oldVal | val)) + return oldVal; + } + } + + + // returns old value + counter_type exchangeGreater(counter_type val) + { + while (true) + { + volatile counter_type oldVal = counter; + + if (oldVal >= val) + return oldVal; + + if (compareExchange(oldVal, val)) + return oldVal; + } + } + + operator counter_type () const + { + return value(); + } + + void operator =(counter_type val) + { + setValue(val); + } + + // returns new value ! counter_type operator ++() { -#ifdef _WIN64 - return InterlockedIncrement64(&counter); -#else - return InterlockedIncrement(&counter); -#endif + return exchangeAdd(1) + 1; } + // returns new value ! counter_type operator --() { + return exchangeAdd(-1) - 1; + } + + void operator +=(counter_type val) + { + exchangeAdd(val); + } + + void operator -=(counter_type val) + { + exchangeAdd(-val); + } + + void operator &=(counter_type val) + { + exchangeBitAnd(val); + } + + void operator |=(counter_type val) + { + exchangeBitOr(val); + } + +private: +#if defined(MINGW) + counter_type counter; +#else + volatile counter_type counter; +#endif +}; + + + +template <typename T> +class AtomicPointer +{ +public: + explicit AtomicPointer(T* val = NULL) : pointer(val) {} + ~AtomicPointer() {} + + T* value() const { return (T*)pointer; } + + void setValue(T* val) + { #ifdef _WIN64 - return InterlockedDecrement64(&counter); + _InterlockedExchangePointer((volatile PVOID*)&pointer, val); #else - return InterlockedDecrement(&counter); + //InterlockedExchangePointer((volatile PVOID*)&pointer, val); + _InterlockedExchange((LONG volatile*)&pointer, (LONG)val); #endif } - counter_type value() const { return counter; } - - counter_type setValue(counter_type val) + bool compareExchange(T* oldVal, T* newVal) { #ifdef _WIN64 - return InterlockedExchange64(&counter, val); + return (_InterlockedCompareExchangePointer((PVOID volatile*)&pointer, newVal, oldVal) == oldVal); #else - return InterlockedExchange(&counter, val); + //return (InterlockedCompareExchangePointer((PVOID volatile*)&pointer, newVal, oldVal) == oldVal); + return ((PVOID)(LONG_PTR)_InterlockedCompareExchange((LONG volatile*)&pointer, (LONG)newVal, (LONG)oldVal)) == oldVal; #endif } + operator T* () const { return value(); } + T* operator ->() const { return value(); } + void operator =(T* val) { setValue(val); } + private: -# if defined(MINGW) - counter_type counter; -# else - volatile counter_type counter; -# endif + volatile T* pointer; }; } // namespace Firebird This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |