Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(811)

Side by Side Diff: src/untrusted/pthread/nc_rwlock.c

Issue 623863002: Implement pthread_rwlock functions for NaCl newlib. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 /*
8 * Native Client rwlock implementation
9 *
10 * This implementation is a 'write-prefering' reader-writer lock which
Mark Seaborn 2015/01/05 16:58:53 "preferring"
Sam Clegg 2015/01/06 19:06:24 Done.
11 * avoids writer starvation by preventing readers from acquiring the lock
12 * while there are waiting writers. See:
13 * (http://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)
Mark Seaborn 2015/01/05 16:58:53 Nit: remove () brackets
Sam Clegg 2015/01/06 19:06:25 Done.
14 *
15 * The thundering herd problem is avoided by only waking a single
16 * waiter (either a single writer or a single reader) when the
17 * lock is released.
18 */
19
20 #include <errno.h>
21 #include <unistd.h>
Mark Seaborn 2015/01/05 16:58:53 Is this used?
Sam Clegg 2015/01/06 19:06:25 Done.
22
23 #include "native_client/src/include/nacl_compiler_annotations.h"
Mark Seaborn 2015/01/05 16:58:53 Is this used?
Sam Clegg 2015/01/06 19:06:24 Done.
24 #include "native_client/src/untrusted/nacl/nacl_irt.h"
Mark Seaborn 2015/01/05 16:58:53 Nit: Not used, AFAICT
Sam Clegg 2015/01/06 19:06:24 Done.
25 #include "native_client/src/untrusted/pthread/pthread.h"
26 #include "native_client/src/untrusted/pthread/pthread_internal.h"
27 #include "native_client/src/untrusted/pthread/pthread_types.h"
28
29 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) {
30 attr->type = PTHREAD_PROCESS_PRIVATE;
31 return 0;
32 }
33
34 int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) {
35 return 0;
36 }
37
38 int pthread_rwlock_init(pthread_rwlock_t *rwlock,
39 const pthread_rwlockattr_t *attr) {
40 rwlock->writer_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID;
41 rwlock->writers_waiting = 0;
42 rwlock->reader_count = 0;
43 int rc = pthread_mutex_init(&rwlock->mutex, NULL);
44 if (rc != 0)
45 return rc;
46 rc = pthread_cond_init(&rwlock->write_possible, NULL);
47 if (rc != 0)
48 return rc;
49 return pthread_cond_init(&rwlock->read_possible, NULL);
50 }
51
52 /*
53 * Helper function used by waiting writers to determine if they can take
54 * the lock. The rwlock->mutex must be held when calling this function.
55 * Returns 1 if the write lock can be taken, 0 it it can't.
Mark Seaborn 2015/01/05 16:58:53 "if it"
Sam Clegg 2015/01/06 19:06:24 Done.
56 */
57 static inline int write_lock_available(pthread_rwlock_t *rwlock) {
58 /*
59 * Write lock is available if there is no current writer and no current
60 * readers.
61 */
62 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID)
63 return 0;
64 if (rwlock->reader_count > 0)
65 return 0;
66 return 1;
67 }
68
69 /*
70 * Helper function used by waiting readers to determine if they can take
71 * the lock. The rwlock->mutex must be held when calling this function.
72 * Returns 1 if the write lock can be taken, 0 it it can't.
Mark Seaborn 2015/01/05 16:58:53 Ditto
Sam Clegg 2015/01/06 19:06:24 Done.
73 */
74 static inline int read_lock_available(pthread_rwlock_t *rwlock) {
75 /*
76 * Read lock is available if there is no current writer and no *waiting*
77 * writers.
78 */
79 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID)
80 return 0;
81 if (rwlock->writers_waiting > 0)
82 return 0;
83 return 1;
84 }
85
86 /*
87 * Internal function used to acquire the read lock.
88 * This operates is three differnet ways in order to implement the three public
Mark Seaborn 2015/01/05 16:58:53 "operates in", "different"
Sam Clegg 2015/01/06 19:06:24 Done.
89 * functions:
90 * pthread_rwlock_rdlock
91 * pthread_rwlock_tryrdlock
92 * pthread_rwlock_timedrdlock
93 */
94 static int rdlock_internal(pthread_rwlock_t *rwlock,
95 const struct timespec *abs_timeout,
96 int try_only) {
97 int rc = pthread_mutex_lock(&rwlock->mutex);
98 if (rc != 0)
99 return rc;
100
101 /*
102 * Wait repeatedly until the write preconditions are met.
103 * In theory this loop should only execute once because the preconditions
104 * should always be true when the condition is signaled.
105 */
106 while (!read_lock_available(rwlock)) {
107 if (try_only) {
108 rc = EBUSY;
109 } else if (abs_timeout != NULL) {
110 rc = pthread_cond_timedwait(&rwlock->read_possible,
111 &rwlock->mutex,
112 abs_timeout);
113
Mark Seaborn 2015/01/05 16:58:53 Remove empty line
Sam Clegg 2015/01/06 19:06:24 Done.
114 } else {
115 rc = pthread_cond_wait(&rwlock->read_possible, &rwlock->mutex);
116 }
117 if (rc != 0)
118 goto done;
119 }
120
121 /* Acquire the read lock. */
122 rwlock->reader_count++;
123 done:
124 pthread_mutex_unlock(&rwlock->mutex);
125 return rc;
126 }
127
128 /*
129 * Internal function used to acquire the write lock.
130 * This operates is three differnet ways in order to implement the three public
Mark Seaborn 2015/01/05 16:58:53 Same here
Sam Clegg 2015/01/06 19:06:24 Done.
131 * functions:
132 * pthread_rwlock_wrlock
133 * pthread_rwlock_trywrlock
134 * pthread_rwlock_timedwrlock
135 */
136 static int rwlock_internal(pthread_rwlock_t *rwlock,
137 const struct timespec *abs_timeout,
138 int try_only) {
139 int rc = pthread_mutex_lock(&rwlock->mutex);
140 if (rc != 0)
141 return rc;
142
143 /* Wait repeatedly until the write preconditions are met */
144 while (!write_lock_available(rwlock)) {
145 if (try_only) {
146 rc = EBUSY;
147 } else {
148 /*
149 * Before waiting (and releasing the lock) we increment the
150 * waiting_writers count so the unlocking code knows to wake
151 * us first (before any waiting readers).
152 */
153 rwlock->writers_waiting++;
154 if (abs_timeout) {
Mark Seaborn 2015/01/05 16:58:53 Style nit: Add "!= NULL"
Sam Clegg 2015/01/06 19:06:24 Done.
155 rc = pthread_cond_timedwait(&rwlock->write_possible,
156 &rwlock->mutex,
157 abs_timeout);
158 } else {
159 rc = pthread_cond_wait(&rwlock->write_possible,
160 &rwlock->mutex);
161 }
162 rwlock->writers_waiting--;
163 }
164 if (rc != 0)
165 goto done;
166 }
167
168 /* Acquire the write lock. */
169 rwlock->writer_thread_id = pthread_self();
170 done:
171 pthread_mutex_unlock(&rwlock->mutex);
Mark Seaborn 2015/01/05 16:58:53 You should really check the return value here too.
Sam Clegg 2015/01/06 19:06:25 Done.
172 return rc;
173 }
174
175 int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
176 const struct timespec *abs_timeout) {
177 return rdlock_internal(rwlock, abs_timeout, 0);
178 }
179
180 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) {
181 return rdlock_internal(rwlock, NULL, 0);
182 }
183
184 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) {
185 return rdlock_internal(rwlock, NULL, 1);
186 }
187
188 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) {
189 return rwlock_internal(rwlock, NULL, 0);
190 }
191
192 int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
193 const struct timespec *abs_timeout) {
194 return rwlock_internal(rwlock, abs_timeout, 0);
195 }
196
197 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) {
198 return rwlock_internal(rwlock, NULL, 1);
199 }
200
201 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) {
202 int rc = pthread_mutex_lock(&rwlock->mutex);
203 if (rc != 0)
204 return rc;
205
206 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID) {
207 /* The write lock is held. Ensure its us that holds it. */
Mark Seaborn 2015/01/05 16:58:53 "it's" "us" is vague. How about "Ensure it's the
Sam Clegg 2015/01/06 19:06:24 Done.
208 if (rwlock->writer_thread_id != pthread_self()) {
209 rc = EPERM;
210 goto done;
211 }
212
213 /* Release write lock. */
214 rwlock->writer_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID;
215 if (rwlock->writers_waiting > 0) {
216 /* Wake a waiting writer if there is one. */
217 rc = pthread_cond_signal(&rwlock->write_possible);
218 } else {
219 /* Otherwise wake a waiting reader. */
220 rc = pthread_cond_signal(&rwlock->read_possible);
221 }
222 } else {
223 if (rwlock->reader_count == 0) {
224 rc = EPERM;
225 goto done;
226 }
227
228 /* Release read lock. */
229 rwlock->reader_count--;
230 if (rwlock->reader_count == 0 && rwlock->writers_waiting > 0) {
231 /* Wake a waiting writer. */
232 rc = pthread_cond_signal(&rwlock->write_possible);
233 }
234 }
235
236 done:
237 pthread_mutex_unlock(&rwlock->mutex);
Mark Seaborn 2015/01/05 16:58:53 Ditto: check return value
Sam Clegg 2015/01/06 19:06:25 Done.
238 return rc;
239 }
240
241 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) {
242 /* Return EBUSY if anther thread hold the mutex */
Mark Seaborn 2015/01/05 16:58:53 "another", "holds". (Can you proof-read your comm
Sam Clegg 2015/01/06 19:06:24 Done.
243 int rc = pthread_mutex_trylock(&rwlock->mutex);
244 if (rc != 0) {
245 return rc;
246 }
247
248 /* Return EBUSY if there are current readers or a current writer */
249 if (rwlock->reader_count != 0) {
250 pthread_mutex_unlock(&rwlock->mutex);
251 return EBUSY;
252 }
253 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID) {
254 pthread_mutex_unlock(&rwlock->mutex);
255 return EBUSY;
256 }
257
258 int rc1 = pthread_cond_destroy(&rwlock->write_possible);
259 int rc2 = pthread_cond_destroy(&rwlock->read_possible);
260
261 /* Finally unlock the mutex and destroy it */
262 pthread_mutex_unlock(&rwlock->mutex);
263 int rc3 = pthread_mutex_destroy(&rwlock->mutex);
264 if (rc1 != 0)
265 return rc1;
266 if (rc2 != 0)
267 return rc2;
268 return rc3;
269 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698