1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * pkix_pl_rwlock.c
6  *
7  * Read/Write Lock Functions
8  *
9  */
10 
11 #include "pkix_pl_rwlock.h"
12 
13 /* --Private-Functions-------------------------------------------- */
14 
15 static PKIX_Error *
pkix_pl_RWLock_Destroy(PKIX_PL_Object * object,void * plContext)16 pkix_pl_RWLock_Destroy(
17         PKIX_PL_Object *object,
18         void *plContext)
19 {
20         PKIX_PL_RWLock* rwlock = NULL;
21 
22         PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_Destroy");
23         PKIX_NULLCHECK_ONE(object);
24 
25         PKIX_CHECK(pkix_CheckType(object, PKIX_RWLOCK_TYPE, plContext),
26                     PKIX_OBJECTNOTRWLOCK);
27 
28         rwlock = (PKIX_PL_RWLock*) object;
29 
30         PKIX_RWLOCK_DEBUG("Calling PR_DestroyRWLock)\n");
31         PR_DestroyRWLock(rwlock->lock);
32         rwlock->lock = NULL;
33 
34 cleanup:
35 
36         PKIX_RETURN(RWLOCK);
37 }
38 
39 /*
40  * FUNCTION: pkix_pl_RWLock_RegisterSelf
41  * DESCRIPTION:
42  *  Registers PKIX_RWLOCK_TYPE and its related functions with systemClasses[]
43  * THREAD SAFETY:
44  *  Not Thread Safe - for performance and complexity reasons
45  *
46  *  Since this function is only called by PKIX_PL_Initialize, which should
47  *  only be called once, it is acceptable that this function is not
48  *  thread-safe.
49  */
50 PKIX_Error *
pkix_pl_RWLock_RegisterSelf(void * plContext)51 pkix_pl_RWLock_RegisterSelf(
52         void *plContext)
53 {
54 
55         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
56         pkix_ClassTable_Entry entry;
57 
58         PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_RegisterSelf");
59 
60         entry.description = "RWLock";
61         entry.objCounter = 0;
62         entry.typeObjectSize = sizeof(PKIX_PL_RWLock);
63         entry.destructor = pkix_pl_RWLock_Destroy;
64         entry.equalsFunction = NULL;
65         entry.hashcodeFunction = NULL;
66         entry.toStringFunction = NULL;
67         entry.comparator = NULL;
68         entry.duplicateFunction = NULL;
69 
70         systemClasses[PKIX_RWLOCK_TYPE] = entry;
71 
72         PKIX_RETURN(RWLOCK);
73 }
74 
75 /* --Public-Functions--------------------------------------------- */
76 
77 PKIX_Error *
PKIX_PL_RWLock_Create(PKIX_PL_RWLock ** pNewLock,void * plContext)78 PKIX_PL_RWLock_Create(
79         PKIX_PL_RWLock **pNewLock,
80         void *plContext)
81 {
82         PKIX_PL_RWLock *rwLock = NULL;
83 
84         PKIX_ENTER(RWLOCK, "PKIX_PL_RWLock_Create");
85         PKIX_NULLCHECK_ONE(pNewLock);
86 
87         PKIX_CHECK(PKIX_PL_Object_Alloc
88                     (PKIX_RWLOCK_TYPE,
89                     sizeof (PKIX_PL_RWLock),
90                     (PKIX_PL_Object **)&rwLock,
91                     plContext),
92                     PKIX_ERRORALLOCATINGRWLOCK);
93 
94         PKIX_RWLOCK_DEBUG("\tCalling PR_NewRWLock)\n");
95         rwLock->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "PKIX RWLock");
96 
97         if (rwLock->lock == NULL) {
98                 PKIX_DECREF(rwLock);
99                 PKIX_ERROR(PKIX_OUTOFMEMORY);
100         }
101 
102         rwLock->readCount = 0;
103         rwLock->writeLocked = PKIX_FALSE;
104 
105         *pNewLock = rwLock;
106 
107 cleanup:
108 
109         PKIX_RETURN(RWLOCK);
110 }
111 
112 PKIX_Error *
PKIX_PL_AcquireReaderLock(PKIX_PL_RWLock * lock,void * plContext)113 PKIX_PL_AcquireReaderLock(
114         PKIX_PL_RWLock *lock,
115         void *plContext)
116 {
117         PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireReaderLock");
118         PKIX_NULLCHECK_ONE(lock);
119 
120         PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Rlock)\n");
121         (void) PR_RWLock_Rlock(lock->lock);
122 
123         lock->readCount++;
124 
125         PKIX_RETURN(RWLOCK);
126 }
127 
128 PKIX_Error *
PKIX_PL_ReleaseReaderLock(PKIX_PL_RWLock * lock,void * plContext)129 PKIX_PL_ReleaseReaderLock(
130         PKIX_PL_RWLock *lock,
131         void *plContext)
132 {
133         PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseReaderLock");
134         PKIX_NULLCHECK_ONE(lock);
135 
136         PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n");
137         (void) PR_RWLock_Unlock(lock->lock);
138 
139         lock->readCount--;
140 
141         PKIX_RETURN(RWLOCK);
142 }
143 
144 PKIX_Error *
PKIX_PL_IsReaderLockHeld(PKIX_PL_RWLock * lock,PKIX_Boolean * pIsHeld,void * plContext)145 PKIX_PL_IsReaderLockHeld(
146         PKIX_PL_RWLock *lock,
147         PKIX_Boolean *pIsHeld,
148         void *plContext)
149 {
150         PKIX_ENTER(RWLOCK, "PKIX_PL_IsReaderLockHeld");
151         PKIX_NULLCHECK_TWO(lock, pIsHeld);
152 
153         *pIsHeld = (lock->readCount > 0)?PKIX_TRUE:PKIX_FALSE;
154 
155         PKIX_RETURN(RWLOCK);
156 }
157 
158 PKIX_Error *
PKIX_PL_AcquireWriterLock(PKIX_PL_RWLock * lock,void * plContext)159 PKIX_PL_AcquireWriterLock(
160         PKIX_PL_RWLock *lock,
161         void *plContext)
162 {
163         PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireWriterLock");
164         PKIX_NULLCHECK_ONE(lock);
165 
166         PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Wlock\n");
167         (void) PR_RWLock_Wlock(lock->lock);
168 
169         if (lock->readCount > 0) {
170                 PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT);
171         }
172 
173         /* We should never acquire a write lock if the lock is held */
174         lock->writeLocked = PKIX_TRUE;
175 
176 cleanup:
177 
178         PKIX_RETURN(RWLOCK);
179 }
180 
181 PKIX_Error *
PKIX_PL_ReleaseWriterLock(PKIX_PL_RWLock * lock,void * plContext)182 PKIX_PL_ReleaseWriterLock(
183         PKIX_PL_RWLock *lock,
184         void *plContext)
185 {
186         PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseWriterLock");
187         PKIX_NULLCHECK_ONE(lock);
188 
189         if (lock->readCount > 0) {
190                 PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT);
191         }
192 
193         PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n");
194         (void) PR_RWLock_Unlock(lock->lock);
195 
196         /* XXX Need to think about thread safety here */
197         /* There should be a single lock holder  */
198         lock->writeLocked = PKIX_FALSE;
199 
200 cleanup:
201 
202         PKIX_RETURN(RWLOCK);
203 }
204 
205 PKIX_Error *
PKIX_PL_IsWriterLockHeld(PKIX_PL_RWLock * lock,PKIX_Boolean * pIsHeld,void * plContext)206 PKIX_PL_IsWriterLockHeld(
207         PKIX_PL_RWLock *lock,
208         PKIX_Boolean *pIsHeld,
209         void *plContext)
210 {
211         PKIX_ENTER(RWLOCK, "PKIX_PL_IsWriterLockHeld");
212         PKIX_NULLCHECK_TWO(lock, pIsHeld);
213 
214         *pIsHeld = lock->writeLocked;
215 
216         PKIX_RETURN(RWLOCK);
217 }
218