ResLocks.cpp
上传用户:woshihumen
上传日期:2013-07-18
资源大小:484k
文件大小:12k
源码类别:

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  XMail by Davide Libenzi ( Intranet and Internet mail server )
  3.  *  Copyright (C) 1999,..,2004  Davide Libenzi
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *
  19.  *  Davide Libenzi <davidel@xmailserver.org>
  20.  *
  21.  */
  22. #include "SysInclude.h"
  23. #include "SysDep.h"
  24. #include "SvrDefines.h"
  25. #include "ShBlocks.h"
  26. #include "ResLocks.h"
  27. #include "BuffSock.h"
  28. #include "MiscUtils.h"
  29. #include "MessQueue.h"
  30. #include "MailConfig.h"
  31. #include "MailSvr.h"
  32. #define STD_WAIT_GATES              37
  33. #define STD_RES_HASH_SIZE           251
  34. #define STD_RLCK_HASH_INIT          9677
  35. struct ResWaitGate {
  36. SYS_SEMAPHORE hSemaphore;
  37. int iWaitingProcesses;
  38. int iHashSize;
  39. SysListHead *pResList;
  40. };
  41. struct ResLockEntry {
  42. SysListHead LLink;
  43. int iShLocks;
  44. int iExLocks;
  45. char szName[1];
  46. };
  47. struct ResLocator {
  48. int iWaitGate;
  49. int iResIdx;
  50. };
  51. static SYS_UINT32 RLckHashString(char const *pData, SYS_UINT32 uHashInit = STD_RLCK_HASH_INIT);
  52. static void RLckGetResLocator(char const *pszResourceName, ResLocator * pRL);
  53. static ResLockEntry *RLckGetEntry(ResLocator const *pRL, char const *pszResourceName);
  54. static int RLckRemoveEntry(ResLocator const *pRL, ResLockEntry * pRLE);
  55. static ResLockEntry *RLckAllocEntry(char const *pszResourceName);
  56. static int RLckFreeEntry(ResLockEntry * pRLE);
  57. static int RLckTryLockEX(ResLocator const *pRL, char const *pszResourceName);
  58. static int RLckDoUnlockEX(ResLocator const *pRL, char const *pszResourceName);
  59. static int RLckTryLockSH(ResLocator const *pRL, char const *pszResourceName);
  60. static int RLckDoUnlockSH(ResLocator const *pRL, char const *pszResourceName);
  61. static RLCK_HANDLE RLckLock(char const *pszResourceName,
  62.     int (*pLockProc) (ResLocator const *, char const *));
  63. static int RLckUnlock(RLCK_HANDLE hLock, int (*pUnlockProc) (ResLocator const *, char const *));
  64. static SYS_MUTEX hRLMutex = SYS_INVALID_MUTEX;
  65. static ResWaitGate RLGates[STD_WAIT_GATES];
  66. int RLckInitLockers(void)
  67. {
  68. ///////////////////////////////////////////////////////////////////////////////
  69. //  Create resource locking mutex
  70. ///////////////////////////////////////////////////////////////////////////////
  71. if ((hRLMutex = SysCreateMutex()) == SYS_INVALID_MUTEX)
  72. return (ErrGetErrorCode());
  73. ///////////////////////////////////////////////////////////////////////////////
  74. //  Initialize wait gates
  75. ///////////////////////////////////////////////////////////////////////////////
  76. for (int ii = 0; ii < STD_WAIT_GATES; ii++) {
  77. if ((RLGates[ii].hSemaphore = SysCreateSemaphore(0,
  78.  SYS_DEFAULT_MAXCOUNT)) ==
  79.     SYS_INVALID_SEMAPHORE) {
  80. ErrorPush();
  81. for (--ii; ii >= 0; ii--) {
  82. SysFree(RLGates[ii].pResList);
  83. SysCloseSemaphore(RLGates[ii].hSemaphore);
  84. }
  85. SysCloseMutex(hRLMutex);
  86. return (ErrorPop());
  87. }
  88. RLGates[ii].iWaitingProcesses = 0;
  89. RLGates[ii].iHashSize = STD_RES_HASH_SIZE;
  90. if ((RLGates[ii].pResList = (SysListHead *)
  91.      SysAlloc(RLGates[ii].iHashSize * sizeof(SysListHead))) == NULL) {
  92. ErrorPush();
  93. SysCloseSemaphore(RLGates[ii].hSemaphore);
  94. for (--ii; ii >= 0; ii--) {
  95. SysFree(RLGates[ii].pResList);
  96. SysCloseSemaphore(RLGates[ii].hSemaphore);
  97. }
  98. SysCloseMutex(hRLMutex);
  99. return (ErrorPop());
  100. }
  101. for (int jj = 0; jj < RLGates[ii].iHashSize; jj++)
  102. SYS_INIT_LIST_HEAD(&RLGates[ii].pResList[jj]);
  103. }
  104. return (0);
  105. }
  106. int RLckCleanupLockers(void)
  107. {
  108. SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT);
  109. for (int ii = 0; ii < STD_WAIT_GATES; ii++) {
  110. for (int jj = 0; jj < RLGates[ii].iHashSize; jj++) {
  111. SysListHead *pHead = &RLGates[ii].pResList[jj];
  112. SysListHead *pLLink;
  113. while ((pLLink = SYS_LIST_FIRST(pHead)) != NULL) {
  114. ResLockEntry *pRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink);
  115. SYS_LIST_DEL(&pRLE->LLink);
  116. RLckFreeEntry(pRLE);
  117. }
  118. }
  119. SysFree(RLGates[ii].pResList);
  120. SysCloseSemaphore(RLGates[ii].hSemaphore);
  121. }
  122. SysUnlockMutex(hRLMutex);
  123. SysCloseMutex(hRLMutex);
  124. return (0);
  125. }
  126. static SYS_UINT32 RLckHashString(char const *pData, SYS_UINT32 uHashInit)
  127. {
  128. SYS_UINT32 uHashVal = uHashInit;
  129. while (*pData) {
  130. uHashVal += (uHashVal << 5);
  131. uHashVal ^= (SYS_UINT32) ToLower(*pData);
  132. pData++;
  133. }
  134. return (uHashVal);
  135. }
  136. static void RLckGetResLocator(char const *pszResourceName, ResLocator * pRL)
  137. {
  138. SYS_UINT32 uResHash = RLckHashString(pszResourceName);
  139. pRL->iWaitGate = (int) (uResHash % STD_WAIT_GATES);
  140. pRL->iResIdx = (int) (uResHash % (SYS_UINT32) RLGates[pRL->iWaitGate].iHashSize);
  141. }
  142. static ResLockEntry *RLckGetEntry(ResLocator const *pRL, char const *pszResourceName)
  143. {
  144. SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx];
  145. SysListHead *pLLink;
  146. SYS_LIST_FOR_EACH(pLLink, pHead) {
  147. ResLockEntry *pRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink);
  148. if (stricmp(pszResourceName, pRLE->szName) == 0)
  149. return (pRLE);
  150. }
  151. ErrSetErrorCode(ERR_LOCK_ENTRY_NOT_FOUND);
  152. return (NULL);
  153. }
  154. static int RLckRemoveEntry(ResLocator const *pRL, ResLockEntry * pRLE)
  155. {
  156. SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx];
  157. SysListHead *pLLink;
  158. SYS_LIST_FOR_EACH(pLLink, pHead) {
  159. ResLockEntry *pCurrRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink);
  160. if (pCurrRLE == pRLE) {
  161. SYS_LIST_DEL(&pRLE->LLink);
  162. RLckFreeEntry(pRLE);
  163. return (0);
  164. }
  165. }
  166. ErrSetErrorCode(ERR_LOCK_ENTRY_NOT_FOUND);
  167. return (ERR_LOCK_ENTRY_NOT_FOUND);
  168. }
  169. static ResLockEntry *RLckAllocEntry(char const *pszResourceName)
  170. {
  171. ResLockEntry *pRLE = (ResLockEntry *) SysAlloc(sizeof(ResLockEntry) +
  172.        strlen(pszResourceName));
  173. if (pRLE == NULL)
  174. return (NULL);
  175. SYS_INIT_LIST_LINK(&pRLE->LLink);
  176. pRLE->iShLocks = 0;
  177. pRLE->iExLocks = 0;
  178. strcpy(pRLE->szName, pszResourceName);
  179. return (pRLE);
  180. }
  181. static int RLckFreeEntry(ResLockEntry * pRLE)
  182. {
  183. SysFree(pRLE);
  184. return (0);
  185. }
  186. static int RLckTryLockEX(ResLocator const *pRL, char const *pszResourceName)
  187. {
  188. ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName);
  189. if (pRLE == NULL) {
  190. SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx];
  191. if ((pRLE = RLckAllocEntry(pszResourceName)) == NULL)
  192. return (ErrGetErrorCode());
  193. pRLE->iExLocks = 1;
  194. ///////////////////////////////////////////////////////////////////////////////
  195. //  Insert new entry in resource list
  196. ///////////////////////////////////////////////////////////////////////////////
  197. SYS_LIST_ADDH(&pRLE->LLink, pHead);
  198. } else {
  199. if ((pRLE->iExLocks > 0) || (pRLE->iShLocks > 0)) {
  200. ErrSetErrorCode(ERR_LOCKED_RESOURCE);
  201. return (ERR_LOCKED_RESOURCE);
  202. }
  203. pRLE->iExLocks = 1;
  204. }
  205. return (0);
  206. }
  207. static int RLckDoUnlockEX(ResLocator const *pRL, char const *pszResourceName)
  208. {
  209. ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName);
  210. if ((pRLE == NULL) || (pRLE->iExLocks == 0)) {
  211. ErrSetErrorCode(ERR_RESOURCE_NOT_LOCKED);
  212. return (ERR_RESOURCE_NOT_LOCKED);
  213. }
  214. pRLE->iExLocks = 0;
  215. ///////////////////////////////////////////////////////////////////////////////
  216. //  Remove entry from list and delete entry memory
  217. ///////////////////////////////////////////////////////////////////////////////
  218. if (RLckRemoveEntry(pRL, pRLE) < 0)
  219. return (ErrGetErrorCode());
  220. ///////////////////////////////////////////////////////////////////////////////
  221. //  Release waiting processes
  222. ///////////////////////////////////////////////////////////////////////////////
  223. if (RLGates[pRL->iWaitGate].iWaitingProcesses > 0) {
  224. SysReleaseSemaphore(RLGates[pRL->iWaitGate].hSemaphore,
  225.     RLGates[pRL->iWaitGate].iWaitingProcesses);
  226. RLGates[pRL->iWaitGate].iWaitingProcesses = 0;
  227. }
  228. return (0);
  229. }
  230. static int RLckTryLockSH(ResLocator const *pRL, char const *pszResourceName)
  231. {
  232. ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName);
  233. if (pRLE == NULL) {
  234. SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx];
  235. if ((pRLE = RLckAllocEntry(pszResourceName)) == NULL)
  236. return (ErrGetErrorCode());
  237. pRLE->iShLocks = 1;
  238. ///////////////////////////////////////////////////////////////////////////////
  239. //  Insert new entry in resource list
  240. ///////////////////////////////////////////////////////////////////////////////
  241. SYS_LIST_ADDH(&pRLE->LLink, pHead);
  242. } else {
  243. if (pRLE->iExLocks > 0) {
  244. ErrSetErrorCode(ERR_LOCKED_RESOURCE);
  245. return (ERR_LOCKED_RESOURCE);
  246. }
  247. ++pRLE->iShLocks;
  248. }
  249. return (0);
  250. }
  251. static int RLckDoUnlockSH(ResLocator const *pRL, char const *pszResourceName)
  252. {
  253. ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName);
  254. if ((pRLE == NULL) || (pRLE->iShLocks == 0)) {
  255. ErrSetErrorCode(ERR_RESOURCE_NOT_LOCKED);
  256. return (ERR_RESOURCE_NOT_LOCKED);
  257. }
  258. if (--pRLE->iShLocks == 0) {
  259. ///////////////////////////////////////////////////////////////////////////////
  260. //  Remove entry from list and delete entry heap memory
  261. ///////////////////////////////////////////////////////////////////////////////
  262. if (RLckRemoveEntry(pRL, pRLE) < 0)
  263. return (ErrGetErrorCode());
  264. ///////////////////////////////////////////////////////////////////////////////
  265. //  Release waiting processes
  266. ///////////////////////////////////////////////////////////////////////////////
  267. if (RLGates[pRL->iWaitGate].iWaitingProcesses > 0) {
  268. SysReleaseSemaphore(RLGates[pRL->iWaitGate].hSemaphore,
  269.     RLGates[pRL->iWaitGate].iWaitingProcesses);
  270. RLGates[pRL->iWaitGate].iWaitingProcesses = 0;
  271. }
  272. }
  273. return (0);
  274. }
  275. static RLCK_HANDLE RLckLock(char const *pszResourceName,
  276.     int (*pLockProc) (ResLocator const *, char const *))
  277. {
  278. ResLocator RL;
  279. RLckGetResLocator(pszResourceName, &RL);
  280. for (;;) {
  281. ///////////////////////////////////////////////////////////////////////////////
  282. //  Lock resources list access
  283. ///////////////////////////////////////////////////////////////////////////////
  284. if (SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT) < 0)
  285. return (INVALID_RLCK_HANDLE);
  286. int iLockResult = pLockProc(&RL, pszResourceName);
  287. if (iLockResult == ERR_LOCKED_RESOURCE) {
  288. SYS_SEMAPHORE SemID = RLGates[RL.iWaitGate].hSemaphore;
  289. ++RLGates[RL.iWaitGate].iWaitingProcesses;
  290. SysUnlockMutex(hRLMutex);
  291. if (SysWaitSemaphore(SemID, SYS_INFINITE_TIMEOUT) < 0)
  292. return (INVALID_RLCK_HANDLE);
  293. } else if (iLockResult == 0) {
  294. SysUnlockMutex(hRLMutex);
  295. break;
  296. } else {
  297. SysUnlockMutex(hRLMutex);
  298. return (INVALID_RLCK_HANDLE);
  299. }
  300. }
  301. return ((RLCK_HANDLE) SysStrDup(pszResourceName));
  302. }
  303. static int RLckUnlock(RLCK_HANDLE hLock, int (*pUnlockProc) (ResLocator const *, char const *))
  304. {
  305. char *pszResourceName = (char *) hLock;
  306. ResLocator RL;
  307. RLckGetResLocator(pszResourceName, &RL);
  308. ///////////////////////////////////////////////////////////////////////////////
  309. //  Lock resources list access
  310. ///////////////////////////////////////////////////////////////////////////////
  311. if (SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT) < 0)
  312. return (ErrGetErrorCode());
  313. if (pUnlockProc(&RL, pszResourceName) < 0) {
  314. ErrorPush();
  315. SysUnlockMutex(hRLMutex);
  316. SysFree(pszResourceName);
  317. return (ErrorPop());
  318. }
  319. SysUnlockMutex(hRLMutex);
  320. SysFree(pszResourceName);
  321. return (0);
  322. }
  323. RLCK_HANDLE RLckLockEX(char const *pszResourceName)
  324. {
  325. return (RLckLock(pszResourceName, RLckTryLockEX));
  326. }
  327. int RLckUnlockEX(RLCK_HANDLE hLock)
  328. {
  329. return (RLckUnlock(hLock, RLckDoUnlockEX));
  330. }
  331. RLCK_HANDLE RLckLockSH(char const *pszResourceName)
  332. {
  333. return (RLckLock(pszResourceName, RLckTryLockSH));
  334. }
  335. int RLckUnlockSH(RLCK_HANDLE hLock)
  336. {
  337. return (RLckUnlock(hLock, RLckDoUnlockSH));
  338. }