$Header: /cvsroot/aolserver/aolserver.com/docs/devel/c/index.html,v 1.1 2002/03/07 19:15:35 kriston Exp $
int Ns_AbsTimedWaitForEvent (
Ns_Cond* event,
Ns_Mutex* lock,
time_t abstime
);
int Ns_AllocThreadLocalStorage(
Ns_ThreadLocalStorage * tls,
void (*destructor) (void *)
);
Thread local storage is often used to store data which must be shared between unrelated functions much like global variables are used in a single threaded program. Thread local storage is also often used to provide buffer space unique to each thread when making older code thread safe.
static Ns_ThreadLocalStorage tls;
void
Init(void)
{
/* This function is called once at startup. */
Ns_AllocThreadLocalStorage(&tls, Ns_Free);
}
char *
GetBuffer
{
void *ptr;
Ns_GetThreadLocalStorage(&tls, &ptr);
if (ptr == NULL) {
/* Allocate a buffer for this thread. */
ptr = Ns_Malloc(BUFFER_SIZE);
Ns_SetThreadLocalStorage(&tls, ptr);
}
return (char *) ptr;
}
int Ns_BeginDetachedThread(
Ns_ThreadProc *start_routine,
void *arg
);
static void
ThreadStart(void *arg)
{
int n;
n = (int) arg;
Ns_Log(Notice, "%d: %d", Ns_GetThreadId(), n);
}
/*
* ManyThreads - Create 10 threads which all log a message.
*/
static void
ManyThreads(void)
{
int i;
for (i = 0; i < 10; ++i) {
Ns_BeginDetachedThread(ThreadStart, (void *) i);
}
}
int Ns_BeginThread(
Ns_ThreadProc *start_routine,
void *arg,
Ns_Thread *thread
);
Ns_ThreadCreate is the preferred function to start a thread.
static void
ThreadStart(void *arg)
{
int n;
n = (int) arg;
Ns_Log(Notice, "%d: %d", Ns_GetThreadId(), n);
}
/*
* ManyThreadWait - Create 10 threads which all log a message
* and wait for all of them to exit.
*/
static void
ManyThreadWait(void)
{
int i;
Ns_Thread tids[10];
for (i = 0; i < 10; ++i) {
Ns_BeginThread(ThreadStart, (void *) i, &tids[i]);
}
for (i = 0; i < 10; ++i) {
Ns_WaitForThread(&tids[i]);
}
}
int Ns_BroadcastEvent(
Ns_Event * event
);
static Ns_Event myev;
static Ns_Mutex mylock;
void
Init(void)
{
/* Initialize the lock and event at startup. */
Ns_InitializeMutex(&mylock);
Ns_InitializeEvent(&myev);
}
/* Lock the mutex and wait for the event. */
void
WaitFunc(void)
{
Ns_LockMutex(&mylock);
Ns_WaitForEvent(&myev, &mylock);
}
/* Wake up any waiting threads. */
void
BroadcastFunc(void)
{
Ns_BroadcastEvent(&myev);
}
void Ns_CacheBroadcast (
Ns_Cache* cache
);
Ns_Cache* Ns_CacheCreate (
char* name,
int keys,
time_t timeout,
Ns_Callback* freeProc
);
For a good example of how to use the Ns_Cache* functions, look at nsd/fastpath.c.
Ns_Entry* Ns_CacheCreateEntry (
Ns_Cache* cache,
char* key,
int* pnew
);
Ns_Cache* Ns_CacheCreateSz (
char* name,
int keys,
size_t maxsize,
Ns_Callback* freeProc
);
void Ns_CacheDeleteEntry (
Ns_Entry* entry
);
Ns_Cache* Ns_CacheFind (
char* name
);
Ns_Entry* Ns_CacheFindEntry (
Ns_Cache* cache,
char* key
);
Ns_Entry* Ns_CacheFirstEntry (
Ns_Cache* cache,
Ns_CacheSearch* searchPtr
);
void Ns_CacheFlush (
Ns_Cache* cache
);
void Ns_CacheFlushEntry (
Ns_Entry* entry
);
void Ns_CacheFree (
Ns_Cache* cache,
void* memPtr
);
void* Ns_CacheGetValue (
Ns_Entry* entry
);
char* Ns_CacheKey (
Ns_Entry* entry
);
void Ns_CacheLock (
Ns_Cache* cache
);
void* Ns_CacheMalloc (
Ns_Cache* cache,
size_t len
);
char* Ns_CacheName (
Ns_Entry* entry
);
Ns_Entry* Ns_CacheNextEntry (
Ns_CacheSearch* searchPtr
);
void Ns_CacheSetValue (
Ns_Entry* entry,
void* value
);
void Ns_CacheSetValueSz (
Ns_Entry* entry,
void* value,
size_t size
);
void Ns_CacheSignal (
Ns_Cache* cache
);
Note: Consider waking all threads with Ns_CacheBroadcast, instead.
void* Ns_CacheTimedGetValue (
Ns_Cache* cache,
char* key,
Ns_Time* timePtr,
int* condPtr
);
int Ns_CacheTimedWait (
Ns_Cache* cache,
Ns_Time* timePtr
);
void Ns_CacheUnlock (
Ns_Cache* cache
);
void Ns_CacheUnsetValue (
Ns_Entry* entry
);
void Ns_CacheWait (
Ns_Cache* cache
);
void Ns_CondBroadcast (
Ns_Cond*
);
void Ns_CondDestroy (
Ns_Cond *condPtr
);
void Ns_CondInit (
Ns_Cond *condPtr
);
void Ns_CondSignal (
Ns_Cond *condPtr
);
int Ns_CondTimedWait (
Ns_Cond *condPtr ,
Ns_Mutex *mutexPtr ,
Ns_Time *timePtr
);
void Ns_CondWait (
Ns_Cond *condPtr ,
Ns_Mutex *mutexPtr
);
void Ns_CsDestroy(
Ns_Cs*
);
void Ns_CsEnter(
Ns_Cs *csPtr
);
void Ns_CsInit(
Ns_Cs *csPtr
);
void Ns_CsLeave(
Ns_Cs *csPtr
);
int Ns_DestroyCriticalSection(
Ns_CriticalSection * section
);
Ns_CsDestroy is the preferred function for freeing a critical section's resources.
int Ns_DestroyEvent(
Ns_Event * event
);
int Ns_DestroyMutex(
Ns_Mutex * mutex
);
Ns_MutexDestroy is the preferred function for freeing a mutex's resources.
int Ns_DestroyRWLock(
Ns_RWLock *lock
);
For general information about read/write locks and an example showing the use of the read/write lock functions, see the Ns_InitializeRWLock function.
Ns_RWLockDestroy is the preferred function for destroying a read/write lock.
int Ns_DestroySemaphore(
Ns_Semaphore * sema
);
Ns_SemaDestroy is the preferred function for freeing a semaphore's resources.
int Ns_EnterCriticalSection(
Ns_CriticalSection * section
);
Ns_CsEnter is the preferred function for entering a critical section.
void Ns_ExitThread (
int retcode
);
Ns_ThreadExit is the preferred function for freeing a thread.
void Ns_GetThread(
Ns_Thread *thread
);
int Ns_GetThreadId(void);
int Ns_GetThreadLocalStorage(
Ns_ThreadLocalStorage * tls,
void **p
);
Ns_TlsGet is the preferred function for getting thread local storage.
int Ns_InitializeCriticalSection(
Ns_CriticalSection * section
);
Ns_CsInit is the preferred function for initializing a critical section.
int Ns_InitializeEvent(
Ns_Event * event
);
int Ns_InitializeMutex(
Ns_Mutex * mutex
);
Ns_MutexInit is the preferred function for initializing a mutex.
int Ns_InitializeRWLock(
Ns_RWLock *lock
);
About Read/Write Locks Read/write locks are a serialization mechanism for using data structures where multiple reads can happen simultaneously, but where writes must happen singly. For example, suppose you have a hash table that is heavily used but doesn't change very often. You'd like to have multiple threads be able to read from the table without blocking on each other, but when you need to update the table, you can do so safely without having to worry about other threads reading incorrect data.
The principal feature of read/write locks is the mechanism of which locks have priority and which locks must wait. Any number of read locks can be pending. If there's a write lock active, the read lock acquisition blocks until the write lock is released. Also, only one write lock can be in effect. If there are pending read locks active, the write lock acquisition blocks until all of the read locks drain. If a subsequent read lock acquisition attempt is made while a write lock is waiting to acquire, the write lock has priority.
Ns_RWLockInit is the preferred function for initializing a read/write lock.
NS_RWLock lock;
int GetData (int key)
{
/* acquire a read lock */
Ns_ReadLockRWLock (&lock);
search through the data structure looking for key's data;
/* release our read lock */
Ns_ReadUnlockRWLock (&lock);
return (value);
} /* GetData */
int StoreData (int key, int value)
{
/* acquire the write lock */
Ns_WriteLockRWLock (&lock);
manipulate the data structure storing key's value;
/* release the write lock */
Ns_WriteUnlockRWLock (&lock);
return (value);
} /* StoreData */
...
Ns_InitializeRWLock (&lock);
...
(different threads using GetData and StoreData)
...
Ns_DestoryRWLock (&lock);
int Ns_InitializeSemaphore(
Ns_Semaphore * sema,
int beg_count
);
Ns_SemaInit is the preferred function for initializing a semaphore.
int Ns_LeaveCriticalSection(
Ns_CriticalSection * section
);
Ns_CsLeave is the preferred function for leaving a critical section.
int Ns_LockMutex(
Ns_Mutex * mutex
);
void Ns_MutexDestroy (
Ns_Mutex *mutexPtr
);
void Ns_MutexInit (
Ns_Mutex *mutexPtr
);
void Ns_MutexLock (
Ns_Mutex *mutexPtr
);
void Ns_MutexUnlock (
Ns_Mutex *mutexPtr
);
int Ns_ReadLockRWLock(
Ns_RWLock *lock
);
For general information about read/write locks and an example showing the use of the read/write lock functions, see the Ns_InitializeRWLock function.
Ns_RWLockRdLock is the preferred function for acquiring a read lock.
int Ns_ReadUnlockRWLock(
Ns_RWLock *lock
);
For general information about read/write locks and an example showing the use of the read/write lock functions, see the Ns_InitializeRWLock function.
Ns_RWLockUnlock is the preferred function for releasing a lock.
int Ns_ReleaseSemaphore(
Ns_Semaphore * sema,
int count
);
Ns_SemaPost is the preferred function for incrementing the semaphore count.
void Ns_RWLockDestroy (
Ns_RWLock*
);
void Ns_RWLockInit (
Ns_RWLock*
);
About Read/Write Locks Read/write locks are a serialization mechanism for using data structures where multiple reads can happen simultaneously, but where writes must happen singly. For example, suppose you have a hash table that is heavily used but doesn't change very often. You'd like to have multiple threads be able to read from the table without blocking on each other, but when you need to update the table, you can do so safely without having to worry about other threads reading incorrect data.
The principal feature of read/write locks is the mechanism of which locks have priority and which locks must wait. Any number of read locks can be pending. If there's a write lock active, the read lock acquisition blocks until the write lock is released. Also, only one write lock can be in effect. If there are pending read locks active, the write lock acquisition blocks until all of the read locks drain. If a subsequent read lock acquisition attempt is made while a write lock is waiting to acquire, the write lock has priority.
void Ns_RWLockRdLock (
Ns_RWLock *lockPtr
);
void Ns_RWLockUnlock (
Ns_RWLock *lockPtr
);
void Ns_RWLockWrLock (
Ns_RWLock *lockPtr
);
int Ns_SemaDestroy(
Ns_Sema*
);
int Ns_SemaInit(
Ns_Sema* ,
int count
);
int Ns_SemaPost(
Ns_Sema* ,
int count
);
int Ns_SemaWait(
Ns_Sema*
);
int Ns_SetThreadLocalStorage(
Ns_ThreadLocalStorage * tls,
void *p
);
See the example for Ns_AllocThreadLocalStorage.Ns_TlsSet is the preferred function for setting thread local storage.
void Ns_ThreadCreate (
Ns_ThreadProc* proc,
void* arg,
long stackSize,
Ns_Thread* threadPtr
);
void Ns_ThreadExit (
int exitCode
);
void Ns_ThreadFree (
void* ptr
);
char* Ns_ThreadGetName (void);
int Ns_ThreadId (void);
void Ns_ThreadJoin (
Ns_Thread* threadPtr,
int* exitCodePtr
);
void* Ns_ThreadMalloc (
unsigned int size
);
Ns_Pool* Ns_ThreadPool (void);
void* Ns_ThreadRealloc (
void* ptr,
unsigned int size
);
void Ns_ThreadSelf (
Ns_Thread* threadPtr
);
void Ns_ThreadSetName (
char* name
);
void Ns_ThreadYield(void);
int Ns_TimedWaitForEvent(
Ns_Event * event,
Ns_Mutex * lock,
int usec
);
Ns_LockMutex(&lock);
if (!ready) {
result = Ns_TimedWaitForEvent(&ev, &lock, 10);
if (result == NS_TIMEOUT) {
... handle timeout ...
} else if (result != NS_OK) {
... handle error ...
}
}
Ns_UnlockMutex(&lock);
void Ns_TlsAlloc (
Ns_Tls* ,
Ns_TlsCleanup*
);
This function is a renamed version of Ns_AllocThreadLocalStorage.
void* Ns_TlsGet (
Ns_Tls *tlsPtr
);
void Ns_TlsSet (
Ns_Tls *tlsPtr ,
void *value
);
int Ns_UnlockMutex(
Ns_Mutex * mutex
);
Ns_MutexLock is the preferred function for unlocking a mutex.
See the example for Ns_LockMutex.
int Ns_UTimedWaitForEvent(
Ns_Event *event,
Ns_Mutex *lock,
int seconds,
int microseconds
);
On the Irix platform, the timeout granularity is still in seconds. In this case, if you specify a timeout of less than one second, it will be treated as one second.
int Ns_WaitForEvent(
Ns_Event * event,
Ns_Mutex * lock
);
static int ready = 0;
static Ns_Event ev;
static Ns_Mutex lock;
void
Init(void)
{
Ns_InitializeMutex(&lock);
Ns_InitializeEvent(&ev);
}
void
Waiter(void)
{
Ns_LockMutex(&lock);
if (!ready) {
Ns_WaitForEvent(&ev, &lock);
}
Ns_UnlockMutex(&lock);
... resource ready ...
}
int Ns_WaitForSemaphore(
Ns_Semaphore * sema
);
Ns_SemaWait is the preferred function for waiting for a semaphore.
static Ns_Semaphore sem;
void
Init(void)
{
Ns_InitializeSemaphore(&sem, 0);
}
void
Waiter(void)
{
Ns_WaitForSemaphore(&sem);
... access resource ...
}
void
Releaser(void)
{
Ns_ReleaseSemaphore(&sem, 1);
}
int Ns_WaitForThread(
Ns_Thread *thread
);
See the example for Ns_BeginThread.
int Ns_WaitThread (
Ns_Thread* thread,
int* retcode
);
int Ns_WriteLockRWLock(
Ns_RWLock *lock
);
For general information about read/write locks and an example showing the use of the read/write lock functions, see the Ns_InitializeRWLock function.
Ns_RWLockWrLock is the preferred function for acquiring a write lock.
int Ns_WriteUnlockRWLock(
Ns_RWLock *lock
);
For general information about read/write locks and an example showing the use of the read/write lock functions, see the Ns_InitializeRWLock function.
Ns_RWLockUnlock is the preferred function for releasing a lock.