summaryrefslogtreecommitdiff
path: root/libs/pthreads/src/ptw32_OLL_lock.c
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2017-12-15 01:05:56 +0300
committeraunsane <aunsane@gmail.com>2017-12-15 01:05:56 +0300
commite124aa3611f38573898aa79c6eabe77bc874e58f (patch)
tree819464260f758bbc002b23c0c8a77f93751dcb42 /libs/pthreads/src/ptw32_OLL_lock.c
parentbbd9647d47f20d10b39570def918a0ac68c305c9 (diff)
preparing to build tox from sources
Diffstat (limited to 'libs/pthreads/src/ptw32_OLL_lock.c')
-rw-r--r--libs/pthreads/src/ptw32_OLL_lock.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/libs/pthreads/src/ptw32_OLL_lock.c b/libs/pthreads/src/ptw32_OLL_lock.c
new file mode 100644
index 0000000000..789d0ad8c6
--- /dev/null
+++ b/libs/pthreads/src/ptw32_OLL_lock.c
@@ -0,0 +1,734 @@
+/*
+ * ptw32_OLL_lock.c
+ *
+ * Description:
+ * This translation unit implements extended reader/writer queue-based locks.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * About the OLL lock (Scalable Reader-Writer Lock):
+ *
+ * OLL locks are queue-based locks similar to the MCS queue lock, where the queue
+ * nodes are local to the thread but where reader threads can enter the critical
+ * section immediately without going through a central guard lock if there are
+ * already readers holding the lock.
+ *
+ * Covered by United States Patent Application 20100241774 (Oracle)
+ */
+
+#include "pthread.h"
+#include "sched.h"
+#include "implement.h"
+
+/*
+ * C-SNZI support
+ */
+typedef union ptw32_oll_counter_t_ ptw32_oll_counter_t;
+typedef struct ptw32_oll_snziRoot_t_ ptw32_oll_snziRoot_t;
+typedef struct ptw32_oll_snziNode_t_ ptw32_oll_snziNode_t;
+typedef union ptw32_oll_snziNodeOrRoot_t_ ptw32_oll_snziNodeOrRoot_t;
+typedef struct ptw32_oll_queryResult_t_ ptw32_oll_queryResult_t;
+typedef struct ptw32_oll_ticket_t_ ptw32_oll_ticket_t;
+typedef struct ptw32_oll_csnzi_t_ ptw32_oll_csnzi_t;
+
+enum
+{
+ ptw32_archWidth = sizeof(size_t)*8,
+ ptw32_oll_countWidth = ptw32_archWidth-2
+};
+
+#define PTW32_OLL_MAXREADERS (((size_t)2<<(ptw32_oll_countWidth-1))-1)
+
+union ptw32_oll_counter_t_
+{
+ size_t word : ptw32_archWidth;
+ struct
+ {
+ /*
+ * This needs to be a single word
+ *
+ * ------------------------------------
+ * | STATE | ROOT | COUNT (readers) |
+ * ------------------------------------
+ * 63 / 31 62 / 30 61 / 29 .. 0
+ */
+ size_t count : ptw32_oll_countWidth;
+ size_t root : 1; /* ROOT or NODE */
+ size_t state : 1; /* OPEN or CLOSED (root only) */
+ } internal;
+};
+
+struct ptw32_oll_snziRoot_t_
+{
+ /*
+ * "counter" must be at same offset in both
+ * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t
+ */
+ ptw32_oll_counter_t counter;
+};
+
+enum
+{
+ ptw32_oll_snziRoot_open = 0,
+ ptw32_oll_snziRoot_closed = 1
+};
+
+enum
+{
+ ptw32_oll_snzi_root = 0,
+ ptw32_oll_snzi_node = 1
+};
+
+/*
+ * Some common SNZI root whole-word states that can be used to set or compare
+ * root words with a single operation.
+ */
+ptw32_oll_snziRoot_t ptw32_oll_snziRoot_openAndZero = {.counter.internal.count = 0,
+ .counter.internal.root = ptw32_oll_snzi_root,
+ .counter.internal.state = ptw32_oll_snziRoot_open};
+ptw32_oll_snziRoot_t ptw32_oll_snziRoot_closedAndZero = {.counter.internal.count = 0,
+ .counter.internal.root = ptw32_oll_snzi_root,
+ .counter.internal.state = ptw32_oll_snziRoot_closed};
+
+struct ptw32_oll_queryResult_t_
+{
+ BOOL nonZero;
+ BOOL open;
+};
+
+union ptw32_oll_snziNodeOrRoot_t_
+{
+ ptw32_oll_snziRoot_t* rootPtr;
+ ptw32_oll_snziNode_t* nodePtr;
+};
+
+struct ptw32_oll_snziNode_t_
+{
+ /* "counter" must be at same offset in both
+ * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t
+ */
+ ptw32_oll_counter_t counter;
+ ptw32_oll_snziNodeOrRoot_t parentPtr;
+};
+
+struct ptw32_oll_ticket_t_
+{
+ ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot;
+};
+
+ptw32_oll_ticket_t ptw32_oll_ticket_null = {NULL};
+
+struct ptw32_oll_csnzi_t_
+{
+ ptw32_oll_snziRoot_t proxyRoot;
+ ptw32_oll_snziNode_t leafs[];
+};
+
+/*
+ * FOLL lock support
+ */
+
+typedef struct ptw32_foll_node_t_ ptw32_foll_node_t;
+typedef struct ptw32_foll_local_t_ ptw32_foll_local_t;
+typedef struct ptw32_foll_rwlock_t_ ptw32_foll_rwlock_t;
+
+enum
+{
+ ptw32_srwl_reader,
+ ptw32_srwl_writer
+};
+
+enum
+{
+ ptw32_srwl_free,
+ ptw32_srwl_in_use
+};
+
+struct ptw32_foll_node_t_
+{
+ ptw32_foll_node_t* qNextPtr;
+ ptw32_oll_csnzi_t* csnziPtr;
+ ptw32_foll_node_t* nextPtr;
+ int kind;
+ int allocState;
+ BOOL spin;
+};
+
+struct ptw32_foll_local_t_
+{
+ ptw32_foll_node_t* rNodePtr; // Default read node. Immutable
+ ptw32_foll_node_t* wNodePtr; // Write node. Immutable.
+ ptw32_foll_node_t* departFromPtr; // List node we last arrived at.
+ ptw32_oll_ticket_t ticket; // C-SNZI ticket
+};
+
+struct ptw32_foll_rwlock_t_
+{
+ ptw32_foll_node_t* tailPtr;
+ ptw32_foll_node_t* rNodesPtr; // Head of reader node
+};
+
+/*
+ * ShouldArriveAtTree() returns true if:
+ * the compare_exchange in Arrive() fails too often under read access; or
+ * ??
+ * Note that this is measured across all access to
+ * this lock, not just this attempt, so that highly
+ * read-contended locks will use C-SNZI. Lightly
+ * read-contended locks can reduce memory usage and some
+ * processing by using the root directly.
+ */
+BOOL
+ptw32_oll_ShouldArriveAtTree()
+{
+ return PTW32_FALSE;
+}
+
+size_t
+ptw32_oll_GetLeafForThread()
+{
+ return 0;
+}
+
+/*
+ * Only readers call ptw32_oll_Arrive()
+ *
+ * Checks whether the C-SNZI state is OPEN, and if so,
+ * increments the surplus of the C-SNZI by either directly
+ * arriving at the root node, or calling TreeArrive on one
+ * of the leaf nodes. Returns a ticket pointing to the node
+ * that was arrived at. If the state is CLOSED, makes no
+ * change and returns a ticket that contains no pointer.
+ */
+ptw32_oll_ticket_t
+ptw32_oll_Arrive(ptw32_oll_csnzi_t* csnzi)
+{
+ for (;;)
+ {
+ ptw32_oll_ticket_t ticket;
+ ptw32_oll_snziRoot_t oldProxy = csnzi->proxyRoot;
+ if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open)
+ {
+ ticket.snziNodeOrRoot.rootPtr = (ptw32_oll_snziRoot_t*)NULL;
+ return ticket;
+ }
+ if (!ptw32_oll_ShouldArriveAtTree())
+ {
+ ptw32_oll_snziRoot_t newProxy = oldProxy;
+ newProxy.counter.internal.count++;
+ if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&csnzi->proxyRoot.counter,
+ (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
+ (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
+ == (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
+ {
+ /* Exchange successful */
+ ticket.snziNodeOrRoot.rootPtr = &csnzi->proxyRoot;
+ return ticket;
+ }
+ }
+ else
+ {
+ ptw32_oll_snziNode_t* leafPtr = &csnzi->leafs[ptw32_oll_GetLeafForThread()];
+ ticket.snziNodeOrRoot.nodePtr = (ptw32_oll_TreeArrive(leafPtr) ? leafPtr : (ptw32_oll_snziNode_t*)NULL);
+ return ticket;
+ }
+ }
+}
+
+/*
+ * Decrements the C-SNZI surplus. Returns false iff the
+ * resulting state is CLOSED and the surplus is zero.
+ * Ticket must have been returned by an arrival. Must have
+ * received this ticket from Arrive more times than Depart
+ * has been called with the ticket. (Thus, the surplus
+ * must be greater than zero.)
+ */
+BOOL
+ptw32_oll_Depart(ptw32_oll_ticket_t ticket)
+{
+ return ptw32_oll_TreeDepart(ticket.snziNodeOrRoot);
+}
+
+/*
+ * Increments the C-SNZI surplus and returns true if the
+ * C-SNZI is open or has a surplus. Calls TreeArrive
+ * recursively on the node’s parent if needed.
+ * Otherwise, returns false without making any changes.
+ */
+BOOL
+ptw32_oll_TreeArrive(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot)
+{
+ if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root)
+ {
+ /* Non-root node */
+ ptw32_oll_counter_t newCounter, oldCounter;
+ BOOL arrivedAtParent = PTW32_FALSE;
+ do
+ {
+ oldCounter = snziNodeOrRoot.nodePtr->counter;
+ if (0 == oldCounter.internal.count && !arrivedAtParent)
+ {
+ if (ptw32_oll_TreeArrive(snziNodeOrRoot.nodePtr->parentPtr))
+ arrivedAtParent = PTW32_TRUE;
+ else
+ return PTW32_FALSE;
+ }
+ newCounter = oldCounter;
+ newCounter.internal.count++;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter,
+ (PTW32_INTERLOCKED_SIZE)newCounter.word,
+ (PTW32_INTERLOCKED_SIZE)oldCounter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldCounter.word);
+ if (newCounter.internal.count != 0 && arrivedAtParent)
+ ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr);
+ return PTW32_TRUE;
+ }
+ else
+ {
+ /* Root node */
+ ptw32_oll_snziRoot_t newRoot, oldRoot;
+ do
+ {
+ oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr;
+ if (oldRoot.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word)
+ return PTW32_FALSE;
+ newRoot = oldRoot;
+ newRoot.counter.internal.count++;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter,
+ (PTW32_INTERLOCKED_SIZE)newRoot.counter.word,
+ (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word);
+ return PTW32_TRUE;
+ }
+}
+
+/*
+ * Decrements the C-SNZI surplus, calling TreeDepart
+ * recursively on the node’s parent if needed. Returns
+ * false iff the resulting state of the C-SNZI is CLOSED
+ * and the surplus is zero. Otherwise, returns true.
+ */
+BOOL
+ptw32_oll_TreeDepart(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot)
+{
+ if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root)
+ {
+ /* Non-root node */
+ ptw32_oll_counter_t newCounter, oldCounter;
+ do
+ {
+ newCounter = oldCounter = snziNodeOrRoot.nodePtr->counter;
+ newCounter.internal.count--;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter,
+ (PTW32_INTERLOCKED_SIZE)newCounter.word,
+ (PTW32_INTERLOCKED_SIZE)oldCounter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldCounter.word);
+ return (0 == newCounter.internal.count)
+ ? ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr)
+ : PTW32_TRUE;
+ }
+ else
+ {
+ /* Root node */
+ ptw32_oll_snziRoot_t newRoot, oldRoot;
+ do
+ {
+ newRoot = oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr;
+ newRoot.counter.internal.count--;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter,
+ (PTW32_INTERLOCKED_SIZE)newRoot.counter.word,
+ (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word);
+ return (newRoot.counter.word != ptw32_oll_snziRoot_closedAndZero.counter.word);
+ }
+}
+
+/*
+ * Opens a C-SNZI object. Requires C-SNZI state to be
+ * CLOSED and the surplus to be zero.
+ */
+void
+ptw32_oll_Open(ptw32_oll_csnzi_t* csnziPtr)
+{
+ csnziPtr->proxyRoot = ptw32_oll_snziRoot_openAndZero;
+}
+
+/*
+ * Opens a C-SNZI object while atomically performing count
+ * arrivals. Requires C-SNZI state to be CLOSED and
+ * the surplus to be zero.
+ */
+void
+ptw32_oll_OpenWithArrivals(ptw32_oll_csnzi_t* csnziPtr, size_t count, BOOL close)
+{
+ csnziPtr->proxyRoot.counter.internal.count = count;
+ csnziPtr->proxyRoot.counter.internal.state = (close ? ptw32_oll_snziRoot_closed : ptw32_oll_snziRoot_open);
+}
+
+/*
+ * Closes a C-SNZI object. Returns true iff the C-SNZI
+ * state changed from OPEN to CLOSED and the surplus is
+ * zero.
+ */
+BOOL
+ptw32_oll_Close(ptw32_oll_csnzi_t* csnziPtr)
+{
+ ptw32_oll_snziRoot_t newProxy, oldProxy;
+ do
+ {
+ oldProxy = csnziPtr->proxyRoot;
+ if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open)
+ {
+ return PTW32_FALSE;
+ }
+ newProxy = oldProxy;
+ newProxy.counter.internal.state = ptw32_oll_snziRoot_closed;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter,
+ (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
+ (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word);
+ return (newProxy.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word);
+}
+
+/*
+ * Closes a C-SNZI if its surplus is zero. Otherwise, does
+ * nothing. Returns true iff C-SNZI state changed from
+ * OPEN to CLOSED.
+ */
+BOOL
+ptw32_oll_CloseIfEmpty(ptw32_oll_csnzi_t* csnziPtr)
+{
+ ptw32_oll_snziRoot_t newProxy, oldProxy;
+ do
+ {
+ oldProxy = csnziPtr->proxyRoot;
+ if (oldProxy.counter.word != ptw32_oll_snziRoot_openAndZero.counter.word)
+ {
+ return PTW32_FALSE;
+ }
+ newProxy = ptw32_oll_snziRoot_closedAndZero;
+ } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE(
+ (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter,
+ (PTW32_INTERLOCKED_SIZE)newProxy.counter.word,
+ (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word)
+ != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word);
+ return PTW32_TRUE;
+}
+
+/*
+ * Returns whether the C-SNZI has a nonzero surplus and
+ * whether the C-SNZI is open.
+ * "nonZero" doesn't appear to be used anywhere in the algorithms.
+ */
+ptw32_oll_queryResult_t
+ptw32_oll_Query(ptw32_oll_csnzi_t* csnziPtr)
+{
+ ptw32_oll_queryResult_t query;
+ ptw32_oll_snziRoot_t proxy = csnziPtr->proxyRoot;
+
+ query.nonZero = (proxy.counter.internal.count > 0);
+ query.open = (proxy.counter.internal.state == ptw32_oll_snziRoot_open);
+ return query;
+}
+
+/*
+ * Returns whether the Arrive operation that returned
+ * the ticket succeeded.
+ */
+BOOL
+ptw32_oll_Arrived(ptw32_oll_ticket_t t)
+{
+ return (t.snziNodeOrRoot.nodePtr != NULL);
+}
+
+/*
+ * Constructs and returns a ticket that can be used to
+ * depart from the root node.
+ */
+ptw32_oll_ticket_t
+ptw32_oll_DirectTicket(ptw32_oll_csnzi_t* csnziPtr)
+{
+ ptw32_oll_ticket_t ticket;
+ ticket.snziNodeOrRoot.rootPtr = &csnziPtr->proxyRoot;
+ return ticket;
+}
+
+/* Scalable RW Locks */
+
+typedef struct ptw32_srwl_rwlock_t_ ptw32_srwl_rwlock_t;
+typedef struct ptw32_srwl_node_t_ ptw32_srwl_node_t;
+typedef struct ptw32_srwl_local_t_ ptw32_srwl_local_t;
+
+enum
+{
+ ptw32_srwl_reader = 0,
+ ptw32_srwl_writer = 1
+};
+
+enum
+{
+ ptw32_srwl_free = 0,
+ ptw32_srwl_in_use = 1
+};
+
+struct ptw32_srwl_rwlock_t_
+{
+ ptw32_srwl_node_t* tailPtr;
+ ptw32_srwl_node_t* readerNodePtr;
+};
+
+struct ptw32_srwl_node_t_
+{
+ ptw32_srwl_node_t* qNextPtr;
+ ptw32_oll_csnzi_t* csnziPtr;
+ ptw32_srwl_node_t* nextReaderPtr;
+ int kind; /* ptw32_srwl_reader, ptw32_srwl_writer */
+ int allocState; /* ptw32_srwl_free, ptw32_srwl_in_use */
+ BOOL spin;
+};
+
+/*
+ * When a ptw32_srwl_local_t is instantiated the "kind" of each of
+ * rNode and wNode must be set as appropriate. This is the only
+ * time "kind" is set.
+ */
+struct ptw32_srwl_local_t_
+{
+ ptw32_srwl_node_t* rNodePtr;
+ ptw32_srwl_node_t* wNodePtr;
+ ptw32_srwl_node_t* departFromPtr;
+ ptw32_oll_ticket_t ticket;
+};
+
+/* Allocates a new reader node. */
+ptw32_srwl_node_t*
+ptw32_srwl_AllocReaderNode(ptw32_srwl_local_t* local)
+{
+ ptw32_srwl_node_t* currNodePtr = local->rNodePtr;
+ for (;;)
+ {
+ if (currNodePtr->allocState == ptw32_srwl_free)
+ {
+ if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
+ (PTW32_INTERLOCKED_LONGPTR)&currNodePtr->allocState,
+ (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use,
+ (PTW32_INTERLOCKED_LONG)ptw32_srwl_free)
+ == (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use)
+ {
+ return currNodePtr;
+ }
+ }
+ currNodePtr = currNodePtr->next;
+ }
+}
+
+/*
+ * Frees a reader node. Requires that its allocState
+ * is ptw32_srwl_in_use.
+ */
+void
+ptw32_srwl_FreeReaderNode(ptw32_srwl_node_t* nodePtr)
+{
+ nodePtr->allocState := ptw32_srwl_free;
+}
+
+void
+ptw32_srwl_WriterLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
+{
+ oldTailPtr = (ptw32_srwl_rwlock_t*)PTW32_INTERLOCKED_EXCHANGE_PTR(
+ (PTW32_INTERLOCKED_PVOID_PTR)&lockPtr->tailPtr,
+ (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr);
+ if (oldTailPtr != NULL)
+ {
+ localPtr->wNodePtr->spin := PTW32_TRUE;
+ oldTailPtr->qNextPtr = localPtr->wNodePtr;
+ if (oldTailPtr->kind == ptw32_srwl_writer)
+ {
+ while (localPtr->wNodePtr->spin);
+ }
+ else
+ {
+ /* Wait until node is properly recycled */
+ while (ptw32_oll_Query(oldTailPtr->csnzi).open);
+ /*
+ * Close C-SNZI of previous reader node.
+ * If there are no readers to signal us, spin on
+ * previous node and free it before entering
+ * critical section.
+ */
+ if (ptw32_oll_Close(oldTailPtr->csnzi))
+ {
+ while (oldTailPtr->spin);
+ ptw32_srwl_FreeReaderNode(oldTailPtr);
+ }
+ else
+ {
+ while (localPtr->wNodePtr->spin);
+ }
+ }
+ }
+}
+
+void
+ptw32_srwl_WriterUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
+{
+ if (localPtr->wNodePtr->qNextPtr == NULL)
+ {
+ if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
+ (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
+ (PTW32_INTERLOCKED_PVOID)NULL,
+ (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr)
+ == (PTW32_INTERLOCKED_PVOID)NULL)
+ {
+ return;
+ }
+ else
+ {
+ while (localPtr->wNodePtr->qNextPtr == NULL);
+ }
+ }
+ /* Clean up */
+ localPtr->wNodePtr->qNextPtr->spin = PTW32_FALSE;
+ localPtr->wNodePtr->qNextPtr = NULL;
+}
+
+void
+ptw32_srwl_ReaderLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
+{
+ ptw32_srwl_node_t* rNodePtr = NULL;
+ for (;;)
+ {
+ ptw32_srwl_node_t* tailPtr = lockPtr->tailPtr;
+ /* If no nodes are in the queue */
+ if (tailPtr == NULL)
+ {
+ if (rNodePtr == NULL)
+ {
+ rNodePtr = ptw32_srwl_AllocReaderNode(localPtr);
+ }
+ rNodePtr->spin = PTW32_FALSE;
+ if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
+ (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
+ (PTW32_INTERLOCKED_PVOID)rNodePtr,
+ (PTW32_INTERLOCKED_PVOID)NULL)
+ == (PTW32_INTERLOCKED_PVOID)rNodePtr)
+ {
+ ptw32_oll_Open(rNodePtr->csnzi);
+ localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi);
+ if (ptw32_oll_Arrived(localPtr->ticket))
+ {
+ localPtr->departFromPtr = rNodePtr;
+ return;
+ }
+ /* Avoid reusing inserted node */
+ rNodePtr = NULL;
+ }
+ }
+ /* Otherwise, there is a node in the queue */
+ else
+ {
+ /* Is last node a writer node? */
+ if (tailPtr->kind == ptw32_srwl_writer)
+ {
+ if (rNodePtr == NULL)
+ {
+ rNodePtr = ptw32_srwl_AllocReaderNode(localPtr);
+ }
+ rNodePtr->spin = PTW32_TRUE;
+ if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(
+ (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr,
+ (PTW32_INTERLOCKED_PVOID)rNodePtr,
+ (PTW32_INTERLOCKED_PVOID)tailPtr)
+ == (PTW32_INTERLOCKED_PVOID)rNodePtr)
+ {
+ tailPtr->qNextPtr = rNodePtr;
+ localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi);
+ if (ptw32_oll_Arrived(localPtr->ticket))
+ {
+ localPtr->departFromPtr = rNodePtr;
+ while (rNodePtr->spin);
+ return;
+ }
+ /* Avoid reusing inserted node */
+ rNodePtr = NULL;
+ }
+ }
+ /*
+ * Otherwise, last node is a reader node.
+ * (tailPtr->kind == ptw32_srwl_reader)
+ */
+ else
+ {
+ localPtr->ticket = ptw32_oll_Arrive(tailPtr->csnzi);
+ if (ptw32_oll_Arrived(localPtr->ticket))
+ {
+ if (rNodePtr != NULL)
+ {
+ ptw32_srwl_FreeReaderNode(rNodePtr);
+ }
+ localPtr->departFromPtr = tailPtr;
+ while (tailPtr->spin);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void
+ptw32_srwl_ReaderUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr)
+{
+ if (ptw32_oll_Depart(localPtr->departFromPtr->csnzi, localPtr->ticket))
+ {
+ return;
+ }
+ /* Clean up */
+ localPtr->departFromPtr->qNextPtr->spin = PTW32_FALSE;
+ localPtr->departFromPtr->qNextPtr = NULL;
+ ptw32_srwl_FreeReaderNode(localPtr->departFromPtr);
+}
+
+
+#include <stdio.h>
+
+int main()
+{
+ printf("%lx\n", PTW32_OLL_MAXREADERS);
+ return 0;
+}
+