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