backport to buster
[hcoop/debian/openafs.git] / src / lwp / lock.c
CommitLineData
805e021f
CE
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#include <roken.h>
29#include <afs/opr.h>
30
31#include "lwp.h"
32#include "lock.h"
33
34#define FALSE 0
35#define TRUE 1
36
37void
38Lock_Init(struct Lock *lock)
39{
40 lock->readers_reading = 0;
41 lock->excl_locked = 0;
42 lock->wait_states = 0;
43 lock->num_waiting = 0;
44#ifdef AFS_PTHREAD_ENV
45 opr_mutex_init(&lock->mutex);
46 opr_cv_init(&lock->read_cv);
47 opr_cv_init(&lock->write_cv);
48#endif /* AFS_PTHREAD_ENV */
49}
50
51void
52Lock_Destroy(struct Lock *lock)
53{
54#ifdef AFS_PTHREAD_ENV
55 opr_mutex_destroy(&lock->mutex);
56 opr_cv_destroy(&lock->read_cv);
57 opr_cv_destroy(&lock->write_cv);
58#endif /* AFS_PTHREAD_ENV */
59}
60
61void
62Afs_Lock_Obtain(struct Lock *lock, int how)
63{
64 switch (how) {
65
66 case READ_LOCK:
67 lock->num_waiting++;
68 do {
69 lock->wait_states |= READ_LOCK;
70#ifdef AFS_PTHREAD_ENV
71 opr_cv_wait(&lock->read_cv, &lock->mutex);
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:
81 lock->num_waiting++;
82 do {
83 lock->wait_states |= WRITE_LOCK;
84#ifdef AFS_PTHREAD_ENV
85 opr_cv_wait(&lock->write_cv, &lock->mutex);
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:
95 lock->num_waiting++;
96 do {
97 lock->wait_states |= SHARED_LOCK;
98#ifdef AFS_PTHREAD_ENV
99 opr_cv_wait(&lock->write_cv, &lock->mutex);
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:
109 lock->num_waiting++;
110 do {
111 lock->wait_states |= WRITE_LOCK;
112#ifdef AFS_PTHREAD_ENV
113 opr_cv_wait(&lock->write_cv, &lock->mutex);
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:
123 printf("Can't happen, bad LOCK type: %d\n", how);
124 opr_Assert(0);
125 }
126}
127
128/* wake up readers waiting for this lock */
129void
130Afs_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 opr_cv_broadcast(&lock->read_cv);
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 */
143void
144Afs_Lock_ReleaseR(struct Lock *lock)
145{
146 if (lock->wait_states & READ_LOCK) {
147 lock->wait_states &= ~READ_LOCK;
148#ifdef AFS_PTHREAD_ENV
149 opr_cv_broadcast(&lock->read_cv);
150#else /* AFS_PTHREAD_ENV */
151 LWP_NoYieldSignal(&lock->readers_reading);
152#endif /* AFS_PTHREAD_ENV */
153 } else {
154 lock->wait_states &= ~EXCL_LOCKS;
155#ifdef AFS_PTHREAD_ENV
156 opr_cv_broadcast(&lock->write_cv);
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 */
164void
165Afs_Lock_ReleaseW(struct Lock *lock)
166{
167 if (lock->wait_states & EXCL_LOCKS) {
168 lock->wait_states &= ~EXCL_LOCKS;
169#ifdef AFS_PTHREAD_ENV
170 opr_cv_broadcast(&lock->write_cv);
171#else /* AFS_PTHREAD_ENV */
172 LWP_NoYieldSignal(&lock->excl_locked);
173#endif /* AFS_PTHREAD_ENV */
174 } else {
175 lock->wait_states &= ~READ_LOCK;
176#ifdef AFS_PTHREAD_ENV
177 opr_cv_broadcast(&lock->read_cv);
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 */
190void
191LWP_WaitProcessR(void *addr, struct Lock *alock)
192{
193 ReleaseReadLock(alock);
194 LWP_WaitProcess(addr);
195}
196
197/* release a write lock and sleep on an address, atomically */
198void
199LWP_WaitProcessW(void *addr, struct Lock *alock)
200{
201 ReleaseWriteLock(alock);
202 LWP_WaitProcess(addr);
203}
204
205/* release a write lock and sleep on an address, atomically */
206void
207LWP_WaitProcessS(void *addr, struct Lock *alock)
208{
209 ReleaseSharedLock(alock);
210 LWP_WaitProcess(addr);
211}
212#endif /* AFS_PTHREAD_ENV */