?? rvmutex.c
字號:
/***********************************************************************
Filename : rvmutex.c
Description: recursive mutex functions
************************************************************************
Copyright (c) 2001 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..
RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvmutex.h"
#include "rvthread.h"
#include <string.h>
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS)
#include <errno.h>
/* See if we have a Solaris that can set a mutex's protocol or not */
static RvBool RvMutexTrySettingProtocol = RV_TRUE;
#endif
/* NOTE: all mutex functions are only callable at task level */
/* define the default attributes since they may be a structure */
static RvMutexAttr RvDefaultMutexAttr = RV_MUTEX_ATTRIBUTE_DEFAULT;
/* Lets make error codes a little easier to type */
#define RvMutexErrorCode(_e) RvErrorCode(RV_ERROR_LIBCODE_CCORE, RV_CCORE_MODULE_MUTEX, (_e))
RvStatus RvMutexInit(void)
{
return RV_OK;
}
RvStatus RvMutexEnd(void)
{
return RV_OK;
}
#if (RV_MUTEX_TYPE != RV_MUTEX_NONE)
/* Don't include any other code if type is none */
/* startcount needs to be <= a signed 32 bit number for compatability */
RVCOREAPI
RvStatus RVCALLCONV RvMutexConstruct(RvMutex *mu)
{
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS)
pthread_mutexattr_t ma;
int result;
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
pthread_mutexattr_t ma;
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
RvStatus result;
#endif
#if defined(RV_NULLCHECK)
if(mu == NULL)
return RvMutexErrorCode(RV_ERROR_NULLPTR);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS) || (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
if(pthread_mutexattr_init(&ma) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS)
/* Should allow these along with _setprioceiling and */
/* _setrobust_np to be set from config file. */
if (RvMutexTrySettingProtocol)
{
result = pthread_mutexattr_setprotocol(&ma, RvDefaultMutexAttr.protocol);
if(result != 0)
{
if (result == ENOSYS)
RvMutexTrySettingProtocol = RV_FALSE; /* Not supported - don't try anymore */
else
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
}
}
if(pthread_mutexattr_setpshared(&ma, RvDefaultMutexAttr.pshared) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
if(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
/* Linux only support one attribute */
if(pthread_mutexattr_setkind_np(&ma, PTHREAD_MUTEX_RECURSIVE_NP) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
if(pthread_mutex_init(mu, &ma) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
if(pthread_mutexattr_destroy(&ma) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif /* Solaris & Linux */
#if (RV_MUTEX_TYPE == RV_MUTEX_VXWORKS)
*mu = semMCreate(RvDefaultMutexAttr);
if(*mu == NULL)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_PSOS)
if(mu_create("rv", RvDefaultMutexAttr | MU_RECURSIVE, 0, mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_MUTEX)
*mu = CreateMutex(NULL, FALSE, NULL);
if(*mu == NULL)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_CRITICAL)
#if (_WIN32_WINNT >= 0x0500)
if(InitializeCriticalSectionAndSpinCount(mu, RvDefaultMutexAttr) != 0) /* tune spincount for MP systems */
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#else
InitializeCriticalSection(mu);
#endif
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
result = RvSemaphoreConstruct(&mu->lock, RvUint32Const(1));
if(result != RV_OK)
return result;
result = RvSemaphoreConstruct(&mu->handle, RvUint32Const(0));
if(result != RV_OK)
return result;
mu->count = RvUint32Const(0);
mu->waiters = RvUint32Const(0);
#endif
return RV_OK;
}
RVCOREAPI
RvStatus RVCALLCONV RvMutexDestruct(RvMutex *mu)
{
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
RvStatus result;
#endif
#if defined(RV_NULLCHECK)
if(mu == NULL)
return RvMutexErrorCode(RV_ERROR_NULLPTR);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS) || (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
if(pthread_mutex_destroy(mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_VXWORKS)
if(semDelete(*mu) != OK)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_PSOS)
if(mu_delete(*mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_MUTEX)
if(CloseHandle(*mu) == 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_CRITICAL)
DeleteCriticalSection(mu);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
result = RvSemaphoreDestruct(&mu->handle);
if(result != RV_OK)
return result;
result = RvSemaphoreDestruct(&mu->lock);
if(result != RV_OK)
return result;
#endif
return RV_OK;
}
/* Block until Mutex is aquired */
RVCOREAPI
RvStatus RVCALLCONV RvMutexLock(RvMutex *mu)
{
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
RvThreadId current;
#endif
#if defined(RV_NULLCHECK)
if(mu == NULL)
return RvMutexErrorCode(RV_ERROR_NULLPTR);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS) || (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
if(pthread_mutex_lock(mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_VXWORKS)
if(semTake(*mu, WAIT_FOREVER) != OK)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_PSOS)
if(mu_lock(*mu, MU_WAIT, 0) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_MUTEX)
if(WaitForSingleObject(*mu, INFINITE) != WAIT_OBJECT_0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_CRITICAL)
EnterCriticalSection(mu);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
current = RvThreadCurrentId();
RvSemaphoreWait(&mu->lock);
if(mu->count > RvUint32Const(0)) {
if (RvThreadIdEqual(mu->owner, current) == RV_FALSE) {
/* owned by someone else */
mu->waiters += RvUint32Const(1);
RvSemaphorePost(&mu->lock);
RvSemaphoreWait(&mu->handle); /* mu->lock is locked when we return */
mu->waiters -= RvUint32Const(1);
}
}
mu->owner = current;
mu->count += RvUint32Const(1);
RvSemaphorePost(&mu->lock);
#endif
return RV_OK;
}
RVCOREAPI
RvStatus RVCALLCONV RvMutexUnlock(RvMutex *mu)
{
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
RvThreadId current;
#endif
#if defined(RV_NULLCHECK)
if(mu == NULL)
return RvMutexErrorCode(RV_ERROR_NULLPTR);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_SOLARIS) || (RV_MUTEX_TYPE == RV_MUTEX_LINUX)
if(pthread_mutex_unlock(mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_VXWORKS)
if(semGive(*mu) != OK)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_PSOS)
if(mu_unlock(*mu) != 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_MUTEX)
if(ReleaseMutex(*mu) == 0)
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_WIN32_CRITICAL)
LeaveCriticalSection(mu);
#endif
#if (RV_MUTEX_TYPE == RV_MUTEX_MANUAL)
current = RvThreadCurrentId();
RvSemaphoreWait(&mu->lock);
/* Make sure unlocking thread is owner and count is not zero */
if((RvThreadIdEqual(mu->owner, current) == RV_FALSE) || (mu->count == RvUint32Const(0)))
return RvMutexErrorCode(RV_ERROR_UNKNOWN);
mu->count -= RvUint32Const(1);
if((mu->count == RvUint32Const(0)) && (mu->waiters > RvUint32Const(0))) {
/* We're giving up the lock and somebody is waiting. The waiter */
/* expects the mutex lock to be locked, so don't unlock it */
RvSemaphorePost(&mu->handle);
} else RvSemaphorePost(&mu->lock);
#endif
return RV_OK;
}
RvStatus RvMutexSetAttr(RvMutexAttr *attr)
{
if(attr != NULL) {
memcpy(&RvDefaultMutexAttr, attr, sizeof(RvDefaultMutexAttr));
}
return RV_OK;
}
#endif /* NONE */
#if defined(RV_TEST_CODE)
#include "rvstdio.h"
#include "rvmemory.h"
#define RvMutexPrintError(_r) RvPrintf("Error %d/%d/%d\n", RvErrorGetLib((_r)), RvErrorGetModule((_r)), RvErrorGetCode((_r)))
void RvMutexTestThread(RvThread *th, void *data)
{
RvMutex *mu;
RvStatus result;
mu = (RvMutex *)data;
RvPrintf("Thread started.\n");
RvPrintf("Thread: Trying to lock...\n");
result = RvMutexLock(mu);
if(result != RV_OK) {
RvPrintf("Thread Lock ");
RvMutexPrintError(result);
} else RvPrintf("Thread RvMutexLock OK\n");
RvPrintf("Thread: Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("Thread: RvMutexLock: ");
result = RvMutexLock(mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Thread: Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("Thread: RvMutexUnlock: ");
result = RvMutexUnlock(mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Thread: Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("Thread: RvMutexUnlock: ");
result = RvMutexUnlock(mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Thread exiting.\n");
}
void RvMutexTest(void)
{
RvStatus result;
RvMutex mu;
RvThread th;
/* Initialize other needed modules */
RvSemaphoreInit();
RvLockInit();
RvMemoryInit();
RvThreadInit();
RvPrintf("RvMutexInit: ");
result = RvMutexInit();
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexConstruct: ");
result = RvMutexConstruct(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexLock: ");
result = RvMutexLock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexLock: ");
result = RvMutexLock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexUnlock: ");
result = RvMutexUnlock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexUnlock: ");
result = RvMutexUnlock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
/* Check between threads */
RvPrintf("RvMutexLock: ");
result = RvMutexLock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvThreadConstruct(&th, RvMutexTestThread, &mu);
RvThreadCreate(&th);
RvThreadStart(&th);
RvPrintf("Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("RvMutexLock: ");
result = RvMutexLock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("RvMutexUnlock: ");
result = RvMutexUnlock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("RvMutexUnlock: ");
result = RvMutexUnlock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("Waiting for 5 seconds.\n");
RvThreadNanosleep(RvInt64Const(5000000000));
RvPrintf("Trying to Lock ...\n");
result = RvMutexLock(&mu);
if(result != RV_OK) {
RvPrintf(" RvMutexLock: ");
RvMutexPrintError(result);
} else RvPrintf(" RvMutexLock: OK\n");
RvPrintf("RvMutexUnlock: ");
result = RvMutexUnlock(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvThreadDestruct(&th);
RvPrintf("RvMutexDestruct: ");
result = RvMutexDestruct(&mu);
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvPrintf("RvMutexEnd: ");
result = RvMutexEnd();
if(result != RV_OK) {
RvMutexPrintError(result);
} else RvPrintf("OK\n");
RvThreadEnd();
RvMemoryEnd();
RvLockEnd();
RvSemaphoreEnd();
}
#endif /* RV_TEST_CODE */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -