src/lib/lwp/rwlock.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1994-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *  Copyright (C) 1991-3 Stephen Crane
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  *  ---
00022  *
00023  *  See files README, COPYING and CREDITS in the root of the source
00024  *  tree for related information and legal notices.  It is expected
00025  *  that future projects/authors will amend these files as needed.
00026  *
00027  *  ---
00028  *
00029  *  rwlock.c: Read-write locks
00030  * 
00031  *  Known contributors to this file:
00032  *     Ron Koenderink, 2007
00033  *     Markus Armbruster, 2007
00034  */
00035 
00036 #include <config.h>
00037 
00038 #include <stdlib.h>
00039 #include <string.h>
00040 
00041 #include "lwp.h"
00042 #include "lwpint.h"
00043 
00044 struct lwp_rwlock {
00045     /*
00046      * Lock counter
00047      * 0: unlocked
00048      * -1: locked for writing
00049      * >0: locked for reading that many times
00050      */
00051     int count;
00052     struct lwpQueue rq;         /* read lock sleepers */
00053     struct lwpQueue wq;         /* write lock sleepers */
00054     char *name;
00055 };
00056 
00057 struct lwp_rwlock *
00058 lwp_rwlock_create(char *name)
00059 {
00060     struct lwp_rwlock *rwlock;
00061 
00062     rwlock = malloc(sizeof(*rwlock));
00063     if (!rwlock)
00064         return NULL;
00065 
00066     memset(rwlock, 0, sizeof(*rwlock));
00067     rwlock->name = strdup(name);
00068     return rwlock;
00069 }
00070 
00071 void
00072 lwp_rwlock_destroy(struct lwp_rwlock *rwlock)
00073 {
00074     if (CANT_HAPPEN(rwlock->count))
00075         return;
00076     free(rwlock->name);
00077     free(rwlock);
00078 }
00079 
00080 void
00081 lwp_rwlock_wrlock(struct lwp_rwlock *rwlock)
00082 {
00083     if (rwlock->count) {
00084         lwpAddTail(&rwlock->wq, LwpCurrent);
00085         lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for writing",
00086                   rwlock->name);
00087         lwpReschedule();
00088     }
00089     CANT_HAPPEN(rwlock->count != 0);
00090     rwlock->count = -1;
00091     lwpStatus(LwpCurrent, "acquired rwlock %s for writing", rwlock->name);
00092 }
00093 
00094 void
00095 lwp_rwlock_rdlock(struct lwp_rwlock *rwlock)
00096 {
00097     if (rwlock->count < 0 || rwlock->wq.head) {
00098         lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for reading",
00099                   rwlock->name);
00100         lwpAddTail(&rwlock->rq, LwpCurrent);
00101         lwpReschedule();
00102     }
00103     CANT_HAPPEN(rwlock->count < 0);
00104     rwlock->count++;
00105     lwpStatus(LwpCurrent, "acquired rwlock %s for reading", rwlock->name);
00106 }
00107 
00108 void
00109 lwp_rwlock_unlock(struct lwp_rwlock *rwlock)
00110 {
00111     struct lwpProc *p;
00112 
00113     lwpStatus(LwpCurrent, "unlocking rwlock %s", rwlock->name);
00114     if (CANT_HAPPEN(rwlock->count == 0))
00115         return;
00116     if (rwlock->count < 0)
00117         rwlock->count = 0;
00118     else
00119         rwlock->count--;
00120 
00121     if (rwlock->count == 0 && rwlock->wq.head) {
00122         p = lwpGetFirst(&rwlock->wq);
00123         lwpStatus(p, "wake up next writer of rwlock %s", rwlock->name);
00124     } else if (rwlock->count >= 0 && rwlock->rq.head && !rwlock->wq.head) {
00125         p = lwpGetFirst(&rwlock->rq);
00126         lwpStatus(p, "wake up next reader of rwlock %s", rwlock->name);
00127     } else
00128         return;
00129 
00130     lwpReady(p);
00131     if (LwpCurrent->pri < p->pri) {
00132         lwpStatus(LwpCurrent, "yielding to thread with higher priority");
00133         lwpYield();
00134     }
00135 }

Generated on Fri Mar 28 11:01:14 2008 for empserver by  doxygen 1.5.2