/**************************************************************************** * * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/Hangman.c_v $ * * INTEL Corporation Prorietary Information * * This listing is supplied under the terms of a license agreement * with INTEL Corporation and may not be copied nor disclosed except * in accordance with the terms of that agreement. * * Copyright (c) 1993-1994 Intel Corporation. * * $Revision: 1.16 $ * $Date: 22 Jan 1997 14:55:52 $ * $Author: MANDREWS $ * * Deliverable: * * Abstract: * * * Notes: * ***************************************************************************/ #include "precomp.h" #include "apierror.h" #include "incommon.h" #include "callcont.h" #include "q931.h" #include "ccmain.h" #include "ccutils.h" #include "hangman.h" static BOOL bHangupInited = FALSE; static struct { PHANGUP pHead; LOCK Lock; } HangupTable; static struct { HHANGUP hHangup; LOCK Lock; } HangupHandle; HRESULT InitHangupManager() { ASSERT(bHangupInited == FALSE); HangupTable.pHead = NULL; InitializeLock(&HangupTable.Lock); HangupHandle.hHangup = CC_INVALID_HANDLE + 1; InitializeLock(&HangupHandle.Lock); bHangupInited = TRUE; return CC_OK; } HRESULT DeInitHangupManager() { PHANGUP pHangup; PHANGUP pNextHangup; if (bHangupInited == FALSE) return CC_OK; pHangup = HangupTable.pHead; while (pHangup != NULL) { AcquireLock(&pHangup->Lock); pNextHangup = pHangup->pNextInTable; FreeHangup(pHangup); pHangup = pNextHangup; } DeleteLock(&HangupHandle.Lock); DeleteLock(&HangupTable.Lock); bHangupInited = FALSE; return CC_OK; } HRESULT _AddHangupToTable( PHANGUP pHangup) { ASSERT(pHangup != NULL); ASSERT(pHangup->hHangup != CC_INVALID_HANDLE); ASSERT(pHangup->bInTable == FALSE); AcquireLock(&HangupTable.Lock); pHangup->pNextInTable = HangupTable.pHead; pHangup->pPrevInTable = NULL; if (HangupTable.pHead != NULL) HangupTable.pHead->pPrevInTable = pHangup; HangupTable.pHead = pHangup; pHangup->bInTable = TRUE; RelinquishLock(&HangupTable.Lock); return CC_OK; } HRESULT _RemoveHangupFromTable( PHANGUP pHangup) { HHANGUP hHangup; BOOL bTimedOut; ASSERT(pHangup != NULL); ASSERT(pHangup->bInTable == TRUE); // Caller must have a lock on the hangup object; // in order to avoid deadlock, we must: // 1. unlock the hangup object, // 2. lock the HangupTable, // 3. locate the hangup object in the HangupTable (note that // after step 2, the hangup object may be deleted from the // HangupTable by another thread), // 4. lock the hangup object (someone else may have the lock) // 5. remove the hangup object from the HangupTable, // 6. unlock the HangupTable // // The caller can now safely unlock and destroy the hangup object, // since no other thread will be able to find the object (its been // removed from the HangupTable), and therefore no other thread will // be able to lock it. // Save the hangup handle; its the only way to look up // the hangup object in the HangupTable. Note that we // can't use pHangup to find the hangup object, since // pHangup may be free'd up, and another hangup object // allocated at the same address hHangup = pHangup->hHangup; // step 1 RelinquishLock(&pHangup->Lock); step2: // step 2 AcquireLock(&HangupTable.Lock); // step 3 pHangup = HangupTable.pHead; while ((pHangup != NULL) && (pHangup->hHangup != hHangup)) pHangup = pHangup->pNextInTable; if (pHangup != NULL) { // step 4 AcquireTimedLock(&pHangup->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&HangupTable.Lock); Sleep(0); goto step2; } // step 5 if (pHangup->pPrevInTable == NULL) HangupTable.pHead = pHangup->pNextInTable; else pHangup->pPrevInTable->pNextInTable = pHangup->pNextInTable; if (pHangup->pNextInTable != NULL) pHangup->pNextInTable->pPrevInTable = pHangup->pPrevInTable; pHangup->pNextInTable = NULL; pHangup->pPrevInTable = NULL; pHangup->bInTable = FALSE; } // step 6 RelinquishLock(&HangupTable.Lock); if (pHangup == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT _MakeHangupHandle( PHHANGUP phHangup) { AcquireLock(&HangupHandle.Lock); *phHangup = HangupHandle.hHangup++; RelinquishLock(&HangupHandle.Lock); return CC_OK; } HRESULT AllocAndLockHangup( PHHANGUP phHangup, CC_HCONFERENCE hConference, DWORD_PTR dwUserToken, PPHANGUP ppHangup) { HRESULT status; ASSERT(bHangupInited == TRUE); // all parameters should have been validated by the caller ASSERT(phHangup != NULL); ASSERT(hConference != CC_INVALID_HANDLE); ASSERT(ppHangup != NULL); // set phHangup now, in case we encounter an error *phHangup = CC_INVALID_HANDLE; *ppHangup = (PHANGUP)MemAlloc(sizeof(HANGUP)); if (*ppHangup == NULL) return CC_NO_MEMORY; (*ppHangup)->bInTable = FALSE; status = _MakeHangupHandle(&(*ppHangup)->hHangup); if (status != CC_OK) { MemFree(*ppHangup); return status; } (*ppHangup)->hConference = hConference; (*ppHangup)->wNumCalls = 0; (*ppHangup)->dwUserToken = dwUserToken; (*ppHangup)->pNextInTable = NULL; (*ppHangup)->pPrevInTable = NULL; InitializeLock(&(*ppHangup)->Lock); AcquireLock(&(*ppHangup)->Lock); *phHangup = (*ppHangup)->hHangup; // add the Hangup to the Hangup table status = _AddHangupToTable(*ppHangup); if (status != CC_OK) FreeHangup(*ppHangup); return status; } // Caller must have a lock on the Hangup object HRESULT FreeHangup( PHANGUP pHangup) { HHANGUP hHangup; ASSERT(pHangup != NULL); // caller must have a lock on the Hangup object, // so there's no need to re-lock it hHangup = pHangup->hHangup; if (pHangup->bInTable == TRUE) if (_RemoveHangupFromTable(pHangup) == CC_BAD_PARAM) // the Hangup object was deleted by another thread, // so just return CC_OK return CC_OK; // Since the hangup object has been removed from the HangupTable, // no other thread will be able to find the hangup object and obtain // a lock, so its safe to unlock the hangup object and delete it here RelinquishLock(&pHangup->Lock); DeleteLock(&pHangup->Lock); MemFree(pHangup); return CC_OK; } HRESULT LockHangup( HHANGUP hHangup, PPHANGUP ppHangup) { BOOL bTimedOut; ASSERT(hHangup != CC_INVALID_HANDLE); ASSERT(ppHangup != NULL); step1: AcquireLock(&HangupTable.Lock); *ppHangup = HangupTable.pHead; while ((*ppHangup != NULL) && ((*ppHangup)->hHangup != hHangup)) *ppHangup = (*ppHangup)->pNextInTable; if (*ppHangup != NULL) { AcquireTimedLock(&(*ppHangup)->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&HangupTable.Lock); Sleep(0); goto step1; } } RelinquishLock(&HangupTable.Lock); if (*ppHangup == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT ValidateHangup( HHANGUP hHangup) { PHANGUP pHangup; ASSERT(hHangup != CC_INVALID_HANDLE); AcquireLock(&HangupTable.Lock); pHangup = HangupTable.pHead; while ((pHangup != NULL) && (pHangup->hHangup != hHangup)) pHangup = pHangup->pNextInTable; RelinquishLock(&HangupTable.Lock); if (pHangup == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT UnlockHangup( PHANGUP pHangup) { ASSERT(pHangup != NULL); RelinquishLock(&pHangup->Lock); return CC_OK; }