Adjust for pthread.h and pthreadtypes.h change.
[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);
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;
76
77   while (1)
78     {
79       __pthread_lock (&rwlock->__rw_lock);
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       self = thread_self ();
88       enqueue (&rwlock->__rw_read_waiting, self);
89       __pthread_unlock (&rwlock->__rw_lock);
90       suspend (self); /* This is not a cancellation point */
91     }
92
93   ++rwlock->__rw_readers;
94   __pthread_unlock (&rwlock->__rw_lock);
95
96   return 0;
97 }
98
99
100 int
101 pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
102 {
103   int result = EBUSY;
104
105   __pthread_lock (&rwlock->__rw_lock);
106   if (rwlock->__rw_writer == NULL
107       || (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
108           && rwlock->__rw_readers != 0))
109     {
110       ++rwlock->__rw_readers;
111       result = 0;
112     }
113   __pthread_unlock (&rwlock->__rw_lock);
114
115   return result;
116 }
117
118
119 int
120 pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
121 {
122   pthread_descr self = thread_self ();
123
124   while(1)
125     {
126       __pthread_lock (&rwlock->__rw_lock);
127       if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
128         {
129           rwlock->__rw_writer = self;
130           __pthread_unlock (&rwlock->__rw_lock);
131           return 0;
132         }
133
134       /* Suspend ourselves, then try again */
135       enqueue (&rwlock->__rw_write_waiting, self);
136       __pthread_unlock (&rwlock->__rw_lock);
137       suspend (self); /* This is not a cancellation point */
138     }
139 }
140
141
142 int
143 pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
144 {
145   int result = EBUSY;
146
147   __pthread_lock (&rwlock->__rw_lock);
148   if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
149     {
150       rwlock->__rw_writer = thread_self ();
151       result = 0;
152     }
153   __pthread_unlock (&rwlock->__rw_lock);
154
155   return result;
156 }
157
158
159 int
160 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
161 {
162   pthread_descr torestart;
163   pthread_descr th;
164
165   __pthread_lock (&rwlock->__rw_lock);
166   if (rwlock->__rw_writer != NULL)
167     {
168       /* Unlocking a write lock.  */
169       if (rwlock->__rw_writer != thread_self ())
170         {
171           __pthread_unlock (&rwlock->__rw_lock);
172           return EPERM;
173         }
174       rwlock->__rw_writer = NULL;
175
176       if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
177           || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL)
178         {
179           /* Restart all waiting readers.  */
180           torestart = rwlock->__rw_read_waiting;
181           rwlock->__rw_read_waiting = NULL;
182           __pthread_unlock (&rwlock->__rw_lock);
183           while ((th = dequeue (&torestart)) != NULL)
184             restart (th);
185         }
186       else
187         {
188           /* Restart one waiting writer.  */
189           __pthread_unlock (&rwlock->__rw_lock);
190           restart (th);
191         }
192     }
193   else
194     {
195       /* Unlocking a read lock.  */
196       if (rwlock->__rw_readers == 0)
197         {
198           __pthread_unlock (&rwlock->__rw_lock);
199           return EPERM;
200         }
201
202       --rwlock->__rw_readers;
203       if (rwlock->__rw_readers == 0)
204         /* Restart one waiting writer, if any.  */
205         th = dequeue (&rwlock->__rw_write_waiting);
206       else
207         th = NULL;
208
209       __pthread_unlock (&rwlock->__rw_lock);
210       if (th != NULL)
211         restart (th);
212     }
213
214   return 0;
215 }
216
217
218
219 int
220 pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
221 {
222   attr->__lockkind = 0;
223   attr->__pshared = 0;
224
225   return 0;
226 }
227
228
229 int
230 pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
231 {
232   return 0;
233 }
234
235
236 int
237 pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
238 {
239   *pshared = attr->__pshared;
240   return 0;
241 }
242
243
244 int
245 pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
246 {
247   if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
248     return EINVAL;
249
250   attr->__pshared = pshared;
251
252   return 0;
253 }
254
255
256 int
257 pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref)
258 {
259   *pref = attr->__lockkind;
260   return 0;
261 }
262
263
264 int
265 pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref)
266 {
267   if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
268       && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP
269       && pref != PTHREAD_RWLOCK_DEFAULT_NP)
270     return EINVAL;
271
272   attr->__lockkind = pref;
273
274   return 0;
275 }