123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 |
- // DiosLock.cpp : 定义 DLL 应用程序的导出函数。
- //
- #include "stdafx.h"
- #include <map>
- #include <vector>
- #include <assert.h>
- #include <tlhelp32.h>
- #include "DiosLock.h"
- using namespace std;
- #define MIN_CHECK_TIMEPERIOD (INFINITE)
- class _ProcLock {
- CRITICAL_SECTION m_Section;
- HANDLE m_ProcHandle;
- public:
- _ProcLock()
- {
- InitializeCriticalSectionAndSpinCount(&m_Section, 4000);//ms recommended number is 4000
- m_ProcHandle = CreateEvent(0, 0, 0, 0);
- };
- ~_ProcLock()
- {
- DeleteCriticalSection(&m_Section);
- CloseHandle(m_ProcHandle);
- };
- DWORD SetSpinWaitCount(DWORD waitcount)
- {
- return SetCriticalSectionSpinCount(&m_Section, waitcount);
- }
- DWORD Proc_Lock(DWORD timeout)
- {
- if (TryEnterCriticalSection(&m_Section) == FALSE)
- {
- if (timeout == 0)
- {
- return WAIT_TIMEOUT;
- }
- //failed get
- while (timeout > 0)
- {
- DWORD FirstHit = GetTickCount();
- DWORD ret = WaitForSingleObject(m_ProcHandle, timeout);
- if (ret == WAIT_OBJECT_0)
- {
- //try it again
- if (TryEnterCriticalSection(&m_Section))
- {
- return WAIT_OBJECT_0;
- }
- //failed get again
- DWORD Usedtime = GetTickCount() - FirstHit;
- if (Usedtime < timeout)
- {
- timeout -= Usedtime;
- }
- else
- {
- return WAIT_TIMEOUT;
- }
- }
- else
- {
- return ret;
- }
- }
- }
- ResetEvent(m_ProcHandle);
- return WAIT_OBJECT_0;
- }
- void Proc_UnLock()
- {
- LeaveCriticalSection(&m_Section);
- SetEvent(m_ProcHandle);
- }
- };
- _ProcLock g_m_ProcLock;
- DWORD Proc_Lock(DWORD timeout)
- {
- return g_m_ProcLock.Proc_Lock(timeout);
- }
- void Proc_UnLock()
- {
- return g_m_ProcLock.Proc_UnLock();
- }
- //TID ->vector<DiosLocks>
- volatile UINT64 g_csDiosLock = 0;//线程之间进行互锁
- //【Locked DiosLock】 maps 【ThreadID】
- //only one Thread Holds the Lock
- map<UINT64,DWORD> g_InternalLockedMap;
- map<UINT64, DiosLock*> g_InternalDiosObjectMap;
- void InitDiosLock()
- {
- //InitializeCriticalSection(&g_csDiosLock);
- }
- void DestroyDiosLock()
- {
- //DeleteCriticalSection(&g_csDiosLock);
- }
- void RegistDiosLock(DiosLock* p)
- {
- UINT64 val = (UINT64)p;
- Dios_ThreadLock(&g_csDiosLock);
- g_InternalDiosObjectMap[val] = p;
- Dios_ThreadUnLock(&g_csDiosLock);
- }
- void UnRegistDiosLock(DiosLock* p)
- {
- UINT64 val = (UINT64)p;
- Dios_ThreadLock(&g_csDiosLock);
- //clean up object map
- map<UINT64, DiosLock*>::iterator iter = g_InternalDiosObjectMap.find(val);
- if (iter != g_InternalDiosObjectMap.end())
- {
- g_InternalDiosObjectMap.erase(iter);
- }
- //clean up locked map
- map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(val);
- if (iter_locked != g_InternalLockedMap.end())
- {
- g_InternalLockedMap.erase(iter_locked);
- }
- Dios_ThreadUnLock(&g_csDiosLock);
- }
- void UnMapLockForThread(DiosLock *p)
- {
- UINT64 ID = (UINT64)p;
- Dios_ThreadLock(&g_csDiosLock);
- //find locked map
- map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(ID);
- #ifdef _DEBUG
- if (iter_locked == g_InternalLockedMap.end())
- {
- assert(0);//buggy
- }
- if (iter_locked->second != GetCurrentThreadId())
- {
- assert(0);//buggy
- }
- #endif
- if (iter_locked != g_InternalLockedMap.end())
- {
- //incase of exp...
- g_InternalLockedMap.erase(iter_locked);
- }
- Dios_ThreadUnLock(&g_csDiosLock);
- }
- void MapLockForThread(DiosLock *p)
- {
- UINT64 ID = (UINT64)p;
- Dios_ThreadLock(&g_csDiosLock);
- //find locked map
- #ifdef _DEBUG
- map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(ID);
- if (iter_locked != g_InternalLockedMap.end())
- {
- assert(0);//buggy
- }
- #endif
- g_InternalLockedMap[ID] = GetCurrentThreadId();
- Dios_ThreadUnLock(&g_csDiosLock);
- }
- void CleanupForThread(DWORD Tid)
- {
- /*
- try to unlock g_csDiosLock, if it's ThreadId matches.
- */
- Dios_ThreadClearForTid(&g_csDiosLock, Tid);//try clear g_cs...
- Dios_ThreadLock(&g_csDiosLock);
- //find locked map
- map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.begin();
- while (iter_locked != g_InternalLockedMap.end())
- {
- if (iter_locked->second == Tid)
- {
- //found one
- DiosLock* pLock = (DiosLock*)(iter_locked->first);
- //check existance of plock
- map<UINT64, DiosLock*>::iterator iter = g_InternalDiosObjectMap.find(iter_locked->first);
- if (iter != g_InternalDiosObjectMap.end())
- {
- //exist
- pLock->Thread_Clear(Tid);
- }
- else
- {
- //the pLock not exit
- }
- iter_locked = g_InternalLockedMap.erase(iter_locked);
- continue;
- }
- ++iter_locked;
- }
- //clear the lock for the thread
- Dios_ThreadUnLock(&g_csDiosLock);
- }
- DiosLock::DiosLock()
- {
- m_InterLock = 0;
- m_RefCount = 0;
- m_LockHandle = CreateEvent(0, 1, 1, 0);
- RegistDiosLock(this);
-
- return;
- }
- DiosLock::~DiosLock()
- {
- if ((m_InterLock) > 0)
- {
- //printf("Warning:ThreadId:%d is in Lock-----------\n", (m_InterLock));
- }
- UnRegistDiosLock(this);
- m_InterLock = 0;
- CloseHandle(m_LockHandle);
- return;
- }
- bool DiosLock::DiosInternal_EnterCriticalSection(DWORD TryCount)
- {
- if (TryCount == 0)
- {
- return false;
- }
-
- DWORD Tid = GetCurrentThreadId();
- //first try
- if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, 0) == 0)
- {
- ++m_RefCount;
- MapLockForThread(this);
- return true;
- }
- //check first
- if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
- {
- //already locked
- ++m_RefCount;
- return true;
- }
- //do loop
- while (TryCount > 1)
- {
- if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, 0) == 0)
- {
- ++m_RefCount;
- MapLockForThread(this);
- return true;
- }
- --TryCount;
- }
- return false;
- }
- void DiosLock::DiosInternal_LeaveCriticalSection()
- {
- DWORD Tid = GetCurrentThreadId();
- if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
- {
- //lock owner is right
- if (m_RefCount > 0)
- {
- --m_RefCount;
- if (m_RefCount > 0)
- {
- return;
- }
- //unmap first
- UnMapLockForThread(this);
- //clear second
- if (InterlockedCompareExchangeRelease(&m_InterLock, 0, Tid) == Tid)
- {
- return;
- }
- }
- }
- //ignore wrong unlocks
- }
- DWORD DiosLock::Thread_Lock(DWORD timeout)
- {
- //timeout == 0 优化
- if (timeout == 0)
- {
- if (DiosInternal_EnterCriticalSection(1) == FALSE)
- {
- return WAIT_TIMEOUT;
- }
- m_LockThreadId = GetCurrentThreadId();
- ResetEvent(m_LockHandle);
- return WAIT_OBJECT_0;
- }
- if (DiosInternal_EnterCriticalSection(800) == FALSE)
- {
- while (timeout > 0)
- {
- DWORD FirstHit = GetTickCount();
- //failed get
- DWORD ret = Thread_WaitUnlockNotify(timeout);
- if (ret == WAIT_OBJECT_0)
- {
- //try it again
- if (DiosInternal_EnterCriticalSection(800))
- {
- m_LockThreadId = GetCurrentThreadId();
- ResetEvent(m_LockHandle);
- return WAIT_OBJECT_0;
- }
- }
- //failed get again
- DWORD Usedtime = GetTickCount() - FirstHit;
- if (Usedtime < timeout)
- {
- timeout -= Usedtime;
- }
- else
- {
- return WAIT_TIMEOUT;
- }
- }
- }
- //ResetEvent(m_LockHandle);
- m_LockThreadId = GetCurrentThreadId();
- ResetEvent(m_LockHandle);
- return WAIT_OBJECT_0;
- }
- void DiosLock::Thread_UnLock()
- {
- DiosInternal_LeaveCriticalSection();
- if (m_RefCount == 0)
- {
- m_LockThreadId = 0;
- SetEvent(m_LockHandle);
- }
- }
- bool DiosLock::Thread_Clear(DWORD Tid)
- {
- if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
- {
- //lock owner is right
- //if (m_RefCount > 0)
- {
- m_RefCount = 0;
- if (InterlockedCompareExchangeRelease(&m_InterLock, 0, Tid) == Tid)
- {
- SetEvent(m_LockHandle);
- return true;
- }
- }
- }
- return false;
- //ignore wrong unlocks
- }
- DWORD DiosLock::Thread_WaitUnlockNotify(DWORD timeout)
- {
- while (timeout > 0)
- {
- DWORD FirstHit = GetTickCount();
- DWORD WaitPeriod = min(timeout, 1000);
- DWORD ret = WaitForSingleObject(m_LockHandle, WaitPeriod);
- if (ret == WAIT_OBJECT_0)
- {
- return WAIT_OBJECT_0;
- }
- //try clear once
- Try_Clear_DeadThread();
- //failed get again
- DWORD Usedtime = GetTickCount() - FirstHit;
- if (Usedtime < timeout)
- {
- timeout -= Usedtime;
- }
- else
- {
- return WAIT_TIMEOUT;
- }
- }
- return WAIT_TIMEOUT;
- }
- INT DiosLock::FindProcessThreads(DWORD dwOwnerTID)
- {
- INT ret = -1;
- DWORD dwOwnerPID = GetCurrentProcessId();
- HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
- THREADENTRY32 te32;
- // Take a snapshot of all running threads
- hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
- if (hThreadSnap == INVALID_HANDLE_VALUE)
- return (ret);
- // Fill in the size of the structure before using it.
- te32.dwSize = sizeof(THREADENTRY32);
- // Retrieve information about the first thread,
- // and exit if unsuccessful
- if (!Thread32First(hThreadSnap, &te32))
- {
- CloseHandle(hThreadSnap); // Must clean up the
- // snapshot object!
- return (ret);
- }
- // Now walk the thread list of the system,
- // and display information about each thread
- // associated with the specified process
- ret = 0;//set not found flag first
- do
- {
- if (te32.th32OwnerProcessID == dwOwnerPID && te32.th32ThreadID == dwOwnerTID)
- {
- //found it
- ret = 1;
- break;
- }
- } while (Thread32Next(hThreadSnap, &te32));
- // Don't forget to clean up the snapshot object.
- CloseHandle(hThreadSnap);
- return (ret);
- }
- bool DiosLock::Try_Clear_DeadThread()
- {
- DWORD Tid = m_InterLock;//just get it
- if (Tid == 0)
- {
- return true;
- }
- int FoundT = FindProcessThreads(Tid);
- if (FoundT == 0)
- {
- //目标不存在
- return Thread_Clear(Tid);
- }
- else if (FoundT > 0)
- {
- return false;
- }
- return false;
- }
- #pragma warning( push )
- #pragma warning( disable : 4114 )
- DIOSLOCK_C_API bool Dios_ThreadLock(volatile UINT64 volatile *pLock)
- {
- DWORD *pLockData = (DWORD*)pLock;
- DWORD *pRefCount = (DWORD*)&pLockData[1];
- DWORD Tid = GetCurrentThreadId();
- //first try
- if (InterlockedCompareExchangeAcquire(pLockData, Tid, 0) == 0)
- {
- ++(*pRefCount);
- return true;
- }
- //check first
- if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
- {
- //already locked
- ++(*pRefCount);
- return true;
- }
- //do loop
- while (1)
- {
- if (InterlockedCompareExchangeAcquire(pLockData, Tid, 0) == 0)
- {
- ++(*pRefCount);
- return true;
- }
- //check exist tid
- }
- return false;
- }
- DIOSLOCK_C_API void Dios_ThreadUnLock(volatile UINT64 volatile *pLock)
- {
- DWORD *pLockData = (DWORD*)pLock;
- DWORD *pRefCount = (DWORD*)&pLockData[1];
- DWORD Tid = GetCurrentThreadId();
- if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
- {
- //lock owner is right
- if ((*pRefCount) > 0)
- {
- --(*pRefCount);
- if ((*pRefCount) > 0)
- {
- return;
- }
- if (InterlockedCompareExchangeRelease(pLockData, 0, Tid) == Tid)
- {
- return;
- }
- }
- }
- //ignore wrong unlocks
- }
- DIOSLOCK_C_API void Dios_ThreadClearForTid(volatile UINT64 volatile *pLock,DWORD Tid)
- {
- DWORD *pLockData = (DWORD*)pLock;
- DWORD *pRefCount = (DWORD*)&pLockData[1];
- if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
- {
- (*pRefCount) = 0;
- if (InterlockedCompareExchangeRelease(pLockData, 0, Tid) == Tid)
- {
- return;
- }
- }
- //ignore wrong unlocks
- }
- #pragma warning( pop )
- DIOSLOCK_C_API DWORD Thread_GetUniqTick()
- {
- static volatile UINT64 g_IdxLock = 0;
- static volatile DWORD oldTick = 1;
- DWORD tick = 0;
- if (Dios_ThreadLock(&g_IdxLock))
- {
- if (oldTick == 0)
- {
- oldTick = 1;
- }
- tick = oldTick++;
- Dios_ThreadUnLock(&g_IdxLock);
- }
- return tick;
- }
|