rwlock.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include <stdlib.h>
  42. #include "crit.h"
  43. #include "rwlock.h"
  44. /*
  45. * rwLock.c
  46. * Implements a shared/exclusive lock package atop the
  47. * critical section/condition variables. It allows multiple
  48. * shared lock holders and only one exclusive lock holder
  49. * on a lock variable.
  50. *
  51. * NOTE : It currently favors writers over readers and writers
  52. * may starve readers. It is usually preferable to allow updates
  53. * if they are not as frequent. We may have to change this if
  54. * the common usage pattern differs from this.
  55. */
  56. typedef struct {
  57. CRITICAL crit; /* Short term crit to synchronize lock ops */
  58. CONDVAR readFree; /* Indicates lock is free for readers */
  59. CONDVAR writeFree; /* Indicates lock is free for the writer */
  60. int numReaders; /* Number of read locks held */
  61. int write; /* Flag to indicate write lock held */
  62. int numWriteWaiters;/* Number of threads waiting for write lock */
  63. } rwLock_t;
  64. /*
  65. * rwlock_init()
  66. * Allocate and initialize the rwlock structure and return
  67. * to the caller.
  68. */
  69. RWLOCK rwlock_Init()
  70. {
  71. rwLock_t *rwLockP;
  72. rwLockP = (rwLock_t *)PERM_MALLOC(sizeof(rwLock_t));
  73. rwLockP->numReaders = 0;
  74. rwLockP->write = 0;
  75. rwLockP->numWriteWaiters = 0;
  76. rwLockP->crit = crit_init();
  77. rwLockP->readFree = condvar_init(rwLockP->crit);
  78. rwLockP->writeFree = condvar_init(rwLockP->crit);
  79. return((RWLOCK)rwLockP);
  80. }
  81. /*
  82. * rwlock_terminate()
  83. * Terminate the associated condvars and critical sections
  84. */
  85. void rwlock_Terminate(RWLOCK lockP)
  86. {
  87. rwLock_t *rwLockP = (rwLock_t *)lockP;
  88. crit_terminate(rwLockP->crit);
  89. condvar_terminate(rwLockP->readFree);
  90. condvar_terminate(rwLockP->writeFree);
  91. PERM_FREE(rwLockP);
  92. }
  93. /*
  94. * rwlock_ReadLock -- Obtain a shared lock. The caller would
  95. * block if there are writers or writeWaiters.
  96. */
  97. void rwlock_ReadLock(RWLOCK lockP)
  98. {
  99. rwLock_t *rwLockP = (rwLock_t *)lockP;
  100. crit_enter(rwLockP->crit);
  101. while (rwLockP->write || rwLockP->numWriteWaiters != 0)
  102. condvar_wait(rwLockP->readFree);
  103. rwLockP->numReaders++;
  104. crit_exit(rwLockP->crit);
  105. }
  106. /*
  107. * rwlock_writeLock -- Obtain an exclusive lock. The caller would
  108. * block if there are other readers or a writer.
  109. */
  110. void rwlock_WriteLock(RWLOCK lockP)
  111. {
  112. rwLock_t *rwLockP = (rwLock_t *)lockP;
  113. crit_enter(rwLockP->crit);
  114. rwLockP->numWriteWaiters++;
  115. while (rwLockP->numReaders != 0 || rwLockP->write)
  116. condvar_wait(rwLockP->writeFree);
  117. rwLockP->numWriteWaiters--;
  118. rwLockP->write = 1;
  119. crit_exit(rwLockP->crit);
  120. }
  121. /*
  122. * rw_Unlock -- Releases the lock.
  123. */
  124. void rwlock_Unlock(RWLOCK lockP)
  125. {
  126. rwLock_t *rwLockP = (rwLock_t *)lockP;
  127. crit_enter(rwLockP->crit);
  128. if (rwLockP->write)
  129. rwLockP->write = 0;
  130. else
  131. rwLockP->numReaders--;
  132. if (rwLockP->numReaders == 0) {
  133. if (rwLockP->numWriteWaiters != 0)
  134. condvar_notify(rwLockP->writeFree);
  135. else
  136. condvar_notifyAll(rwLockP->readFree);
  137. }
  138. crit_exit(rwLockP->crit);
  139. }
  140. /*
  141. * rwlock_DemoteLock -- Change an exclusive lock on the given lock
  142. * variable into a shared lock.
  143. */
  144. void rwlock_DemoteLock(RWLOCK lockP)
  145. {
  146. rwLock_t *rwLockP = (rwLock_t *)lockP;
  147. crit_enter(rwLockP->crit);
  148. rwLockP->numReaders = 1;
  149. rwLockP->write = 0;
  150. if (rwLockP->numWriteWaiters == 0)
  151. condvar_notifyAll(rwLockP->readFree);
  152. crit_exit(rwLockP->crit);
  153. }