DiosLock.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. // DiosLock.cpp : 定义 DLL 应用程序的导出函数。
  2. //
  3. #include "stdafx.h"
  4. #include <map>
  5. #include <vector>
  6. #include <assert.h>
  7. #include <tlhelp32.h>
  8. #include "DiosLock.h"
  9. using namespace std;
  10. #define MIN_CHECK_TIMEPERIOD (INFINITE)
  11. class _ProcLock {
  12. CRITICAL_SECTION m_Section;
  13. HANDLE m_ProcHandle;
  14. public:
  15. _ProcLock()
  16. {
  17. InitializeCriticalSectionAndSpinCount(&m_Section, 4000);//ms recommended number is 4000
  18. m_ProcHandle = CreateEvent(0, 0, 0, 0);
  19. };
  20. ~_ProcLock()
  21. {
  22. DeleteCriticalSection(&m_Section);
  23. CloseHandle(m_ProcHandle);
  24. };
  25. DWORD SetSpinWaitCount(DWORD waitcount)
  26. {
  27. return SetCriticalSectionSpinCount(&m_Section, waitcount);
  28. }
  29. DWORD Proc_Lock(DWORD timeout)
  30. {
  31. if (TryEnterCriticalSection(&m_Section) == FALSE)
  32. {
  33. if (timeout == 0)
  34. {
  35. return WAIT_TIMEOUT;
  36. }
  37. //failed get
  38. while (timeout > 0)
  39. {
  40. DWORD FirstHit = GetTickCount();
  41. DWORD ret = WaitForSingleObject(m_ProcHandle, timeout);
  42. if (ret == WAIT_OBJECT_0)
  43. {
  44. //try it again
  45. if (TryEnterCriticalSection(&m_Section))
  46. {
  47. return WAIT_OBJECT_0;
  48. }
  49. //failed get again
  50. DWORD Usedtime = GetTickCount() - FirstHit;
  51. if (Usedtime < timeout)
  52. {
  53. timeout -= Usedtime;
  54. }
  55. else
  56. {
  57. return WAIT_TIMEOUT;
  58. }
  59. }
  60. else
  61. {
  62. return ret;
  63. }
  64. }
  65. }
  66. ResetEvent(m_ProcHandle);
  67. return WAIT_OBJECT_0;
  68. }
  69. void Proc_UnLock()
  70. {
  71. LeaveCriticalSection(&m_Section);
  72. SetEvent(m_ProcHandle);
  73. }
  74. };
  75. _ProcLock g_m_ProcLock;
  76. DWORD Proc_Lock(DWORD timeout)
  77. {
  78. return g_m_ProcLock.Proc_Lock(timeout);
  79. }
  80. void Proc_UnLock()
  81. {
  82. return g_m_ProcLock.Proc_UnLock();
  83. }
  84. //TID ->vector<DiosLocks>
  85. volatile UINT64 g_csDiosLock = 0;//线程之间进行互锁
  86. //【Locked DiosLock】 maps 【ThreadID】
  87. //only one Thread Holds the Lock
  88. map<UINT64,DWORD> g_InternalLockedMap;
  89. map<UINT64, DiosLock*> g_InternalDiosObjectMap;
  90. void InitDiosLock()
  91. {
  92. //InitializeCriticalSection(&g_csDiosLock);
  93. }
  94. void DestroyDiosLock()
  95. {
  96. //DeleteCriticalSection(&g_csDiosLock);
  97. }
  98. void RegistDiosLock(DiosLock* p)
  99. {
  100. UINT64 val = (UINT64)p;
  101. Dios_ThreadLock(&g_csDiosLock);
  102. g_InternalDiosObjectMap[val] = p;
  103. Dios_ThreadUnLock(&g_csDiosLock);
  104. }
  105. void UnRegistDiosLock(DiosLock* p)
  106. {
  107. UINT64 val = (UINT64)p;
  108. Dios_ThreadLock(&g_csDiosLock);
  109. //clean up object map
  110. map<UINT64, DiosLock*>::iterator iter = g_InternalDiosObjectMap.find(val);
  111. if (iter != g_InternalDiosObjectMap.end())
  112. {
  113. g_InternalDiosObjectMap.erase(iter);
  114. }
  115. //clean up locked map
  116. map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(val);
  117. if (iter_locked != g_InternalLockedMap.end())
  118. {
  119. g_InternalLockedMap.erase(iter_locked);
  120. }
  121. Dios_ThreadUnLock(&g_csDiosLock);
  122. }
  123. void UnMapLockForThread(DiosLock *p)
  124. {
  125. UINT64 ID = (UINT64)p;
  126. Dios_ThreadLock(&g_csDiosLock);
  127. //find locked map
  128. map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(ID);
  129. #ifdef _DEBUG
  130. if (iter_locked == g_InternalLockedMap.end())
  131. {
  132. assert(0);//buggy
  133. }
  134. if (iter_locked->second != GetCurrentThreadId())
  135. {
  136. assert(0);//buggy
  137. }
  138. #endif
  139. if (iter_locked != g_InternalLockedMap.end())
  140. {
  141. //incase of exp...
  142. g_InternalLockedMap.erase(iter_locked);
  143. }
  144. Dios_ThreadUnLock(&g_csDiosLock);
  145. }
  146. void MapLockForThread(DiosLock *p)
  147. {
  148. UINT64 ID = (UINT64)p;
  149. Dios_ThreadLock(&g_csDiosLock);
  150. //find locked map
  151. #ifdef _DEBUG
  152. map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.find(ID);
  153. if (iter_locked != g_InternalLockedMap.end())
  154. {
  155. assert(0);//buggy
  156. }
  157. #endif
  158. g_InternalLockedMap[ID] = GetCurrentThreadId();
  159. Dios_ThreadUnLock(&g_csDiosLock);
  160. }
  161. void CleanupForThread(DWORD Tid)
  162. {
  163. /*
  164. try to unlock g_csDiosLock, if it's ThreadId matches.
  165. */
  166. Dios_ThreadClearForTid(&g_csDiosLock, Tid);//try clear g_cs...
  167. Dios_ThreadLock(&g_csDiosLock);
  168. //find locked map
  169. map<UINT64, DWORD>::iterator iter_locked = g_InternalLockedMap.begin();
  170. while (iter_locked != g_InternalLockedMap.end())
  171. {
  172. if (iter_locked->second == Tid)
  173. {
  174. //found one
  175. DiosLock* pLock = (DiosLock*)(iter_locked->first);
  176. //check existance of plock
  177. map<UINT64, DiosLock*>::iterator iter = g_InternalDiosObjectMap.find(iter_locked->first);
  178. if (iter != g_InternalDiosObjectMap.end())
  179. {
  180. //exist
  181. pLock->Thread_Clear(Tid);
  182. }
  183. else
  184. {
  185. //the pLock not exit
  186. }
  187. iter_locked = g_InternalLockedMap.erase(iter_locked);
  188. continue;
  189. }
  190. ++iter_locked;
  191. }
  192. //clear the lock for the thread
  193. Dios_ThreadUnLock(&g_csDiosLock);
  194. }
  195. DiosLock::DiosLock()
  196. {
  197. m_InterLock = 0;
  198. m_RefCount = 0;
  199. m_LockHandle = CreateEvent(0, 1, 1, 0);
  200. RegistDiosLock(this);
  201. return;
  202. }
  203. DiosLock::~DiosLock()
  204. {
  205. if ((m_InterLock) > 0)
  206. {
  207. //printf("Warning:ThreadId:%d is in Lock-----------\n", (m_InterLock));
  208. }
  209. UnRegistDiosLock(this);
  210. m_InterLock = 0;
  211. CloseHandle(m_LockHandle);
  212. return;
  213. }
  214. bool DiosLock::DiosInternal_EnterCriticalSection(DWORD TryCount)
  215. {
  216. if (TryCount == 0)
  217. {
  218. return false;
  219. }
  220. DWORD Tid = GetCurrentThreadId();
  221. //first try
  222. if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, 0) == 0)
  223. {
  224. ++m_RefCount;
  225. MapLockForThread(this);
  226. return true;
  227. }
  228. //check first
  229. if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
  230. {
  231. //already locked
  232. ++m_RefCount;
  233. return true;
  234. }
  235. //do loop
  236. while (TryCount > 1)
  237. {
  238. if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, 0) == 0)
  239. {
  240. ++m_RefCount;
  241. MapLockForThread(this);
  242. return true;
  243. }
  244. --TryCount;
  245. }
  246. return false;
  247. }
  248. void DiosLock::DiosInternal_LeaveCriticalSection()
  249. {
  250. DWORD Tid = GetCurrentThreadId();
  251. if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
  252. {
  253. //lock owner is right
  254. if (m_RefCount > 0)
  255. {
  256. --m_RefCount;
  257. if (m_RefCount > 0)
  258. {
  259. return;
  260. }
  261. //unmap first
  262. UnMapLockForThread(this);
  263. //clear second
  264. if (InterlockedCompareExchangeRelease(&m_InterLock, 0, Tid) == Tid)
  265. {
  266. return;
  267. }
  268. }
  269. }
  270. //ignore wrong unlocks
  271. }
  272. DWORD DiosLock::Thread_Lock(DWORD timeout)
  273. {
  274. //timeout == 0 优化
  275. if (timeout == 0)
  276. {
  277. if (DiosInternal_EnterCriticalSection(1) == FALSE)
  278. {
  279. return WAIT_TIMEOUT;
  280. }
  281. m_LockThreadId = GetCurrentThreadId();
  282. ResetEvent(m_LockHandle);
  283. return WAIT_OBJECT_0;
  284. }
  285. if (DiosInternal_EnterCriticalSection(800) == FALSE)
  286. {
  287. while (timeout > 0)
  288. {
  289. DWORD FirstHit = GetTickCount();
  290. //failed get
  291. DWORD ret = Thread_WaitUnlockNotify(timeout);
  292. if (ret == WAIT_OBJECT_0)
  293. {
  294. //try it again
  295. if (DiosInternal_EnterCriticalSection(800))
  296. {
  297. m_LockThreadId = GetCurrentThreadId();
  298. ResetEvent(m_LockHandle);
  299. return WAIT_OBJECT_0;
  300. }
  301. }
  302. //failed get again
  303. DWORD Usedtime = GetTickCount() - FirstHit;
  304. if (Usedtime < timeout)
  305. {
  306. timeout -= Usedtime;
  307. }
  308. else
  309. {
  310. return WAIT_TIMEOUT;
  311. }
  312. }
  313. }
  314. //ResetEvent(m_LockHandle);
  315. m_LockThreadId = GetCurrentThreadId();
  316. ResetEvent(m_LockHandle);
  317. return WAIT_OBJECT_0;
  318. }
  319. void DiosLock::Thread_UnLock()
  320. {
  321. DiosInternal_LeaveCriticalSection();
  322. if (m_RefCount == 0)
  323. {
  324. m_LockThreadId = 0;
  325. SetEvent(m_LockHandle);
  326. }
  327. }
  328. bool DiosLock::Thread_Clear(DWORD Tid)
  329. {
  330. if (InterlockedCompareExchangeAcquire(&m_InterLock, Tid, Tid) == Tid)
  331. {
  332. //lock owner is right
  333. //if (m_RefCount > 0)
  334. {
  335. m_RefCount = 0;
  336. if (InterlockedCompareExchangeRelease(&m_InterLock, 0, Tid) == Tid)
  337. {
  338. SetEvent(m_LockHandle);
  339. return true;
  340. }
  341. }
  342. }
  343. return false;
  344. //ignore wrong unlocks
  345. }
  346. DWORD DiosLock::Thread_WaitUnlockNotify(DWORD timeout)
  347. {
  348. while (timeout > 0)
  349. {
  350. DWORD FirstHit = GetTickCount();
  351. DWORD WaitPeriod = min(timeout, 1000);
  352. DWORD ret = WaitForSingleObject(m_LockHandle, WaitPeriod);
  353. if (ret == WAIT_OBJECT_0)
  354. {
  355. return WAIT_OBJECT_0;
  356. }
  357. //try clear once
  358. Try_Clear_DeadThread();
  359. //failed get again
  360. DWORD Usedtime = GetTickCount() - FirstHit;
  361. if (Usedtime < timeout)
  362. {
  363. timeout -= Usedtime;
  364. }
  365. else
  366. {
  367. return WAIT_TIMEOUT;
  368. }
  369. }
  370. return WAIT_TIMEOUT;
  371. }
  372. INT DiosLock::FindProcessThreads(DWORD dwOwnerTID)
  373. {
  374. INT ret = -1;
  375. DWORD dwOwnerPID = GetCurrentProcessId();
  376. HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
  377. THREADENTRY32 te32;
  378. // Take a snapshot of all running threads
  379. hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  380. if (hThreadSnap == INVALID_HANDLE_VALUE)
  381. return (ret);
  382. // Fill in the size of the structure before using it.
  383. te32.dwSize = sizeof(THREADENTRY32);
  384. // Retrieve information about the first thread,
  385. // and exit if unsuccessful
  386. if (!Thread32First(hThreadSnap, &te32))
  387. {
  388. CloseHandle(hThreadSnap); // Must clean up the
  389. // snapshot object!
  390. return (ret);
  391. }
  392. // Now walk the thread list of the system,
  393. // and display information about each thread
  394. // associated with the specified process
  395. ret = 0;//set not found flag first
  396. do
  397. {
  398. if (te32.th32OwnerProcessID == dwOwnerPID && te32.th32ThreadID == dwOwnerTID)
  399. {
  400. //found it
  401. ret = 1;
  402. break;
  403. }
  404. } while (Thread32Next(hThreadSnap, &te32));
  405. // Don't forget to clean up the snapshot object.
  406. CloseHandle(hThreadSnap);
  407. return (ret);
  408. }
  409. bool DiosLock::Try_Clear_DeadThread()
  410. {
  411. DWORD Tid = m_InterLock;//just get it
  412. if (Tid == 0)
  413. {
  414. return true;
  415. }
  416. int FoundT = FindProcessThreads(Tid);
  417. if (FoundT == 0)
  418. {
  419. //目标不存在
  420. return Thread_Clear(Tid);
  421. }
  422. else if (FoundT > 0)
  423. {
  424. return false;
  425. }
  426. return false;
  427. }
  428. #pragma warning( push )
  429. #pragma warning( disable : 4114 )
  430. DIOSLOCK_C_API bool Dios_ThreadLock(volatile UINT64 volatile *pLock)
  431. {
  432. DWORD *pLockData = (DWORD*)pLock;
  433. DWORD *pRefCount = (DWORD*)&pLockData[1];
  434. DWORD Tid = GetCurrentThreadId();
  435. //first try
  436. if (InterlockedCompareExchangeAcquire(pLockData, Tid, 0) == 0)
  437. {
  438. ++(*pRefCount);
  439. return true;
  440. }
  441. //check first
  442. if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
  443. {
  444. //already locked
  445. ++(*pRefCount);
  446. return true;
  447. }
  448. //do loop
  449. while (1)
  450. {
  451. if (InterlockedCompareExchangeAcquire(pLockData, Tid, 0) == 0)
  452. {
  453. ++(*pRefCount);
  454. return true;
  455. }
  456. //check exist tid
  457. }
  458. return false;
  459. }
  460. DIOSLOCK_C_API void Dios_ThreadUnLock(volatile UINT64 volatile *pLock)
  461. {
  462. DWORD *pLockData = (DWORD*)pLock;
  463. DWORD *pRefCount = (DWORD*)&pLockData[1];
  464. DWORD Tid = GetCurrentThreadId();
  465. if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
  466. {
  467. //lock owner is right
  468. if ((*pRefCount) > 0)
  469. {
  470. --(*pRefCount);
  471. if ((*pRefCount) > 0)
  472. {
  473. return;
  474. }
  475. if (InterlockedCompareExchangeRelease(pLockData, 0, Tid) == Tid)
  476. {
  477. return;
  478. }
  479. }
  480. }
  481. //ignore wrong unlocks
  482. }
  483. DIOSLOCK_C_API void Dios_ThreadClearForTid(volatile UINT64 volatile *pLock,DWORD Tid)
  484. {
  485. DWORD *pLockData = (DWORD*)pLock;
  486. DWORD *pRefCount = (DWORD*)&pLockData[1];
  487. if (InterlockedCompareExchangeAcquire(pLockData, Tid, Tid) == Tid)
  488. {
  489. (*pRefCount) = 0;
  490. if (InterlockedCompareExchangeRelease(pLockData, 0, Tid) == Tid)
  491. {
  492. return;
  493. }
  494. }
  495. //ignore wrong unlocks
  496. }
  497. #pragma warning( pop )
  498. DIOSLOCK_C_API DWORD Thread_GetUniqTick()
  499. {
  500. static volatile UINT64 g_IdxLock = 0;
  501. static volatile DWORD oldTick = 1;
  502. DWORD tick = 0;
  503. if (Dios_ThreadLock(&g_IdxLock))
  504. {
  505. if (oldTick == 0)
  506. {
  507. oldTick = 1;
  508. }
  509. tick = oldTick++;
  510. Dios_ThreadUnLock(&g_IdxLock);
  511. }
  512. return tick;
  513. }