rwlock.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. #include <stdlib.h>
  39. #include "crit.h"
  40. #include "rwlock.h"
  41. /*
  42. * rwLock.c
  43. * Implements a shared/exclusive lock package atop the
  44. * critical section/condition variables. It allows multiple
  45. * shared lock holders and only one exclusive lock holder
  46. * on a lock variable.
  47. *
  48. * NOTE : It currently favors writers over readers and writers
  49. * may starve readers. It is usually preferable to allow updates
  50. * if they are not as frequent. We may have to change this if
  51. * the common usage pattern differs from this.
  52. */
  53. typedef struct {
  54. CRITICAL crit; /* Short term crit to synchronize lock ops */
  55. CONDVAR readFree; /* Indicates lock is free for readers */
  56. CONDVAR writeFree; /* Indicates lock is free for the writer */
  57. int numReaders; /* Number of read locks held */
  58. int write; /* Flag to indicate write lock held */
  59. int numWriteWaiters;/* Number of threads waiting for write lock */
  60. } rwLock_t;
  61. /*
  62. * rwlock_init()
  63. * Allocate and initialize the rwlock structure and return
  64. * to the caller.
  65. */
  66. RWLOCK rwlock_Init()
  67. {
  68. rwLock_t *rwLockP;
  69. rwLockP = (rwLock_t *)PERM_MALLOC(sizeof(rwLock_t));
  70. rwLockP->numReaders = 0;
  71. rwLockP->write = 0;
  72. rwLockP->numWriteWaiters = 0;
  73. rwLockP->crit = crit_init();
  74. rwLockP->readFree = condvar_init(rwLockP->crit);
  75. rwLockP->writeFree = condvar_init(rwLockP->crit);
  76. return((RWLOCK)rwLockP);
  77. }
  78. /*
  79. * rwlock_terminate()
  80. * Terminate the associated condvars and critical sections
  81. */
  82. void rwlock_Terminate(RWLOCK lockP)
  83. {
  84. rwLock_t *rwLockP = (rwLock_t *)lockP;
  85. crit_terminate(rwLockP->crit);
  86. condvar_terminate(rwLockP->readFree);
  87. condvar_terminate(rwLockP->writeFree);
  88. PERM_FREE(rwLockP);
  89. }
  90. /*
  91. * rwlock_ReadLock -- Obtain a shared lock. The caller would
  92. * block if there are writers or writeWaiters.
  93. */
  94. void rwlock_ReadLock(RWLOCK lockP)
  95. {
  96. rwLock_t *rwLockP = (rwLock_t *)lockP;
  97. crit_enter(rwLockP->crit);
  98. while (rwLockP->write || rwLockP->numWriteWaiters != 0)
  99. condvar_wait(rwLockP->readFree);
  100. rwLockP->numReaders++;
  101. crit_exit(rwLockP->crit);
  102. }
  103. /*
  104. * rwlock_writeLock -- Obtain an exclusive lock. The caller would
  105. * block if there are other readers or a writer.
  106. */
  107. void rwlock_WriteLock(RWLOCK lockP)
  108. {
  109. rwLock_t *rwLockP = (rwLock_t *)lockP;
  110. crit_enter(rwLockP->crit);
  111. rwLockP->numWriteWaiters++;
  112. while (rwLockP->numReaders != 0 || rwLockP->write)
  113. condvar_wait(rwLockP->writeFree);
  114. rwLockP->numWriteWaiters--;
  115. rwLockP->write = 1;
  116. crit_exit(rwLockP->crit);
  117. }
  118. /*
  119. * rw_Unlock -- Releases the lock.
  120. */
  121. void rwlock_Unlock(RWLOCK lockP)
  122. {
  123. rwLock_t *rwLockP = (rwLock_t *)lockP;
  124. crit_enter(rwLockP->crit);
  125. if (rwLockP->write)
  126. rwLockP->write = 0;
  127. else
  128. rwLockP->numReaders--;
  129. if (rwLockP->numReaders == 0)
  130. if (rwLockP->numWriteWaiters != 0)
  131. condvar_notify(rwLockP->writeFree);
  132. else
  133. condvar_notifyAll(rwLockP->readFree);
  134. crit_exit(rwLockP->crit);
  135. }
  136. /*
  137. * rwlock_DemoteLock -- Change an exclusive lock on the given lock
  138. * variable into a shared lock.
  139. */
  140. void rwlock_DemoteLock(RWLOCK lockP)
  141. {
  142. rwLock_t *rwLockP = (rwLock_t *)lockP;
  143. crit_enter(rwLockP->crit);
  144. rwLockP->numReaders = 1;
  145. rwLockP->write = 0;
  146. if (rwLockP->numWriteWaiters == 0)
  147. condvar_notifyAll(rwLockP->readFree);
  148. crit_exit(rwLockP->crit);
  149. }