LinuxThreads library.
[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   rwlock->rw_spinlock = 0;
34   rwlock->rw_readers = 0;
35   rwlock->rw_writer = NULL;
36
37   queue_init(&rwlock->rw_read_waiting);
38   queue_init(&rwlock->rw_write_waiting);
39
40   if (attr == NULL)
41     {
42       rwlock->rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
43       rwlock->rw_pshared = PTHREAD_PROCESS_PRIVATE;
44     }
45   else
46     {
47       rwlock->rw_kind = attr->lockkind;
48       rwlock->rw_pshared = attr->pshared;
49     }
50
51   return 0;
52 }
53
54
55 int
56 pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
57 {
58   int readers;
59   _pthread_descr writer;
60
61   acquire (&rwlock->rw_spinlock);
62   readers = rwlock->rw_readers;
63   writer = rwlock->rw_writer;
64   release (&rwlock->rw_spinlock);
65
66   if (readers > 0 || writer != NULL)
67     return EBUSY;
68
69   return 0;
70 }
71
72
73 int
74 pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
75 {
76   pthread_descr self;
77
78   while (1)
79     {
80       acquire (&rwlock->rw_spinlock);
81       if (rwlock->rw_writer == NULL
82           || (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
83               && rwlock->rw_readers != 0))
84         /* We can add a reader lock.  */
85         break;
86
87       /* Suspend ourselves, then try again */
88       self = thread_self ();
89       enqueue (&rwlock->rw_read_waiting, self);
90       release (&rwlock->rw_spinlock);
91       suspend (self); /* This is not a cancellation point */
92     }
93
94   ++rwlock->rw_readers;
95   release (&rwlock->rw_spinlock);
96
97   return 0;
98 }
99
100
101 int
102 pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
103 {
104   int result = EBUSY;
105
106   acquire (&rwlock->rw_spinlock);
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   release (&rwlock->rw_spinlock);
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       acquire (&rwlock->rw_spinlock);
128       if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL)
129         {
130           rwlock->rw_writer = self;
131           release (&rwlock->rw_spinlock);
132           return 0;
133         }
134
135       /* Suspend ourselves, then try again */
136       enqueue (&rwlock->rw_write_waiting, self);
137       release (&rwlock->rw_spinlock);
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   acquire (&rwlock->rw_spinlock);
149   if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL)
150     {
151       rwlock->rw_writer = thread_self ();
152       result = 0;
153     }
154   release (&rwlock->rw_spinlock);
155
156   return result;
157 }
158
159
160 int
161 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
162 {
163   struct _pthread_queue torestart;
164   pthread_descr th;
165
166   acquire (&rwlock->rw_spinlock);
167   if (rwlock->rw_writer != NULL)
168     {
169       /* Unlocking a write lock.  */
170       if (rwlock->rw_writer != thread_self ())
171         {
172           release (&rwlock->rw_spinlock);
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           queue_init (&rwlock->rw_read_waiting);
183           release (&rwlock->rw_spinlock);
184           while ((th = dequeue (&torestart)) != NULL)
185             restart (th);
186         }
187       else
188         {
189           /* Restart one waiting writer.  */
190           release (&rwlock->rw_spinlock);
191           restart (th);
192         }
193     }
194   else
195     {
196       /* Unlocking a read lock.  */
197       if (rwlock->rw_readers == 0)
198         {
199           release (&rwlock->rw_spinlock);
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       release (&rwlock->rw_spinlock);
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 }