Adjust for __pthread_lock interface change. Use already computed self
[kopensolaris-gnu/glibc.git] / linuxthreads / rwlock.c
1 /* Read-write lock implementation.
2    Copyright (C) 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Xavier Leroy <Xavier.Leroy@inria.fr>
5    and Ulrich Drepper <drepper@cygnus.com>, 1998.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Library General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Library General Public License for more details.
16
17    You should have received a copy of the GNU Library General Public
18    License along with the GNU C Library; see the file COPYING.LIB.  If not,
19    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include <errno.h>
23 #include <pthread.h>
24 #include "internals.h"
25 #include "queue.h"
26 #include "restart.h"
27 #include "spinlock.h"
28
29 int
30 pthread_rwlock_init (pthread_rwlock_t *rwlock,
31                      const pthread_rwlockattr_t *attr)
32 {
33   __pthread_init_lock(&rwlock->__rw_lock);
34   rwlock->__rw_readers = 0;
35   rwlock->__rw_writer = NULL;
36   rwlock->__rw_read_waiting = NULL;
37   rwlock->__rw_write_waiting = NULL;
38
39   if (attr == NULL)
40     {
41       rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
42       rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE;
43     }
44   else
45     {
46       rwlock->__rw_kind = attr->__lockkind;
47       rwlock->__rw_pshared = attr->__pshared;
48     }
49
50   return 0;
51 }
52
53
54 int
55 pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
56 {
57   int readers;
58   _pthread_descr writer;
59
60   __pthread_lock (&rwlock->__rw_lock, NULL);
61   readers = rwlock->__rw_readers;
62   writer = rwlock->__rw_writer;
63   __pthread_unlock (&rwlock->__rw_lock);
64
65   if (readers > 0 || writer != NULL)
66     return EBUSY;
67
68   return 0;
69 }
70
71
72 int
73 pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
74 {
75   pthread_descr self = NULL;
76
77   while (1)
78     {
79       __pthread_lock (&rwlock->__rw_lock, self);
80       if (rwlock->__rw_writer == NULL
81           || (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
82               && rwlock->__rw_readers != 0))
83         /* We can add a reader lock.  */
84         break;
85
86       /* Suspend ourselves, then try again */
87       if (self == NULL)
88         self = thread_self ();
89       enqueue (&rwlock->__rw_read_waiting, self);
90       __pthread_unlock (&rwlock->__rw_lock);
91       suspend (self); /* This is not a cancellation point */
92     }
93
94   ++rwlock->__rw_readers;
95   __pthread_unlock (&rwlock->__rw_lock);
96
97   return 0;
98 }
99
100
101 int
102 pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
103 {
104   int result = EBUSY;
105
106   __pthread_lock (&rwlock->__rw_lock, NULL);
107   if (rwlock->__rw_writer == NULL
108       || (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
109           && rwlock->__rw_readers != 0))
110     {
111       ++rwlock->__rw_readers;
112       result = 0;
113     }
114   __pthread_unlock (&rwlock->__rw_lock);
115
116   return result;
117 }
118
119
120 int
121 pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
122 {
123   pthread_descr self = thread_self ();
124
125   while(1)
126     {
127       __pthread_lock (&rwlock->__rw_lock, self);
128       if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
129         {
130           rwlock->__rw_writer = self;
131           __pthread_unlock (&rwlock->__rw_lock);
132           return 0;
133         }
134
135       /* Suspend ourselves, then try again */
136       enqueue (&rwlock->__rw_write_waiting, self);
137       __pthread_unlock (&rwlock->__rw_lock);
138       suspend (self); /* This is not a cancellation point */
139     }
140 }
141
142
143 int
144 pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
145 {
146   int result = EBUSY;
147
148   __pthread_lock (&rwlock->__rw_lock, NULL);
149   if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
150     {
151       rwlock->__rw_writer = thread_self ();
152       result = 0;
153     }
154   __pthread_unlock (&rwlock->__rw_lock);
155
156   return result;
157 }
158
159
160 int
161 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
162 {
163   pthread_descr torestart;
164   pthread_descr th;
165
166   __pthread_lock (&rwlock->__rw_lock, NULL);
167   if (rwlock->__rw_writer != NULL)
168     {
169       /* Unlocking a write lock.  */
170       if (rwlock->__rw_writer != thread_self ())
171         {
172           __pthread_unlock (&rwlock->__rw_lock);
173           return EPERM;
174         }
175       rwlock->__rw_writer = NULL;
176
177       if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
178           || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL)
179         {
180           /* Restart all waiting readers.  */
181           torestart = rwlock->__rw_read_waiting;
182           rwlock->__rw_read_waiting = NULL;
183           __pthread_unlock (&rwlock->__rw_lock);
184           while ((th = dequeue (&torestart)) != NULL)
185             restart (th);
186         }
187       else
188         {
189           /* Restart one waiting writer.  */
190           __pthread_unlock (&rwlock->__rw_lock);
191           restart (th);
192         }
193     }
194   else
195     {
196       /* Unlocking a read lock.  */
197       if (rwlock->__rw_readers == 0)
198         {
199           __pthread_unlock (&rwlock->__rw_lock);
200           return EPERM;
201         }
202
203       --rwlock->__rw_readers;
204       if (rwlock->__rw_readers == 0)
205         /* Restart one waiting writer, if any.  */
206         th = dequeue (&rwlock->__rw_write_waiting);
207       else
208         th = NULL;
209
210       __pthread_unlock (&rwlock->__rw_lock);
211       if (th != NULL)
212         restart (th);
213     }
214
215   return 0;
216 }
217
218
219
220 int
221 pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
222 {
223   attr->__lockkind = 0;
224   attr->__pshared = 0;
225
226   return 0;
227 }
228
229
230 int
231 pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
232 {
233   return 0;
234 }
235
236
237 int
238 pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
239 {
240   *pshared = attr->__pshared;
241   return 0;
242 }
243
244
245 int
246 pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
247 {
248   if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
249     return EINVAL;
250
251   attr->__pshared = pshared;
252
253   return 0;
254 }
255
256
257 int
258 pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref)
259 {
260   *pref = attr->__lockkind;
261   return 0;
262 }
263
264
265 int
266 pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref)
267 {
268   if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
269       && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP
270       && pref != PTHREAD_RWLOCK_DEFAULT_NP)
271     return EINVAL;
272
273   attr->__lockkind = pref;
274
275   return 0;
276 }