diff options
author | aunsane <aunsane@gmail.com> | 2017-12-15 01:05:56 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2017-12-15 01:05:56 +0300 |
commit | e124aa3611f38573898aa79c6eabe77bc874e58f (patch) | |
tree | 819464260f758bbc002b23c0c8a77f93751dcb42 /libs/pthreads/src/ptw32_OLL_lock.c | |
parent | bbd9647d47f20d10b39570def918a0ac68c305c9 (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.c | 734 |
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; +} + |