include-afsconfig-before-param-h-20010712
[openafs.git] / src / lwp / lock.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*******************************************************************\
11 *                                                                   *
12 *       Information Technology Center                               *
13 *       Carnegie-Mellon University                                  *
14 *                                                                   *
15 *                                                                   *
16 *                                                                   *
17 \*******************************************************************/
18
19
20 /*
21         Locking routines for Vice.
22
23 */
24
25 #include <afsconfig.h>
26 #include <afs/param.h>
27
28 RCSID("$Header$");
29
30 #ifdef AFS_PTHREAD_ENV
31 #include <afs/assert.h>
32 #else /* AFS_PTHREAD_ENV */
33 #include <assert.h>
34 #endif /* AFS_PTHRED_ENV */
35 #include "lwp.h"
36 #include "lock.h"
37 #include <stdio.h>
38
39 #define FALSE   0
40 #define TRUE    1
41
42 void Lock_Init(struct Lock *lock)
43 {
44     lock -> readers_reading = 0;
45     lock -> excl_locked = 0;
46     lock -> wait_states = 0;
47     lock -> num_waiting = 0;
48 #ifdef AFS_PTHREAD_ENV
49     assert(pthread_mutex_init(&lock->mutex, (const pthread_mutexattr_t*)0)==0);
50     assert(pthread_cond_init(&lock->read_cv, (const pthread_condattr_t*)0)==0);
51     assert(pthread_cond_init(&lock->write_cv, (const pthread_condattr_t*)0)==0);
52 #endif /* AFS_PTHRED_ENV */
53 }
54
55 void Lock_Destroy(struct Lock *lock)
56 {
57 #ifdef AFS_PTHREAD_ENV
58     assert(pthread_mutex_destroy(&lock->mutex) == 0);
59     assert(pthread_cond_destroy(&lock->read_cv) == 0);
60     assert(pthread_cond_destroy(&lock->write_cv) == 0);
61 #endif /* AFS_PTHRED_ENV */
62 }
63 \f
64 void Afs_Lock_Obtain(struct Lock * lock, int how)
65 {
66     switch (how) {
67
68         case READ_LOCK:         lock->num_waiting++;
69                                 do {
70                                     lock -> wait_states |= READ_LOCK;
71 #ifdef AFS_PTHREAD_ENV
72                                     assert(pthread_cond_wait(&lock->read_cv,
73                                                 &lock->mutex) == 0);
74 #else /* AFS_PTHREAD_ENV */
75                                     LWP_WaitProcess(&lock->readers_reading);
76 #endif /* AFS_PTHREAD_ENV */
77                                 } while (lock->excl_locked & WRITE_LOCK);
78                                 lock->num_waiting--;
79                                 lock->readers_reading++;
80                                 break;
81
82         case WRITE_LOCK:        lock->num_waiting++;
83                                 do {
84                                     lock -> wait_states |= WRITE_LOCK;
85 #ifdef AFS_PTHREAD_ENV
86                                     assert(pthread_cond_wait(&lock->write_cv,
87                                                 &lock->mutex) == 0);
88 #else /* AFS_PTHREAD_ENV */
89                                     LWP_WaitProcess(&lock->excl_locked);
90 #endif /* AFS_PTHREAD_ENV */
91                                 } while (lock->excl_locked || lock->readers_reading);
92                                 lock->num_waiting--;
93                                 lock->excl_locked = WRITE_LOCK;
94                                 break;
95
96         case SHARED_LOCK:       lock->num_waiting++;
97                                 do {
98                                     lock->wait_states |= SHARED_LOCK;
99 #ifdef AFS_PTHREAD_ENV
100                                     assert(pthread_cond_wait(&lock->write_cv,
101                                                 &lock->mutex) == 0);
102 #else /* AFS_PTHREAD_ENV */
103                                     LWP_WaitProcess(&lock->excl_locked);
104 #endif /* AFS_PTHREAD_ENV */
105                                 } while (lock->excl_locked);
106                                 lock->num_waiting--;
107                                 lock->excl_locked = SHARED_LOCK;
108                                 break;
109
110         case BOOSTED_LOCK:      lock->num_waiting++;
111                                 do {
112                                     lock->wait_states |= WRITE_LOCK;
113 #ifdef AFS_PTHREAD_ENV
114                                     assert(pthread_cond_wait(&lock->write_cv,
115                                                 &lock->mutex) == 0);
116 #else /* AFS_PTHREAD_ENV */
117                                     LWP_WaitProcess(&lock->excl_locked);
118 #endif /* AFS_PTHREAD_ENV */
119                                 } while (lock->readers_reading);
120                                 lock->num_waiting--;
121                                 lock->excl_locked = WRITE_LOCK;
122                                 break;
123
124         default:                printf("Can't happen, bad LOCK type: %d\n", how);
125                                 assert(0);
126     }
127 }
128
129 /* wake up readers waiting for this lock */
130 void Afs_Lock_WakeupR(struct Lock *lock)
131 {
132     if (lock->wait_states & READ_LOCK) {
133         lock->wait_states &= ~READ_LOCK;
134 #ifdef AFS_PTHREAD_ENV
135         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
136 #else /* AFS_PTHREAD_ENV */
137         LWP_NoYieldSignal(&lock->readers_reading);
138 #endif /* AFS_PTHREAD_ENV */
139     }
140 }
141
142 /* release a lock, giving preference to new readers */
143 void Afs_Lock_ReleaseR(struct Lock *lock)
144 {
145     if (lock->wait_states & READ_LOCK) {
146         lock->wait_states &= ~READ_LOCK;
147 #ifdef AFS_PTHREAD_ENV
148         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
149 #else /* AFS_PTHREAD_ENV */
150         LWP_NoYieldSignal(&lock->readers_reading);
151 #endif /* AFS_PTHREAD_ENV */
152     }
153     else {
154         lock->wait_states &= ~EXCL_LOCKS;
155 #ifdef AFS_PTHREAD_ENV
156         assert(pthread_cond_broadcast(&lock->write_cv) == 0);
157 #else /* AFS_PTHREAD_ENV */
158         LWP_NoYieldSignal(&lock->excl_locked);
159 #endif /* AFS_PTHREAD_ENV */
160     }
161 }
162
163 /* release a lock, giving preference to new writers */
164 void Afs_Lock_ReleaseW(struct Lock * lock)
165 {
166     if (lock->wait_states & EXCL_LOCKS) {
167         lock->wait_states &= ~EXCL_LOCKS;
168 #ifdef AFS_PTHREAD_ENV
169         assert(pthread_cond_broadcast(&lock->write_cv) == 0);
170 #else /* AFS_PTHREAD_ENV */
171         LWP_NoYieldSignal(&lock->excl_locked);
172 #endif /* AFS_PTHREAD_ENV */
173     }
174     else {
175         lock->wait_states &= ~READ_LOCK;
176 #ifdef AFS_PTHREAD_ENV
177         assert(pthread_cond_broadcast(&lock->read_cv) == 0);
178 #else /* AFS_PTHREAD_ENV */
179         LWP_NoYieldSignal(&lock->readers_reading);
180 #endif /* AFS_PTHREAD_ENV */
181     }
182 }
183
184 #ifndef AFS_PTHREAD_ENV
185 /* These next guys exist to provide an interface to drop a lock atomically with
186  * blocking.  They're trivial to do in a non-preemptive LWP environment.
187  */
188
189 /* release a write lock and sleep on an address, atomically */
190 void LWP_WaitProcessR(addr, alock)
191 register char *addr;
192 register struct Lock *alock; {
193     ReleaseReadLock(alock);
194     LWP_WaitProcess(addr);
195 }
196
197 /* release a write lock and sleep on an address, atomically */
198 void LWP_WaitProcessW(addr, alock)
199 register char *addr;
200 register struct Lock *alock; {
201     ReleaseWriteLock(alock);
202     LWP_WaitProcess(addr);
203 }
204
205 /* release a write lock and sleep on an address, atomically */
206 void LWP_WaitProcessS(addr, alock)
207 register char *addr;
208 register struct Lock *alock; {
209     ReleaseSharedLock(alock);
210     LWP_WaitProcess(addr);
211 }
212 #endif /* AFS_PTHREAD_ENV */