semsrw-generic.cpp revision 881b5ff6bc55e1fb0f4ef42f9782ccec79c0a138
/* $Id$ */
/** @file
* InnoTek Portable Runtime - Read-Write Semaphore, Generic.
*
* This is a generic implementation for OSes which don't have
* native RW semaphores.
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/** @todo fix generic RW sems. (reimplement) */
#define USE_CRIT_SECT
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/semaphore.h>
#ifdef USE_CRIT_SECT
#include <iprt/critsect.h>
#endif
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** Internal representation of a Read-Write semaphore for the
* Generic implementation. */
struct RTSEMRWINTERNAL
{
#ifdef USE_CRIT_SECT
/** Critical section. */
#else
/** Magic (RTSEMRW_MAGIC). */
/** This critical section serializes the access to and updating of the structure members. */
/** The current number of readers. */
/** The number of readers waiting. */
/** The current number of waiting writers. */
/** The handle of the event object on which the waiting readers block. (manual reset). */
/** The handle of the event object on which the waiting writers block. (manual reset). */
/** The current state of the read-write lock. */
#endif
};
/**
* Validate a read-write semaphore handle passed to one of the interface.
*
* @returns true if valid.
* @returns false if invalid.
* @param pIntRWSem Pointer to the read-write semaphore to validate.
*/
{
return false;
#ifdef USE_CRIT_SECT
return false;
#else
return false;
#endif
return true;
}
{
int rc;
/*
* Allocate memory.
*/
struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
if (pIntRWSem)
{
#ifdef USE_CRIT_SECT
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
#else
/*
* Create the semaphores.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/*
* Signal the read semaphore and initialize other variables.
*/
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
#endif
}
else
rc = VERR_NO_MEMORY;
return rc;
}
{
/*
* Validate handle.
*/
if (!rtsemRWValid(RWSem))
{
return VERR_INVALID_HANDLE;
}
#ifdef USE_CRIT_SECT
if (RT_SUCCESS(rc))
return rc;
#else
/*
* Check if busy.
*/
if (RT_SUCCESS(rc))
{
{
/*
* Make it invalid and unusable.
*/
/*
* Do actual cleanup.
* None of these can now fail excep for the mutex which
* can be a little bit busy.
*/
for (unsigned i = 32; i > 0; i--)
{
if (RT_SUCCESS(rc))
break;
RTThreadSleep(1);
}
rc = VINF_SUCCESS;
}
else
{
rc = VERR_SEM_BUSY;
}
}
else
return VINF_SUCCESS;
#endif
}
{
/*
* Validate handle.
*/
if (!rtsemRWValid(RWSem))
{
return VERR_INVALID_HANDLE;
}
#ifdef USE_CRIT_SECT
#else
/*
* Take mutex and check if already reader.
*/
//RTTHREAD Self = RTThreadSelf();
unsigned cMilliesInitial = cMillies;
if (cMillies != RTSEM_INDEFINITE_WAIT)
tsStart = RTTimeNanoTS();
if (RT_FAILURE(rc))
{
return rc;
}
while (i-- > 0)
{
{
else
{
AssertMsgFailed(("Too many requests for one thread!\n"));
return VERR_TOO_MANY_SEM_REQUESTS;
}
}
}
for (;;)
{
/*
* Check if the stat of the affairs allow read access.
*/
{
{
{
/*
* Add ourselves to the list of readers and return.
*/
return VINF_SUCCESS;
}
else
{
AssertMsgFailed(("Too many readers! How come we have so many threads!?!\n"));
}
}
#if 0 /* any action here shouldn't be necessary */
else
{
}
#endif
}
else
if (RT_FAILURE(rc))
break;
/*
* Wait till it's ready for reading.
*/
if (cMillies != RTSEM_INDEFINITE_WAIT)
{
if (tsDelta >= 1000000)
{
if (cMillies > cMilliesInitial)
}
}
if (RT_FAILURE(rc))
{
break;
}
/*
* Get Mutex.
*/
if (RT_FAILURE(rc))
{
break;
}
}
return rc;
#endif
}
{
}
{
/*
* Validate handle.
*/
if (!rtsemRWValid(RWSem))
{
return VERR_INVALID_HANDLE;
}
#ifdef USE_CRIT_SECT
#else
/*
* Take Mutex.
*/
//RTTHREAD Self = RTThreadSelf();
if (RT_SUCCESS(rc))
{
while (i-- > 0)
{
{
AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n"));
{
/* Kick off writers? */
{
}
}
else
return VINF_SUCCESS;
}
}
rc = VERR_NOT_OWNER;
}
else
return rc;
#endif
}
{
/*
* Validate handle.
*/
if (!rtsemRWValid(RWSem))
{
return VERR_INVALID_HANDLE;
}
#ifdef USE_CRIT_SECT
#else
/*
* Get Mutex.
*/
//RTTHREAD Self = RTThreadSelf();
unsigned cMilliesInitial = cMillies;
if (cMillies != RTSEM_INDEFINITE_WAIT)
tsStart = RTTimeNanoTS();
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Check that we're not a reader.
*/
while (i-- > 0)
{
{
return VERR_DEADLOCK;
}
}
/*
* Reset the reader event semaphore and increment number of readers.
*/
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Wait while there are other threads owning this sem.
*/
{
("The lock is write owned by there is only one waiter...\n"));
/*
* Release the mutex and wait on the writer semaphore.
*/
if (RT_FAILURE(rc))
{
return VERR_SEM_DESTROYED;
}
/*
* Wait.
*/
if (cMillies != RTSEM_INDEFINITE_WAIT)
{
if (tsDelta >= 1000000)
{
if (cMillies > cMilliesInitial)
}
}
/*
* Check that the semaphore wasn't destroyed while we waited.
*/
if ( rc == VERR_SEM_DESTROYED
return VERR_SEM_DESTROYED;
/*
* Attempt take the mutex.
*/
{
if (RT_SUCCESS(rc))
else
/*
* Remove our selves from the writers queue.
*/
/** @todo write an atomic dec function! (it's too late for that kind of stuff tonight) */
if (RT_SUCCESS(rc2))
return rc;
}
AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("We woke up an there is owner! %#x\n", pIntRWSem->WROwner));
}
/*
* If we get here we own the mutex and we are ready to take
* the read-write ownership.
*/
return VINF_SUCCESS;
#endif
}
{
}
{
/*
* Validate handle.
*/
if (!rtsemRWValid(RWSem))
{
return VERR_INVALID_HANDLE;
}
#ifdef USE_CRIT_SECT
#else
/*
* Check if owner.
*/
//RTTHREAD Self = RTThreadSelf();
{
return VERR_NOT_OWNER;
}
/*
* Request the mutex.
*/
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Release ownership and remove ourselves from the writers count.
*/
/*
* Release the readers if no more writers.
*/
{
AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); NOREF(rc);
}
AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); NOREF(rc);
return VINF_SUCCESS;
#endif
}