www.gusucode.com > VC++版的邮件服务器源程序源码程序 > VC++版的邮件服务器源程序源码程序\code\ResLocks.cpp
//Download by http://www.NewXing.com /* * XMail by Davide Libenzi ( Intranet and Internet mail server ) * Copyright (C) 1999,..,2004 Davide Libenzi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi <davidel@xmailserver.org> * */ #include "SysInclude.h" #include "SysDep.h" #include "SvrDefines.h" #include "ShBlocks.h" #include "ResLocks.h" #include "BuffSock.h" #include "MiscUtils.h" #include "MessQueue.h" #include "MailConfig.h" #include "MailSvr.h" #define STD_WAIT_GATES 37 #define STD_RES_HASH_SIZE 251 struct ResWaitGate { SYS_SEMAPHORE hSemaphore; int iWaitingProcesses; int iHashSize; SysListHead *pResList; }; struct ResLockEntry { SysListHead LLink; int iShLocks; int iExLocks; char szName[1]; }; struct ResLocator { int iWaitGate; int iResIdx; }; static void RLckGetResLocator(char const *pszResourceName, ResLocator * pRL); static ResLockEntry *RLckGetEntry(ResLocator const *pRL, char const *pszResourceName); static int RLckRemoveEntry(ResLocator const *pRL, ResLockEntry * pRLE); static ResLockEntry *RLckAllocEntry(char const *pszResourceName); static int RLckFreeEntry(ResLockEntry * pRLE); static int RLckTryLockEX(ResLocator const *pRL, char const *pszResourceName); static int RLckDoUnlockEX(ResLocator const *pRL, char const *pszResourceName); static int RLckTryLockSH(ResLocator const *pRL, char const *pszResourceName); static int RLckDoUnlockSH(ResLocator const *pRL, char const *pszResourceName); static RLCK_HANDLE RLckLock(char const *pszResourceName, int (*pLockProc) (ResLocator const *, char const *)); static int RLckUnlock(RLCK_HANDLE hLock, int (*pUnlockProc) (ResLocator const *, char const *)); static SYS_MUTEX hRLMutex = SYS_INVALID_MUTEX; static ResWaitGate RLGates[STD_WAIT_GATES]; int RLckInitLockers(void) { /////////////////////////////////////////////////////////////////////////////// // Create resource locking mutex /////////////////////////////////////////////////////////////////////////////// if ((hRLMutex = SysCreateMutex()) == SYS_INVALID_MUTEX) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Initialize wait gates /////////////////////////////////////////////////////////////////////////////// for (int ii = 0; ii < STD_WAIT_GATES; ii++) { if ((RLGates[ii].hSemaphore = SysCreateSemaphore(0, SYS_DEFAULT_MAXCOUNT)) == SYS_INVALID_SEMAPHORE) { ErrorPush(); for (--ii; ii >= 0; ii--) { SysFree(RLGates[ii].pResList); SysCloseSemaphore(RLGates[ii].hSemaphore); } SysCloseMutex(hRLMutex); return (ErrorPop()); } RLGates[ii].iWaitingProcesses = 0; RLGates[ii].iHashSize = STD_RES_HASH_SIZE; if ((RLGates[ii].pResList = (SysListHead *) SysAlloc(RLGates[ii].iHashSize * sizeof(SysListHead))) == NULL) { ErrorPush(); SysCloseSemaphore(RLGates[ii].hSemaphore); for (--ii; ii >= 0; ii--) { SysFree(RLGates[ii].pResList); SysCloseSemaphore(RLGates[ii].hSemaphore); } SysCloseMutex(hRLMutex); return (ErrorPop()); } for (int jj = 0; jj < RLGates[ii].iHashSize; jj++) SYS_INIT_LIST_HEAD(&RLGates[ii].pResList[jj]); } return (0); } int RLckCleanupLockers(void) { SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT); for (int ii = 0; ii < STD_WAIT_GATES; ii++) { for (int jj = 0; jj < RLGates[ii].iHashSize; jj++) { SysListHead *pHead = &RLGates[ii].pResList[jj]; SysListHead *pLLink; while ((pLLink = SYS_LIST_FIRST(pHead)) != NULL) { ResLockEntry *pRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink); SYS_LIST_DEL(&pRLE->LLink); RLckFreeEntry(pRLE); } } SysFree(RLGates[ii].pResList); SysCloseSemaphore(RLGates[ii].hSemaphore); } SysUnlockMutex(hRLMutex); SysCloseMutex(hRLMutex); return (0); } static void RLckGetResLocator(char const *pszResourceName, ResLocator * pRL) { SYS_UINT32 uResHash = MscHashString(pszResourceName, strlen(pszResourceName)); pRL->iWaitGate = (int) (uResHash % STD_WAIT_GATES); pRL->iResIdx = (int) (uResHash % (SYS_UINT32) RLGates[pRL->iWaitGate].iHashSize); } static ResLockEntry *RLckGetEntry(ResLocator const *pRL, char const *pszResourceName) { SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx]; SysListHead *pLLink; SYS_LIST_FOR_EACH(pLLink, pHead) { ResLockEntry *pRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink); if (stricmp(pszResourceName, pRLE->szName) == 0) return (pRLE); } ErrSetErrorCode(ERR_LOCK_ENTRY_NOT_FOUND); return (NULL); } static int RLckRemoveEntry(ResLocator const *pRL, ResLockEntry * pRLE) { SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx]; SysListHead *pLLink; SYS_LIST_FOR_EACH(pLLink, pHead) { ResLockEntry *pCurrRLE = SYS_LIST_ENTRY(pLLink, ResLockEntry, LLink); if (pCurrRLE == pRLE) { SYS_LIST_DEL(&pRLE->LLink); RLckFreeEntry(pRLE); return (0); } } ErrSetErrorCode(ERR_LOCK_ENTRY_NOT_FOUND); return (ERR_LOCK_ENTRY_NOT_FOUND); } static ResLockEntry *RLckAllocEntry(char const *pszResourceName) { ResLockEntry *pRLE = (ResLockEntry *) SysAlloc(sizeof(ResLockEntry) + strlen(pszResourceName)); if (pRLE == NULL) return (NULL); SYS_INIT_LIST_LINK(&pRLE->LLink); pRLE->iShLocks = 0; pRLE->iExLocks = 0; strcpy(pRLE->szName, pszResourceName); return (pRLE); } static int RLckFreeEntry(ResLockEntry * pRLE) { SysFree(pRLE); return (0); } static int RLckTryLockEX(ResLocator const *pRL, char const *pszResourceName) { ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName); if (pRLE == NULL) { SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx]; if ((pRLE = RLckAllocEntry(pszResourceName)) == NULL) return (ErrGetErrorCode()); pRLE->iExLocks = 1; /////////////////////////////////////////////////////////////////////////////// // Insert new entry in resource list /////////////////////////////////////////////////////////////////////////////// SYS_LIST_ADDH(&pRLE->LLink, pHead); } else { if ((pRLE->iExLocks > 0) || (pRLE->iShLocks > 0)) { ErrSetErrorCode(ERR_LOCKED_RESOURCE); return (ERR_LOCKED_RESOURCE); } pRLE->iExLocks = 1; } return (0); } static int RLckDoUnlockEX(ResLocator const *pRL, char const *pszResourceName) { ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName); if ((pRLE == NULL) || (pRLE->iExLocks == 0)) { ErrSetErrorCode(ERR_RESOURCE_NOT_LOCKED); return (ERR_RESOURCE_NOT_LOCKED); } pRLE->iExLocks = 0; /////////////////////////////////////////////////////////////////////////////// // Remove entry from list and delete entry memory /////////////////////////////////////////////////////////////////////////////// if (RLckRemoveEntry(pRL, pRLE) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Release waiting processes /////////////////////////////////////////////////////////////////////////////// if (RLGates[pRL->iWaitGate].iWaitingProcesses > 0) { SysReleaseSemaphore(RLGates[pRL->iWaitGate].hSemaphore, RLGates[pRL->iWaitGate].iWaitingProcesses); RLGates[pRL->iWaitGate].iWaitingProcesses = 0; } return (0); } static int RLckTryLockSH(ResLocator const *pRL, char const *pszResourceName) { ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName); if (pRLE == NULL) { SysListHead *pHead = &RLGates[pRL->iWaitGate].pResList[pRL->iResIdx]; if ((pRLE = RLckAllocEntry(pszResourceName)) == NULL) return (ErrGetErrorCode()); pRLE->iShLocks = 1; /////////////////////////////////////////////////////////////////////////////// // Insert new entry in resource list /////////////////////////////////////////////////////////////////////////////// SYS_LIST_ADDH(&pRLE->LLink, pHead); } else { if (pRLE->iExLocks > 0) { ErrSetErrorCode(ERR_LOCKED_RESOURCE); return (ERR_LOCKED_RESOURCE); } ++pRLE->iShLocks; } return (0); } static int RLckDoUnlockSH(ResLocator const *pRL, char const *pszResourceName) { ResLockEntry *pRLE = RLckGetEntry(pRL, pszResourceName); if ((pRLE == NULL) || (pRLE->iShLocks == 0)) { ErrSetErrorCode(ERR_RESOURCE_NOT_LOCKED); return (ERR_RESOURCE_NOT_LOCKED); } if (--pRLE->iShLocks == 0) { /////////////////////////////////////////////////////////////////////////////// // Remove entry from list and delete entry heap memory /////////////////////////////////////////////////////////////////////////////// if (RLckRemoveEntry(pRL, pRLE) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Release waiting processes /////////////////////////////////////////////////////////////////////////////// if (RLGates[pRL->iWaitGate].iWaitingProcesses > 0) { SysReleaseSemaphore(RLGates[pRL->iWaitGate].hSemaphore, RLGates[pRL->iWaitGate].iWaitingProcesses); RLGates[pRL->iWaitGate].iWaitingProcesses = 0; } } return (0); } static RLCK_HANDLE RLckLock(char const *pszResourceName, int (*pLockProc) (ResLocator const *, char const *)) { ResLocator RL; RLckGetResLocator(pszResourceName, &RL); for (;;) { /////////////////////////////////////////////////////////////////////////////// // Lock resources list access /////////////////////////////////////////////////////////////////////////////// if (SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT) < 0) return (INVALID_RLCK_HANDLE); int iLockResult = pLockProc(&RL, pszResourceName); if (iLockResult == ERR_LOCKED_RESOURCE) { SYS_SEMAPHORE SemID = RLGates[RL.iWaitGate].hSemaphore; ++RLGates[RL.iWaitGate].iWaitingProcesses; SysUnlockMutex(hRLMutex); if (SysWaitSemaphore(SemID, SYS_INFINITE_TIMEOUT) < 0) return (INVALID_RLCK_HANDLE); } else if (iLockResult == 0) { SysUnlockMutex(hRLMutex); break; } else { SysUnlockMutex(hRLMutex); return (INVALID_RLCK_HANDLE); } } return ((RLCK_HANDLE) SysStrDup(pszResourceName)); } static int RLckUnlock(RLCK_HANDLE hLock, int (*pUnlockProc) (ResLocator const *, char const *)) { char *pszResourceName = (char *) hLock; ResLocator RL; RLckGetResLocator(pszResourceName, &RL); /////////////////////////////////////////////////////////////////////////////// // Lock resources list access /////////////////////////////////////////////////////////////////////////////// if (SysLockMutex(hRLMutex, SYS_INFINITE_TIMEOUT) < 0) return (ErrGetErrorCode()); if (pUnlockProc(&RL, pszResourceName) < 0) { ErrorPush(); SysUnlockMutex(hRLMutex); SysFree(pszResourceName); return (ErrorPop()); } SysUnlockMutex(hRLMutex); SysFree(pszResourceName); return (0); } RLCK_HANDLE RLckLockEX(char const *pszResourceName) { return (RLckLock(pszResourceName, RLckTryLockEX)); } int RLckUnlockEX(RLCK_HANDLE hLock) { return (RLckUnlock(hLock, RLckDoUnlockEX)); } RLCK_HANDLE RLckLockSH(char const *pszResourceName) { return (RLckLock(pszResourceName, RLckTryLockSH)); } int RLckUnlockSH(RLCK_HANDLE hLock) { return (RLckUnlock(hLock, RLckDoUnlockSH)); }