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

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: spellcheck Created 6 years, 2 months 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 avoids writer starvation by preventing readers
Mark Seaborn 2014/12/01 22:33:07 You might want to comment on whether/why you want
Sam Clegg 2014/12/10 19:17:43 I added a link to the wikipedia page with more inf
11 * from acquiring the lock while there are waiting writers.
12 *
13 * The thundering herd problem is avoided by only waking a single
14 * waiter (either a single writer or a single reader) when the
15 * lock is released.
16 */
17
18 #include <assert.h>
Mark Seaborn 2014/12/01 22:33:07 Not used
Sam Clegg 2014/12/10 19:17:42 Done.
19 #include <errno.h>
20 #include <unistd.h>
21
22 #include "native_client/src/include/nacl_compiler_annotations.h"
23 #include "native_client/src/untrusted/nacl/nacl_irt.h"
24 #include "native_client/src/untrusted/pthread/pthread.h"
25 #include "native_client/src/untrusted/pthread/pthread_internal.h"
26 #include "native_client/src/untrusted/pthread/pthread_types.h"
27
28 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) {
29 attr->type = PTHREAD_PROCESS_PRIVATE;
30 return 0;
31 }
32
33 int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) {
34 return 0;
35 }
36
37 int pthread_rwlock_init(pthread_rwlock_t *rwlock,
38 const pthread_rwlockattr_t *attr) {
39 rwlock->writer_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID;
40 rwlock->writers_waiting = 0;
41 rwlock->reader_count = 0;
42 pthread_mutex_init(&rwlock->mutex, NULL);
Mark Seaborn 2014/12/01 22:33:07 You should really check for errors from all the pt
Sam Clegg 2014/12/10 19:17:42 Done.
43 pthread_cond_init(&rwlock->write_possible, NULL);
44 pthread_cond_init(&rwlock->read_possible, NULL);
45 return 0;
46 }
47
48 /**
Mark Seaborn 2014/12/01 22:33:07 Don't need "/**" here -- it's for doc comments, wh
Sam Clegg 2014/12/10 19:17:42 Done.
49 * Helper function used by waiting writers to determine if they can take
50 * the lock. The rwlock->mutex must be held when calling this function.
51 * Returns 1 if the write lock can be taken, 0 it it can't.
52 */
53 static inline int write_lock_available(pthread_rwlock_t *rwlock) {
54 /*
55 * write lock is available if there is no current writer and no current
Mark Seaborn 2014/12/01 22:33:07 Nit: capitalise as "Write"
Sam Clegg 2014/12/10 19:17:42 Done.
56 * readers.
57 */
58 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID)
59 return 0;
60 if (rwlock->reader_count > 0)
61 return 0;
62 return 1;
63 }
64
65 /**
66 * Helper function used by waiting readers to determine if they can take
67 * the lock. The rwlock->mutex must be held when calling this function.
68 * Returns 1 if the write lock can be taken, 0 it it can't.
69 */
70 static inline int read_lock_available(pthread_rwlock_t *rwlock) {
71 /*
72 * read lock is available if there is no current writer and no *waiting*
Mark Seaborn 2014/12/01 22:33:07 Capitalise as "Read" too
Sam Clegg 2014/12/10 19:17:42 Done.
73 * writers.
74 */
75 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID)
76 return 0;
77 if (rwlock->writers_waiting > 0)
78 return 0;
79 return 1;
80 }
81
82 int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
83 const struct timespec *abs_timeout) {
84 int rc = 0;
85 pthread_mutex_lock(&rwlock->mutex);
86 /*
87 * Wait repeatedly until the write preconditions are met.
88 * In theory this loop should only execute once because the preconditions
89 * should always be true when the condition is signaled.
90 */
91 while (!read_lock_available(rwlock)) {
92 rc = pthread_cond_timedwait(&rwlock->read_possible,
93 &rwlock->mutex,
94 abs_timeout);
95 if (rc != 0)
96 goto done;
97 }
98
99 /* Acquire the read lock. */
100 rwlock->reader_count++;
101 done:
102 pthread_mutex_unlock(&rwlock->mutex);
103 return rc;
104 }
105
106 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) {
107 struct timespec timeout = { 0, 0 };
Mark Seaborn 2014/12/01 22:33:07 This means a zero timeout, I think, so this won't
Sam Clegg 2014/12/10 19:17:42 Done.
108 return pthread_rwlock_timedrdlock(rwlock, &timeout);
109 }
110
111 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) {
Mark Seaborn 2014/12/01 22:33:07 You *could* merge this into rwlock_lock(), using a
Sam Clegg 2014/12/10 19:17:43 Done.
112 int rc = 0;
113 pthread_mutex_lock(&rwlock->mutex);
114 if (!read_lock_available(rwlock)) {
115 rc = EBUSY;
116 goto done;
117 }
118
119 /* Acquire the read lock. */
120 rwlock->reader_count++;
121 done:
122 pthread_mutex_unlock(&rwlock->mutex);
123 return rc;
124 }
125
126 int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
127 const struct timespec *abs_timeout) {
128 int rc = 0;
129 pthread_mutex_lock(&rwlock->mutex);
130
131 /* Wait repeatedly until the write preconditions are met */
132 while (!write_lock_available(rwlock)) {
133 /*
134 * Before waiting (and releasing the lock) we increment the
135 * waiting_writers count so the unlocking code knows to wake
136 * us first (before any waiting readers).
137 */
138 rwlock->writers_waiting++;
139 rc = pthread_cond_timedwait(&rwlock->write_possible,
140 &rwlock->mutex,
141 abs_timeout);
142 rwlock->writers_waiting--;
143 if (rc != 0)
144 goto done;
145 }
146
147 /* Acquire the write lock. */
148 rwlock->writer_thread_id = pthread_self();
149 done:
150 pthread_mutex_unlock(&rwlock->mutex);
151 return rc;
152 }
153
154 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) {
155 struct timespec timeout = { 0, 0 };
156 return pthread_rwlock_timedwrlock(rwlock, &timeout);
157 }
158
159 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) {
160 int rc = 0;
161 pthread_mutex_lock(&rwlock->mutex);
162 /* Wait until there is no writer *and* no readers. */
Mark Seaborn 2014/12/01 22:33:07 Nit: trywrlock() doesn't wait
Sam Clegg 2014/12/10 19:17:42 Done.
163 if (!write_lock_available(rwlock)) {
164 rc = EBUSY;
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);
172 return rc;
173 }
174
175 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) {
176 int rc = 0;
177 pthread_mutex_lock(&rwlock->mutex);
178
179 if (rwlock->writer_thread_id != NACL_PTHREAD_ILLEGAL_THREAD_ID) {
180 /* The write-lock is held. Ensure its us the holds it. */
Mark Seaborn 2014/12/01 22:33:07 "the" -> "that"
Sam Clegg 2014/12/10 19:17:42 Done.
181 if (rwlock->writer_thread_id != pthread_self()) {
182 rc = EPERM;
183 goto done;
184 }
185
186 /* Release write lock. */
187 rwlock->writer_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID;
188 if (rwlock->writers_waiting > 0) {
189 /* Wake a waiting writer if there is one. */
190 pthread_cond_signal(&rwlock->write_possible);
191 } else {
192 /* Otherwise wake a waiting reader. */
193 pthread_cond_signal(&rwlock->read_possible);
194 }
195 } else {
196 if (rwlock->reader_count == 0) {
197 rc = EPERM;
198 goto done;
199 }
200
201 /* Release read lock. */
202 rwlock->reader_count--;
203 if (rwlock->reader_count == 0 && rwlock->writers_waiting > 0) {
204 /* Wake a waiting writer. */
205 pthread_cond_signal(&rwlock->write_possible);
206 }
207 }
208
209 done:
210 pthread_mutex_unlock(&rwlock->mutex);
211 return rc;
212 }
213
214 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) {
Mark Seaborn 2014/12/01 22:33:07 Optional: You could check that reader_count and wr
Sam Clegg 2014/12/10 19:17:43 Done.
215 pthread_mutex_destroy(&rwlock->mutex);
216 pthread_cond_destroy(&rwlock->write_possible);
217 pthread_cond_destroy(&rwlock->read_possible);
218 return 0;
219 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698