semaphore.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * Copyright (c) 2017-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <stdbool.h>
  20. #include <stdint.h>
  21. #include <kern/atomic.h>
  22. #include <kern/futex.h>
  23. #include <kern/semaphore.h>
  24. #include <kern/semaphore_i.h>
  25. #include <machine/cpu.h>
  26. void
  27. semaphore_init(struct semaphore *semaphore, uint16_t value, uint16_t max_value)
  28. {
  29. assert(value <= max_value);
  30. semaphore->values = ((uint32_t)max_value << 16) + value;
  31. }
  32. int
  33. semaphore_trywait(struct semaphore *semaphore)
  34. {
  35. uint32_t values;
  36. for (;;) {
  37. values = atomic_load(&semaphore->values, ATOMIC_RELAXED);
  38. if ((values & 0xffff) == 0) {
  39. return EAGAIN;
  40. } else if (atomic_cas(&semaphore->values, values, values - 1,
  41. ATOMIC_ACQUIRE) == values) {
  42. return 0;
  43. }
  44. cpu_pause();
  45. }
  46. }
  47. void
  48. semaphore_wait(struct semaphore *semaphore)
  49. {
  50. uint32_t values;
  51. for (;;) {
  52. values = atomic_load(&semaphore->values, ATOMIC_RELAXED);
  53. if ((values & 0xffff) == 0) {
  54. futex_wait(&semaphore->values, values, 0, 0);
  55. continue;
  56. } else if (atomic_cas(&semaphore->values, values, values - 1,
  57. ATOMIC_ACQUIRE) == values) {
  58. return;
  59. }
  60. cpu_pause();
  61. }
  62. }
  63. int
  64. semaphore_timedwait(struct semaphore *semaphore, uint64_t ticks)
  65. {
  66. uint32_t values;
  67. for (;;) {
  68. values = atomic_load(&semaphore->values, ATOMIC_RELAXED);
  69. if ((values & 0xffff) != 0) {
  70. if (atomic_cas(&semaphore->values, values, values - 1,
  71. ATOMIC_ACQUIRE) == values) {
  72. return 0;
  73. }
  74. cpu_pause();
  75. } else if (futex_wait(&semaphore->values, values,
  76. FUTEX_TIMED | FUTEX_ABS, ticks) == ETIMEDOUT) {
  77. return ETIMEDOUT;
  78. }
  79. }
  80. }
  81. int
  82. semaphore_post(struct semaphore *semaphore)
  83. {
  84. uint32_t values;
  85. for (;;) {
  86. values = atomic_load(&semaphore->values, ATOMIC_RELAXED);
  87. if ((values & 0xffff) == (values >> 16)) {
  88. return EOVERFLOW;
  89. } else if (atomic_cas(&semaphore->values, values, values + 1,
  90. ATOMIC_RELEASE) == values) {
  91. futex_wake(&semaphore->values, 0, 0);
  92. return 0;
  93. }
  94. cpu_pause();
  95. }
  96. }