/* * The contents of this file are subject to the AOLserver Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://aolserver.com/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is AOLserver Code and related documentation * distributed by AOL. * * The Initial Developer of the Original Code is America Online, * Inc. Portions created by AOL are Copyright (C) 1999 America Online, * Inc. All Rights Reserved. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License (the "GPL"), in which case the * provisions of GPL are applicable instead of those above. If you wish * to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the * License, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the License or the GPL. */ /* * mutex.c -- * * Mutex locks with metering. */ static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsthread/mutex.c,v 1.4 2003/03/07 18:08:51 vasiljevic Exp $, compiled: " __DATE__ " " __TIME__; #include "thread.h" /* * The following structure defines a mutex with * string name and lock and busy counters. */ typedef struct Mutex { void *lock; struct Mutex *nextPtr; unsigned int id; unsigned long nlock; unsigned long nbusy; char name[NS_THREAD_NAMESIZE+1]; } Mutex; #define GETMUTEX(mutex) (*(mutex)?((Mutex *)*(mutex)):GetMutex((mutex))) static Mutex *GetMutex(Ns_Mutex *mutex); static Mutex *firstMutexPtr; /* *---------------------------------------------------------------------- * Ns_MutexInit -- * * Mutex initialization, often called the first time a mutex * is locked. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_MutexInit(Ns_Mutex *mutex) { Mutex *mutexPtr; static unsigned int nextid; mutexPtr = ns_calloc(1, sizeof(Mutex)); mutexPtr->lock = NsLockAlloc(); Ns_MasterLock(); mutexPtr->nextPtr = firstMutexPtr; firstMutexPtr = mutexPtr; mutexPtr->id = nextid++; sprintf(mutexPtr->name, "mu%d", mutexPtr->id); Ns_MasterUnlock(); *mutex = (Ns_Mutex) mutexPtr; } /* *---------------------------------------------------------------------- * * Ns_MutexSetName, Ns_MutexSetName2 -- * * Update the string name of a mutex. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_MutexSetName(Ns_Mutex *mutex, char *name) { Ns_MutexSetName2(mutex, name, NULL); } void Ns_MutexSetName2(Ns_Mutex *mutex, char *prefix, char *name) { Mutex *mutexPtr = GETMUTEX(mutex); int plen, nlen; char *p; plen = strlen(prefix); if (plen > NS_THREAD_NAMESIZE) { plen = NS_THREAD_NAMESIZE; nlen = 0; } else { nlen = name ? strlen(name) : 0; if ((nlen + plen + 1) > NS_THREAD_NAMESIZE) { nlen = NS_THREAD_NAMESIZE - plen - 1; } } Ns_MasterLock(); p = strncpy(mutexPtr->name, prefix, (size_t)plen) + plen; if (nlen > 0) { *p++ = ':'; p = strncpy(p, name, (size_t)nlen) + nlen; } *p = '\0'; Ns_MasterUnlock(); } /* *---------------------------------------------------------------------- * * Ns_MutexDestroy -- * * Mutex destroy. Note this routine is not used very often * as mutexes normally exists in memory until the process exits. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_MutexDestroy(Ns_Mutex *mutex) { Mutex **mutexPtrPtr; Mutex *mutexPtr = (Mutex *) *mutex; if (mutexPtr != NULL) { NsLockFree(mutexPtr->lock); Ns_MasterLock(); mutexPtrPtr = &firstMutexPtr; while ((*mutexPtrPtr) != mutexPtr) { mutexPtrPtr = &(*mutexPtrPtr)->nextPtr; } *mutexPtrPtr = mutexPtr->nextPtr; Ns_MasterUnlock(); ns_free(mutexPtr); *mutex = NULL; } } /* *---------------------------------------------------------------------- * * Ns_MutexLock -- * * Lock a mutex, tracking the number of locks and the number of * which were not aquired immediately. * * Results: * None. * * Side effects: * Thread may be suspended if the lock is held. * *---------------------------------------------------------------------- */ void Ns_MutexLock(Ns_Mutex *mutex) { Mutex *mutexPtr = GETMUTEX(mutex); if (!NsLockTry(mutexPtr->lock)) { NsLockSet(mutexPtr->lock); ++mutexPtr->nbusy; } ++mutexPtr->nlock; } /* *---------------------------------------------------------------------- * * Ns_MutexTryLock -- * * Attempt to lock a mutex. * * Results: * NS_OK if locked, NS_TIMEOUT if lock already held. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_MutexTryLock(Ns_Mutex *mutex) { Mutex *mutexPtr = GETMUTEX(mutex); if (!NsLockTry(mutexPtr->lock)) { return NS_TIMEOUT; } ++mutexPtr->nlock; return NS_OK; } /* *---------------------------------------------------------------------- * * Ns_MutexUnlock -- * * Unlock a mutex. * * Results: * None. * * Side effects: * Other waiting thread, if any, is resumed. * *---------------------------------------------------------------------- */ void Ns_MutexUnlock(Ns_Mutex *mutex) { Mutex *mutexPtr = (Mutex *) *mutex; NsLockUnset(mutexPtr->lock); } /* *---------------------------------------------------------------------- * * Ns_MutexList -- * * Append info on each lock. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_MutexList(Tcl_DString *dsPtr) { Mutex *mutexPtr; char buf[100]; Ns_MasterLock(); mutexPtr = firstMutexPtr; while (mutexPtr != NULL) { Tcl_DStringStartSublist(dsPtr); Tcl_DStringAppendElement(dsPtr, mutexPtr->name); Tcl_DStringAppendElement(dsPtr, ""); sprintf(buf, " %d %lu %lu", mutexPtr->id, mutexPtr->nlock, mutexPtr->nbusy); Tcl_DStringAppend(dsPtr, buf, -1); Tcl_DStringEndSublist(dsPtr); mutexPtr = mutexPtr->nextPtr; } Ns_MasterUnlock(); } /* *---------------------------------------------------------------------- * * NsMutexInitNext -- * * Initialize and name the next internal mutex. * * Results: * None. * * Side effects: * Given counter is updated. * *---------------------------------------------------------------------- */ void NsMutexInitNext(Ns_Mutex *mutex, char *prefix, unsigned int *nextPtr) { unsigned int id; char buf[20]; Ns_MasterLock(); id = *nextPtr; *nextPtr = id + 1; Ns_MasterUnlock(); sprintf(buf, "ns:%s:%u", prefix, id); Ns_MutexInit(mutex); Ns_MutexSetName(mutex, buf); } /* *---------------------------------------------------------------------- * * NsGetLock -- * * Return the private lock pointer for a Ns_Mutex. * * Results: * Pointer to lock. * * Side effects: * None. * *---------------------------------------------------------------------- */ void * NsGetLock(Ns_Mutex *mutex) { Mutex *mutexPtr = GETMUTEX(mutex); return mutexPtr->lock; } /* *---------------------------------------------------------------------- * * GetMutex -- * * Cast an Ns_Mutex to a Mutex, initializing if needed. * * Results: * Pointer to Mutex. * * Side effects: * Mutex is initialized the first time. * *---------------------------------------------------------------------- */ static Mutex * GetMutex(Ns_Mutex *mutex) { Ns_MasterLock(); if (*mutex == NULL) { Ns_MutexInit(mutex); } Ns_MasterUnlock(); return (Mutex *) *mutex; }