mutex.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * Copyright (c) 2017 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 <stdbool.h>
  19. #include <stddef.h>
  20. #include <stdint.h>
  21. #include <kern/atomic.h>
  22. #include <kern/init.h>
  23. #include <kern/mutex.h>
  24. #include <kern/sleepq.h>
  25. #include <kern/syscnt.h>
  26. static int
  27. mutex_lock_slow_common (struct mutex *mutex, bool timed, uint64_t ticks)
  28. {
  29. int error = 0;
  30. struct sleepq *sleepq = sleepq_lend (mutex);
  31. while (1)
  32. {
  33. uint32_t state = atomic_swap_rel (&mutex->state, MUTEX_CONTENDED);
  34. if (state == MUTEX_UNLOCKED)
  35. break;
  36. else if (! timed)
  37. sleepq_wait (sleepq, "mutex");
  38. else
  39. {
  40. error = sleepq_timedwait (sleepq, "mutex", ticks);
  41. if (error)
  42. break;
  43. }
  44. }
  45. if (sleepq_empty (sleepq))
  46. {
  47. if (error)
  48. atomic_cas_rlx (&mutex->state, MUTEX_CONTENDED, MUTEX_LOCKED);
  49. else
  50. atomic_store_rlx (&mutex->state, MUTEX_LOCKED);
  51. }
  52. sleepq_return (sleepq);
  53. return (error);
  54. }
  55. void
  56. mutex_lock_slow (struct mutex *mutex)
  57. {
  58. int error = mutex_lock_slow_common (mutex, false, 0);
  59. assert (! error);
  60. }
  61. int
  62. mutex_timedlock_slow (struct mutex *mutex, uint64_t ticks)
  63. {
  64. return (mutex_lock_slow_common (mutex, true, ticks));
  65. }
  66. void
  67. mutex_unlock_slow (struct mutex *mutex)
  68. {
  69. struct sleepq *sleepq = sleepq_acquire (mutex);
  70. if (! sleepq)
  71. return;
  72. sleepq_signal (sleepq);
  73. sleepq_release (sleepq);
  74. }
  75. static int __init
  76. mutex_setup (void)
  77. {
  78. return (0);
  79. }
  80. INIT_OP_DEFINE (mutex_setup);