/**************************************************************************** * * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/Listman.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.22 $ * $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 "listman.h" static BOOL bListenInited = FALSE; static struct { PLISTEN pHead; LOCK Lock; } ListenTable; static struct { CC_HLISTEN hListen; LOCK Lock; } ListenHandle; HRESULT InitListenManager() { ASSERT(bListenInited == FALSE); ListenTable.pHead = NULL; InitializeLock(&ListenTable.Lock); ListenHandle.hListen = CC_INVALID_HANDLE + 1; InitializeLock(&ListenHandle.Lock); bListenInited = TRUE; return CC_OK; } HRESULT DeInitListenManager() { PLISTEN pListen; PLISTEN pNextListen; if (bListenInited == FALSE) return CC_OK; pListen = ListenTable.pHead; while (pListen != NULL) { AcquireLock(&pListen->Lock); pNextListen = pListen->pNextInTable; FreeListen(pListen); pListen = pNextListen; } DeleteLock(&ListenHandle.Lock); DeleteLock(&ListenTable.Lock); bListenInited = FALSE; return CC_OK; } HRESULT _AddListenToTable( PLISTEN pListen) { ASSERT(pListen != NULL); ASSERT(pListen->hListen != CC_INVALID_HANDLE); ASSERT(pListen->bInTable == FALSE); AcquireLock(&ListenTable.Lock); pListen->pNextInTable = ListenTable.pHead; pListen->pPrevInTable = NULL; if (ListenTable.pHead != NULL) ListenTable.pHead->pPrevInTable = pListen; ListenTable.pHead = pListen; pListen->bInTable = TRUE; RelinquishLock(&ListenTable.Lock); return CC_OK; } HRESULT _RemoveListenFromTable( PLISTEN pListen) { CC_HLISTEN hListen; BOOL bTimedOut; ASSERT(pListen != NULL); ASSERT(pListen->bInTable == TRUE); // Caller must have a lock on the listen object; // in order to avoid deadlock, we must: // 1. unlock the listen object, // 2. lock the ListenTable, // 3. locate the listen object in the ListenTable (note that // after step 2, the listen object may be deleted from the // ListenTable by another thread), // 4. lock the listen object (someone else may have the lock) // 5. remove the listen object from the ListenTable, // 6. unlock the ListenTable // // The caller can now safely unlock and destroy the listen object, // since no other thread will be able to find the object (its been // removed from the ListenTable), and therefore no other thread will // be able to lock it. // Save the listen handle; its the only way to look up // the listen object in the ListenTable. Note that we // can't use pListen to find the listen object, since // pListen may be free'd up, and another listen object // allocated at the same address hListen = pListen->hListen; // step 1 RelinquishLock(&pListen->Lock); step2: // step 2 AcquireLock(&ListenTable.Lock); // step 3 pListen = ListenTable.pHead; while ((pListen != NULL) && (pListen->hListen != hListen)) pListen = pListen->pNextInTable; if (pListen != NULL) { // step 4 AcquireTimedLock(&pListen->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&ListenTable.Lock); Sleep(0); goto step2; } // step 5 if (pListen->pPrevInTable == NULL) ListenTable.pHead = pListen->pNextInTable; else pListen->pPrevInTable->pNextInTable = pListen->pNextInTable; if (pListen->pNextInTable != NULL) pListen->pNextInTable->pPrevInTable = pListen->pPrevInTable; pListen->pNextInTable = NULL; pListen->pPrevInTable = NULL; pListen->bInTable = FALSE; } // step 6 RelinquishLock(&ListenTable.Lock); if (pListen == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT _MakeListenHandle( PCC_HLISTEN phListen) { AcquireLock(&ListenHandle.Lock); *phListen = ListenHandle.hListen++; RelinquishLock(&ListenHandle.Lock); return CC_OK; } HRESULT AllocAndLockListen( PCC_HLISTEN phListen, PCC_ADDR pListenAddr, HQ931LISTEN hQ931Listen, PCC_ALIASNAMES pLocalAliasNames, DWORD_PTR dwListenToken, CC_LISTEN_CALLBACK ListenCallback, PPLISTEN ppListen) { HRESULT status; ASSERT(bListenInited == TRUE); // all parameters should have been validated by the caller ASSERT(phListen != NULL); ASSERT(pListenAddr != NULL); ASSERT(ListenCallback != NULL); ASSERT(ppListen != NULL); // set phListen now, in case we encounter an error *phListen = CC_INVALID_HANDLE; *ppListen = (PLISTEN)MemAlloc(sizeof(LISTEN)); if (*ppListen == NULL) return CC_NO_MEMORY; (*ppListen)->bInTable = FALSE; status = _MakeListenHandle(&(*ppListen)->hListen); if (status != CC_OK) { MemFree(*ppListen); return status; } // make a local copy of the ListenAddr (*ppListen)->ListenAddr = *pListenAddr; (*ppListen)->hQ931Listen = hQ931Listen; (*ppListen)->dwListenToken = dwListenToken; (*ppListen)->pLocalAliasNames = NULL; (*ppListen)->ListenCallback = ListenCallback; (*ppListen)->pNextInTable = NULL; (*ppListen)->pPrevInTable = NULL; (*ppListen)->pLocalAliasNames = NULL; InitializeLock(&(*ppListen)->Lock); AcquireLock(&(*ppListen)->Lock); *phListen = (*ppListen)->hListen; // make a local copy of the local alias names status = Q931CopyAliasNames(&(*ppListen)->pLocalAliasNames, pLocalAliasNames); if (status != CS_OK) { FreeListen(*ppListen); *phListen = CC_INVALID_HANDLE; return status; } // add the Listen to the Listen table status = _AddListenToTable(*ppListen); if (status != CC_OK) FreeListen(*ppListen); return status; } // Caller must have a lock on the Listen object HRESULT FreeListen( PLISTEN pListen) { CC_HLISTEN hListen; ASSERT(pListen != NULL); // caller must have a lock on the Listen object, // so there's no need to re-lock it hListen = pListen->hListen; if (pListen->bInTable == TRUE) if (_RemoveListenFromTable(pListen) == CC_BAD_PARAM) // the Listen object was deleted by another thread, // so just return CC_OK return CC_OK; if (pListen->pLocalAliasNames != NULL) Q931FreeAliasNames(pListen->pLocalAliasNames); // Since the listen object has been removed from the ListenTable, // no other thread will be able to find the listen object and obtain // a lock, so its safe to unlock the listen object and delete it here RelinquishLock(&pListen->Lock); DeleteLock(&pListen->Lock); MemFree(pListen); return CC_OK; } HRESULT LockListen( CC_HLISTEN hListen, PPLISTEN ppListen) { BOOL bTimedOut; ASSERT(hListen != CC_INVALID_HANDLE); ASSERT(ppListen != NULL); step1: AcquireLock(&ListenTable.Lock); *ppListen = ListenTable.pHead; while ((*ppListen != NULL) && ((*ppListen)->hListen != hListen)) *ppListen = (*ppListen)->pNextInTable; if (*ppListen != NULL) { AcquireTimedLock(&(*ppListen)->Lock,10,&bTimedOut); if (bTimedOut) { RelinquishLock(&ListenTable.Lock); Sleep(0); goto step1; } } RelinquishLock(&ListenTable.Lock); if (*ppListen == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT ValidateListen( CC_HLISTEN hListen) { PLISTEN pListen; ASSERT(hListen != CC_INVALID_HANDLE); AcquireLock(&ListenTable.Lock); pListen = ListenTable.pHead; while ((pListen != NULL) && (pListen->hListen != hListen)) pListen = pListen->pNextInTable; RelinquishLock(&ListenTable.Lock); if (pListen == NULL) return CC_BAD_PARAM; else return CC_OK; } HRESULT UnlockListen( PLISTEN pListen) { ASSERT(pListen != NULL); RelinquishLock(&pListen->Lock); return CC_OK; } HRESULT GetLastListenAddress( PCC_ADDR pListenAddr) { HRESULT status; PLISTEN pListen; PLISTEN pLastListen; ASSERT(pListenAddr != NULL); AcquireLock(&ListenTable.Lock); pListen = ListenTable.pHead; pLastListen = pListen; while (pListen != NULL) { if (pLastListen->hListen < pListen->hListen) pLastListen = pListen; pListen = pListen->pNextInTable; } if (pLastListen == NULL) status = CC_BAD_PARAM; else { status = CC_OK; *pListenAddr = pLastListen->ListenAddr; } RelinquishLock(&ListenTable.Lock); return status; }