NCBI C++ ToolKit
ptw32_MCS_lock.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * ptw32_MCS_lock.c
3  *
4  * Description:
5  * This translation unit implements queue-based locks.
6  *
7  * --------------------------------------------------------------------------
8  *
9  * Pthreads-win32 - POSIX Threads Library for Win32
10  * Copyright(C) 1998 John E. Bossom
11  * Copyright(C) 1999,2005 Pthreads-win32 contributors
12  *
13  * Contact Email: rpj@callisto.canberra.edu.au
14  *
15  * The current list of contributors is contained
16  * in the file CONTRIBUTORS included with the source
17  * code distribution. The list can also be seen at the
18  * following World Wide Web location:
19  * http://sources.redhat.com/pthreads-win32/contributors.html
20  *
21  * This library is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU Lesser General Public
23  * License as published by the Free Software Foundation; either
24  * version 2 of the License, or (at your option) any later version.
25  *
26  * This library is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29  * Lesser General Public License for more details.
30  *
31  * You should have received a copy of the GNU Lesser General Public
32  * License along with this library in the file COPYING.LIB;
33  * if not, write to the Free Software Foundation, Inc.,
34  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
35  */
36 
37 /*
38  * About MCS locks:
39  *
40  * MCS locks are queue-based locks, where the queue nodes are local to the
41  * thread. The 'lock' is nothing more than a global pointer that points to
42  * the last node in the queue, or is NULL if the queue is empty.
43  *
44  * Originally designed for use as spin locks requiring no kernel resources
45  * for synchronisation or blocking, the implementation below has adapted
46  * the MCS spin lock for use as a general mutex that will suspend threads
47  * when there is lock contention.
48  *
49  * Because the queue nodes are thread-local, most of the memory read/write
50  * operations required to add or remove nodes from the queue do not trigger
51  * cache-coherence updates.
52  *
53  * Like 'named' mutexes, MCS locks consume system resources transiently -
54  * they are able to acquire and free resources automatically - but MCS
55  * locks do not require any unique 'name' to identify the lock to all
56  * threads using it.
57  *
58  * Usage of MCS locks:
59  *
60  * - you need a global ptw32_mcs_lock_t instance initialised to 0 or NULL.
61  * - you need a local thread-scope ptw32_mcs_local_node_t instance, which
62  * may serve several different locks but you need at least one node for
63  * every lock held concurrently by a thread.
64  *
65  * E.g.:
66  *
67  * ptw32_mcs_lock_t lock1 = 0;
68  * ptw32_mcs_lock_t lock2 = 0;
69  *
70  * void *mythread(void *arg)
71  * {
72  * ptw32_mcs_local_node_t node;
73  *
74  * ptw32_mcs_acquire (&lock1, &node);
75  * ptw32_mcs_release (&node);
76  *
77  * ptw32_mcs_acquire (&lock2, &node);
78  * ptw32_mcs_release (&node);
79  * {
80  * ptw32_mcs_local_node_t nodex;
81  *
82  * ptw32_mcs_acquire (&lock1, &node);
83  * ptw32_mcs_acquire (&lock2, &nodex);
84  *
85  * ptw32_mcs_release (&nodex);
86  * ptw32_mcs_release (&node);
87  * }
88  * return (void *)0;
89  * }
90  */
91 
92 #if 0
93 #include "implement.h"
94 #include "pthread.h"
95 #endif
96 
98 {
99  struct ptw32_mcs_node_t_ **lock; /* ptr to tail of queue */
100  struct ptw32_mcs_node_t_ *next; /* ptr to successor in queue */
101  void *readyFlag; /* set after lock is released by predecessor */
102  void *nextFlag; /* set after 'next' ptr is set by successor */
103 };
104 
107 
108 /*
109  * ptw32_mcs_flag_set -- notify another thread about an event.
110  *
111  * Set event if an event handle has been stored in the flag, and
112  * set flag to -1 otherwise. Note that -1 cannot be a valid handle value.
113  */
114 static inline void
115 ptw32_mcs_flag_set(PVOID volatile *flag)
116 {
117  HANDLE e = (HANDLE) InterlockedCompareExchangePointer(flag, (void *) -1, (void *) 0);
118 
119  if ((HANDLE) 0 != e) {
120  /* another thread has already stored an event handle in the flag */
121  SetEvent(e);
122  }
123 }
124 
125 /*
126  * ptw32_mcs_flag_set -- wait for notification from another.
127  *
128  * Store an event handle in the flag and wait on it if the flag has not been
129  * set, and proceed without creating an event otherwise.
130  */
131 static inline void
132 ptw32_mcs_flag_wait(PVOID volatile *flag)
133 {
134  if (0 == InterlockedCompareExchangePointer(flag, 0, 0)) { /* MBR fence */
135  /* the flag is not set. create event. */
136  HANDLE e = CreateEvent(NULL, FALSE, FALSE, NULL);
137 
138  if (0 == InterlockedCompareExchangePointer(flag, (void *) e, (void *) 0)) {
139  /* stored handle in the flag. wait on it now. */
140  WaitForSingleObject(e, INFINITE);
141  }
142  CloseHandle(e);
143  }
144 }
145 
146 /*
147  * ptw32_mcs_lock_acquire -- acquire an MCS lock.
148  *
149  * See:
150  * J. M. Mellor-Crummey and M. L. Scott.
151  * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors.
152  * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991.
153  */
154 static inline void
156 {
158 
159  node->lock = lock;
160  node->nextFlag = 0;
161  node->readyFlag = 0;
162  node->next = 0; /* initially, no successor */
163 
164  /* queue for the lock */
165  pred = (ptw32_mcs_local_node_t *) InterlockedExchangePointer((void **) lock, node);
166 
167  if (0 != pred) {
168  /* the lock was not free. link behind predecessor. */
169  pred->next = node;
172  }
173 }
174 
175 /*
176  * ptw32_mcs_lock_release -- release an MCS lock.
177  *
178  * See:
179  * J. M. Mellor-Crummey and M. L. Scott.
180  * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors.
181  * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991.
182  */
183 static inline void
185 {
186  ptw32_mcs_lock_t *lock = node->lock;
187 
189  InterlockedCompareExchangePointer((void * volatile*) &node->next, 0, 0); /* MBR fence */
190 
191  if (0 == next) {
192  /* no known successor */
193  if (node == (ptw32_mcs_local_node_t *) InterlockedCompareExchangePointer((void * volatile*) lock, 0, node)) {
194  /* no successor, lock is free now */
195  return;
196  }
197 
198  /* wait for successor */
200  next = (ptw32_mcs_local_node_t *) InterlockedCompareExchangePointer((void * volatile*) &node->next, 0, 0); /* MBR fence */
201  }
202 
203  /* pass the lock */
204  ptw32_mcs_flag_set(&next->readyFlag);
205 }
206 
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
static void ptw32_mcs_flag_set(PVOID volatile *flag)
static void ptw32_mcs_flag_wait(PVOID volatile *flag)
static void ptw32_mcs_lock_release(ptw32_mcs_local_node_t *node)
struct ptw32_mcs_node_t_ * ptw32_mcs_lock_t
static void ptw32_mcs_lock_acquire(ptw32_mcs_lock_t *lock, ptw32_mcs_local_node_t *node)
#define NULL
Definition: ncbistd.hpp:225
#define HANDLE
An abstraction for a file handle.
Definition: mdb.c:383
#define FALSE
bool replacment for C indicating false.
Definition: ncbi_std.h:101
struct ptw32_mcs_node_t_ * next
struct ptw32_mcs_node_t_ ** lock
Modified on Fri Sep 20 14:58:21 2024 by modify_doxy.py rev. 669887