semrw-posix.cpp revision 2e409a283e011f22209ad3f6009baffdbdf30539
af062818b47340eef15700d2f0211576ba3506eevboxsync/* $Id$ */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @file
af062818b47340eef15700d2f0211576ba3506eevboxsync * innotek Portable Runtime - Read-Write Semaphore, POSIX.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2006-2007 innotek GmbH
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License (GPL) as published by the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
af062818b47340eef15700d2f0211576ba3506eevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The contents of this file may alternatively be used under the terms
af062818b47340eef15700d2f0211576ba3506eevboxsync * of the Common Development and Distribution License Version 1.0
af062818b47340eef15700d2f0211576ba3506eevboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution, in which case the provisions of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * CDDL are applicable instead of those of the GPL.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync *
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * You may elect to license modified versions of this file under the
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * terms and conditions of either the GPL or the CDDL or both.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/*******************************************************************************
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync* Header Files *
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync*******************************************************************************/
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/semaphore.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/assert.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/alloc.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/asm.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/err.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <errno.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <pthread.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <unistd.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <sys/time.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "internal/magics.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/** @todo move this to r3/posix/something.h. */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#ifdef RT_OS_SOLARIS
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) ASMAtomicReadSize(pvVar, pThread)
af062818b47340eef15700d2f0211576ba3506eevboxsync# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWriteSize(pvVar, pThread)
af062818b47340eef15700d2f0211576ba3506eevboxsync#else
af062818b47340eef15700d2f0211576ba3506eevboxsyncAssertCompileSize(pthread_t, sizeof(void *));
af062818b47340eef15700d2f0211576ba3506eevboxsync# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) do { *(pThread) = (pthread_t)ASMAtomicReadPtr((void *volatile *)pvVar); } while (0)
af062818b47340eef15700d2f0211576ba3506eevboxsync# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWritePtr((void *volatile *)pvVar, (void *)pThread)
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Structures and Typedefs *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsync/** Posix internal representation of a read-write semaphore. */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstruct RTSEMRWINTERNAL
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /** The usual magic. (RTSEMRW_MAGIC) */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t u32Magic;
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Alignment padding. */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t u32Padding;
af062818b47340eef15700d2f0211576ba3506eevboxsync /** Number of write recursions. */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t cWrites;
af062818b47340eef15700d2f0211576ba3506eevboxsync /** Number of read recursions by the writer. */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t cWriterReads;
af062818b47340eef15700d2f0211576ba3506eevboxsync /** The write owner of the lock. */
af062818b47340eef15700d2f0211576ba3506eevboxsync volatile pthread_t Writer;
af062818b47340eef15700d2f0211576ba3506eevboxsync /** pthread rwlock. */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_rwlock_t RWLock;
af062818b47340eef15700d2f0211576ba3506eevboxsync};
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Allocate handle.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
af062818b47340eef15700d2f0211576ba3506eevboxsync if (pThis)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Create the rwlock.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_rwlockattr_t Attr;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pthread_rwlockattr_init(&Attr);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->u32Magic = RTSEMRW_MAGIC;
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->u32Padding = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWrites = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWriterReads = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->Writer = (pthread_t)-1;
af062818b47340eef15700d2f0211576ba3506eevboxsync *pRWSem = pThis;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync RTMemFree(pThis);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NO_MEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate input, nil handle is fine.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RWSem == NIL_RTSEMRW)
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = RWSem;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
af062818b47340eef15700d2f0211576ba3506eevboxsync VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(pThis->Writer == (pthread_t)-1);
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(!pThis->cWrites);
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(!pThis->cWriterReads);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Try destroy it.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_destroy(&pThis->RWLock);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->u32Magic++;
af062818b47340eef15700d2f0211576ba3506eevboxsync RTMemFree(pThis);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate input.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = RWSem;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
af062818b47340eef15700d2f0211576ba3506eevboxsync VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Check if it's the writer (implement write+read recursion).
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Self = pthread_self();
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Writer;
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (Writer == Self)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(pThis->cWriterReads < INT32_MAX);
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWriterReads++;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Try lock it.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cMillies == RT_INDEFINITE_WAIT)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* take rwlock */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_rdlock(&pThis->RWLock);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef RT_OS_DARWIN
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_NOT_IMPLEMENTED;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#else /* !RT_OS_DARWIN */
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Get current time and calc end of wait time.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct timespec ts = {0,0};
af062818b47340eef15700d2f0211576ba3506eevboxsync clock_gettime(CLOCK_REALTIME, &ts);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cMillies != 0)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_nsec += (cMillies % 1000) * 1000000;
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_sec += cMillies / 1000;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ts.tv_nsec >= 1000000000)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_nsec -= 1000000000;
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_sec++;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* take rwlock */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* !RT_OS_DARWIN */
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /* EINTR isn't returned by the wait functions we're using. */
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTSemRWRequestRead(RWSem, cMillies);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate input.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = RWSem;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
af062818b47340eef15700d2f0211576ba3506eevboxsync VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Check if it's the writer.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Self = pthread_self();
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Writer;
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (Writer == Self)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->cWriterReads > 0,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p\n", pThis), VERR_NOT_OWNER);
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWriterReads--;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Try unlock it.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_unlock(&pThis->RWLock);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate input.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = RWSem;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
af062818b47340eef15700d2f0211576ba3506eevboxsync VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Recursion?
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Self = pthread_self();
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Writer;
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (Writer == Self)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(pThis->cWrites < INT32_MAX);
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWrites++;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Try lock it.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cMillies == RT_INDEFINITE_WAIT)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* take rwlock */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_wrlock(&pThis->RWLock);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef RT_OS_DARWIN
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_NOT_IMPLEMENTED;
af062818b47340eef15700d2f0211576ba3506eevboxsync#else /* !RT_OS_DARWIN */
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Get current time and calc end of wait time.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct timespec ts = {0,0};
af062818b47340eef15700d2f0211576ba3506eevboxsync clock_gettime(CLOCK_REALTIME, &ts);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cMillies != 0)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_nsec += (cMillies % 1000) * 1000000;
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_sec += cMillies / 1000;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ts.tv_nsec >= 1000000000)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_nsec -= 1000000000;
af062818b47340eef15700d2f0211576ba3506eevboxsync ts.tv_sec++;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* take rwlock */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* !RT_OS_DARWIN */
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWrites = 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /* EINTR isn't returned by the wait functions we're using. */
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTSemRWRequestWrite(RWSem, cMillies);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncRTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate input.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync struct RTSEMRWINTERNAL *pThis = RWSem;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
af062818b47340eef15700d2f0211576ba3506eevboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
af062818b47340eef15700d2f0211576ba3506eevboxsync VERR_INVALID_HANDLE);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Verify ownership and implement recursion.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Self = pthread_self();
af062818b47340eef15700d2f0211576ba3506eevboxsync pthread_t Writer;
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
af062818b47340eef15700d2f0211576ba3506eevboxsync pThis->cWrites--;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (pThis->cWrites)
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertReturn(!pThis->cWriterReads, VERR_WRONG_ORDER);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Try unlock it.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pthread_rwlock_unlock(&pThis->RWLock);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
af062818b47340eef15700d2f0211576ba3506eevboxsync return RTErrConvertFromErrno(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync