]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/rwlock.c
Update copyright notice
[empserver] / src / lib / lwp / rwlock.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1994-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *  Copyright (C) 1991-3 Stephen Crane
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program 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
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *  ---
22  *
23  *  See files README, COPYING and CREDITS in the root of the source
24  *  tree for related information and legal notices.  It is expected
25  *  that future projects/authors will amend these files as needed.
26  *
27  *  ---
28  *
29  *  rwlock.c: Read-write locks
30  * 
31  *  Known contributors to this file:
32  *     Ron Koenderink, 2007
33  *     Markus Armbruster, 2007
34  */
35
36 #include <config.h>
37
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "lwp.h"
42 #include "lwpint.h"
43
44 struct lwp_rwlock {
45     /*
46      * Lock counter
47      * 0: unlocked
48      * -1: locked for writing
49      * >0: locked for reading that many times
50      */
51     int count;
52     struct lwpQueue rq;         /* read lock sleepers */
53     struct lwpQueue wq;         /* write lock sleepers */
54     char *name;
55 };
56
57 struct lwp_rwlock *
58 lwp_rwlock_create(char *name)
59 {
60     struct lwp_rwlock *rwlock;
61
62     rwlock = malloc(sizeof(*rwlock));
63     if (!rwlock)
64         return NULL;
65
66     memset(rwlock, 0, sizeof(*rwlock));
67     rwlock->name = strdup(name);
68     return rwlock;
69 }
70
71 void
72 lwp_rwlock_destroy(struct lwp_rwlock *rwlock)
73 {
74     if (CANT_HAPPEN(rwlock->count))
75         return;
76     free(rwlock->name);
77     free(rwlock);
78 }
79
80 void
81 lwp_rwlock_wrlock(struct lwp_rwlock *rwlock)
82 {
83     if (rwlock->count) {
84         lwpAddTail(&rwlock->wq, LwpCurrent);
85         lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for writing",
86                   rwlock->name);
87         lwpReschedule();
88     }
89     CANT_HAPPEN(rwlock->count != 0);
90     rwlock->count = -1;
91     lwpStatus(LwpCurrent, "acquired rwlock %s for writing", rwlock->name);
92 }
93
94 void
95 lwp_rwlock_rdlock(struct lwp_rwlock *rwlock)
96 {
97     if (rwlock->count < 0 || rwlock->wq.head) {
98         lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for reading",
99                   rwlock->name);
100         lwpAddTail(&rwlock->rq, LwpCurrent);
101         lwpReschedule();
102     }
103     CANT_HAPPEN(rwlock->count < 0);
104     rwlock->count++;
105     lwpStatus(LwpCurrent, "acquired rwlock %s for reading", rwlock->name);
106 }
107
108 void
109 lwp_rwlock_unlock(struct lwp_rwlock *rwlock)
110 {
111     struct lwpProc *p;
112
113     lwpStatus(LwpCurrent, "unlocking rwlock %s", rwlock->name);
114     if (CANT_HAPPEN(rwlock->count == 0))
115         return;
116     if (rwlock->count < 0)
117         rwlock->count = 0;
118     else
119         rwlock->count--;
120
121     if (rwlock->count == 0 && rwlock->wq.head) {
122         p = lwpGetFirst(&rwlock->wq);
123         lwpStatus(p, "wake up next writer of rwlock %s", rwlock->name);
124     } else if (rwlock->count >= 0 && rwlock->rq.head && !rwlock->wq.head) {
125         p = lwpGetFirst(&rwlock->rq);
126         lwpStatus(p, "wake up next reader of rwlock %s", rwlock->name);
127     } else
128         return;
129
130     lwpReady(p);
131     if (LwpCurrent->pri < p->pri) {
132         lwpStatus(LwpCurrent, "yielding to thread with higher priority");
133         lwpYield();
134     }
135 }