]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/rwlock.c
Update known contributors comments
[empserver] / src / lib / lwp / rwlock.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1994-2009, 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-2009
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     int maxpri;
113
114     lwpStatus(LwpCurrent, "unlocking rwlock %s", rwlock->name);
115     if (CANT_HAPPEN(rwlock->count == 0))
116         return;
117     if (rwlock->count < 0)
118         rwlock->count = 0;
119     else
120         rwlock->count--;
121
122     if (rwlock->count == 0 && rwlock->wq.head) {
123         p = lwpGetFirst(&rwlock->wq);
124         lwpStatus(p, "wake up next writer of rwlock %s", rwlock->name);
125         maxpri = p->pri;
126         lwpReady(p);
127     } else if (rwlock->count >= 0 && rwlock->rq.head && !rwlock->wq.head) {
128         maxpri = 0;
129         while ((p = lwpGetFirst(&rwlock->rq))) {
130             lwpStatus(p, "wake up next reader of rwlock %s", rwlock->name);
131             maxpri = MAX(maxpri, p->pri);
132             lwpReady(p);
133         }
134     } else
135         return;
136
137     if (LwpCurrent->pri < maxpri) {
138         lwpStatus(LwpCurrent, "yielding to thread with higher priority");
139         lwpYield();
140     }
141 }