synch.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * Synchronization primitives.
  31. * The specifications of the functions are in synch.h.
  32. */
  33. #include <types.h>
  34. #include <lib.h>
  35. #include <spinlock.h>
  36. #include <wchan.h>
  37. #include <thread.h>
  38. #include <current.h>
  39. #include <synch.h>
  40. ////////////////////////////////////////////////////////////
  41. //
  42. // Semaphore.
  43. struct semaphore *
  44. sem_create(const char *name, int initial_count)
  45. {
  46. struct semaphore *sem;
  47. KASSERT(initial_count >= 0);
  48. sem = kmalloc(sizeof(struct semaphore));
  49. if (sem == NULL) {
  50. return NULL;
  51. }
  52. sem->sem_name = kstrdup(name);
  53. if (sem->sem_name == NULL) {
  54. kfree(sem);
  55. return NULL;
  56. }
  57. sem->sem_wchan = wchan_create(sem->sem_name);
  58. if (sem->sem_wchan == NULL) {
  59. kfree(sem->sem_name);
  60. kfree(sem);
  61. return NULL;
  62. }
  63. spinlock_init(&sem->sem_lock);
  64. sem->sem_count = initial_count;
  65. return sem;
  66. }
  67. void
  68. sem_destroy(struct semaphore *sem)
  69. {
  70. KASSERT(sem != NULL);
  71. /* wchan_cleanup will assert if anyone's waiting on it */
  72. spinlock_cleanup(&sem->sem_lock);
  73. wchan_destroy(sem->sem_wchan);
  74. kfree(sem->sem_name);
  75. kfree(sem);
  76. }
  77. void
  78. P(struct semaphore *sem)
  79. {
  80. KASSERT(sem != NULL);
  81. /*
  82. * May not block in an interrupt handler.
  83. *
  84. * For robustness, always check, even if we can actually
  85. * complete the P without blocking.
  86. */
  87. KASSERT(curthread->t_in_interrupt == false);
  88. spinlock_acquire(&sem->sem_lock);
  89. while (sem->sem_count == 0) {
  90. /*
  91. * Bridge to the wchan lock, so if someone else comes
  92. * along in V right this instant the wakeup can't go
  93. * through on the wchan until we've finished going to
  94. * sleep. Note that wchan_sleep unlocks the wchan.
  95. *
  96. * Note that we don't maintain strict FIFO ordering of
  97. * threads going through the semaphore; that is, we
  98. * might "get" it on the first try even if other
  99. * threads are waiting. Apparently according to some
  100. * textbooks semaphores must for some reason have
  101. * strict ordering. Too bad. :-)
  102. *
  103. * Exercise: how would you implement strict FIFO
  104. * ordering?
  105. */
  106. wchan_lock(sem->sem_wchan);
  107. spinlock_release(&sem->sem_lock);
  108. wchan_sleep(sem->sem_wchan);
  109. spinlock_acquire(&sem->sem_lock);
  110. }
  111. KASSERT(sem->sem_count > 0);
  112. sem->sem_count--;
  113. spinlock_release(&sem->sem_lock);
  114. }
  115. void
  116. V(struct semaphore *sem)
  117. {
  118. KASSERT(sem != NULL);
  119. spinlock_acquire(&sem->sem_lock);
  120. sem->sem_count++;
  121. KASSERT(sem->sem_count > 0);
  122. wchan_wakeone(sem->sem_wchan);
  123. spinlock_release(&sem->sem_lock);
  124. }
  125. ////////////////////////////////////////////////////////////
  126. //
  127. // Lock.
  128. struct lock * lock_create(const char * name)
  129. {
  130. struct lock * lock = kmalloc(sizeof(struct lock));
  131. if (lock == NULL)
  132. {
  133. return NULL;
  134. }
  135. lock->lk_name = kstrdup(name);
  136. struct wchan * wc = wchan_create(lock->lk_name);
  137. if (lock->lk_name == NULL || wc == NULL)
  138. {
  139. kfree(lock->lk_name);
  140. kfree(lock);
  141. kfree(wc);
  142. return NULL;
  143. }
  144. spinlock_init(&(lock->spin));
  145. lock->owner = NULL;
  146. lock->wc = wc;
  147. return lock;
  148. }
  149. void lock_destroy(struct lock * lock)
  150. {
  151. KASSERT(lock);
  152. spinlock_cleanup(&(lock->spin));
  153. wchan_destroy(lock->wc);
  154. kfree(lock->lk_name);
  155. kfree(lock);
  156. }
  157. void lock_acquire(struct lock * lock)
  158. {
  159. KASSERT(lock);
  160. KASSERT(!(lock_do_i_hold(lock)));
  161. spinlock_acquire(&(lock->spin));
  162. while (lock->owner)
  163. {
  164. wchan_lock(lock->wc);
  165. spinlock_release(&(lock->spin));
  166. wchan_sleep(lock->wc);
  167. spinlock_acquire(&(lock->spin));
  168. }
  169. lock->owner = curthread;
  170. spinlock_release(&(lock->spin));
  171. }
  172. void lock_release(struct lock * lock)
  173. {
  174. KASSERT(lock);
  175. KASSERT(lock_do_i_hold(lock));
  176. spinlock_acquire(&(lock->spin));
  177. lock->owner = NULL;
  178. wchan_wakeone(lock->wc);
  179. spinlock_release(&(lock->spin));
  180. }
  181. bool lock_do_i_hold(struct lock * lock)
  182. {
  183. KASSERT(lock);
  184. return (lock->owner == curthread);
  185. }
  186. ////////////////////////////////////////////////////////////
  187. //
  188. // CV
  189. struct cv * cv_create(const char * name)
  190. {
  191. struct cv * cv = kmalloc(sizeof(struct cv));
  192. if (cv == NULL)
  193. {
  194. return NULL;
  195. }
  196. cv->cv_name = kstrdup(name);
  197. struct wchan * wc = wchan_create(cv->cv_name);
  198. if (cv->cv_name == NULL || wc == NULL)
  199. {
  200. kfree(cv->cv_name);
  201. kfree(cv);
  202. kfree(wc);
  203. return NULL;
  204. }
  205. cv->wc = wc;
  206. return cv;
  207. }
  208. void cv_destroy(struct cv * cv)
  209. {
  210. KASSERT(cv);
  211. wchan_destroy(cv->wc);
  212. kfree(cv->cv_name);
  213. kfree(cv);
  214. }
  215. void cv_wait(struct cv * cv, struct lock * lock)
  216. {
  217. KASSERT(lock_do_i_hold(lock));
  218. wchan_lock(cv->wc);
  219. lock_release(lock);
  220. wchan_sleep(cv->wc);
  221. lock_acquire(lock);
  222. }
  223. void
  224. cv_signal(struct cv * cv, struct lock * lock)
  225. {
  226. KASSERT(lock_do_i_hold(lock));
  227. KASSERT(cv);
  228. wchan_wakeone(cv->wc);
  229. }
  230. void
  231. cv_broadcast(struct cv * cv, struct lock * lock)
  232. {
  233. KASSERT(lock_do_i_hold(lock));
  234. KASSERT(cv);
  235. wchan_wakeall(cv->wc);
  236. }