《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
1.6 KiB

12 years ago
  1. #include <defs.h>
  2. #include <wait.h>
  3. #include <atomic.h>
  4. #include <kmalloc.h>
  5. #include <sem.h>
  6. #include <proc.h>
  7. #include <sync.h>
  8. #include <assert.h>
  9. void
  10. sem_init(semaphore_t *sem, int value) {
  11. sem->value = value;
  12. wait_queue_init(&(sem->wait_queue));
  13. }
  14. static __noinline void __up(semaphore_t *sem, uint32_t wait_state) {
  15. bool intr_flag;
  16. local_intr_save(intr_flag);
  17. {
  18. wait_t *wait;
  19. if ((wait = wait_queue_first(&(sem->wait_queue))) == NULL) {
  20. sem->value ++;
  21. }
  22. else {
  23. assert(wait->proc->wait_state == wait_state);
  24. wakeup_wait(&(sem->wait_queue), wait, wait_state, 1);
  25. }
  26. }
  27. local_intr_restore(intr_flag);
  28. }
  29. static __noinline uint32_t __down(semaphore_t *sem, uint32_t wait_state) {
  30. bool intr_flag;
  31. local_intr_save(intr_flag);
  32. if (sem->value > 0) {
  33. sem->value --;
  34. local_intr_restore(intr_flag);
  35. return 0;
  36. }
  37. wait_t __wait, *wait = &__wait;
  38. wait_current_set(&(sem->wait_queue), wait, wait_state);
  39. local_intr_restore(intr_flag);
  40. schedule();
  41. local_intr_save(intr_flag);
  42. wait_current_del(&(sem->wait_queue), wait);
  43. local_intr_restore(intr_flag);
  44. if (wait->wakeup_flags != wait_state) {
  45. return wait->wakeup_flags;
  46. }
  47. return 0;
  48. }
  49. void
  50. up(semaphore_t *sem) {
  51. __up(sem, WT_KSEM);
  52. }
  53. void
  54. down(semaphore_t *sem) {
  55. uint32_t flags = __down(sem, WT_KSEM);
  56. assert(flags == 0);
  57. }
  58. bool
  59. try_down(semaphore_t *sem) {
  60. bool intr_flag, ret = 0;
  61. local_intr_save(intr_flag);
  62. if (sem->value > 0) {
  63. sem->value --, ret = 1;
  64. }
  65. local_intr_restore(intr_flag);
  66. return ret;
  67. }