spin.c 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2015 Dale Weiler
  5. *
  6. * Spin locks with waiters
  7. *
  8. */
  9. #include <kernel/system.h>
  10. static inline int arch_atomic_swap(volatile int * x, int v) {
  11. asm("xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory");
  12. return v;
  13. }
  14. static inline void arch_atomic_store(volatile int * p, int x) {
  15. asm("movl %1, %0" : "=m"(*p) : "r"(x) : "memory");
  16. }
  17. static inline void arch_atomic_inc(volatile int * x) {
  18. asm("lock; incl %0" : "=m"(*x) : "m"(*x) : "memory");
  19. }
  20. static inline void arch_atomic_dec(volatile int * x) {
  21. asm("lock; decl %0" : "=m"(*x) : "m"(*x) : "memory");
  22. }
  23. void spin_wait(volatile int * addr, volatile int * waiters) {
  24. if (waiters) {
  25. arch_atomic_inc(waiters);
  26. }
  27. while (*addr) {
  28. switch_task(1);
  29. }
  30. if (waiters) {
  31. arch_atomic_dec(waiters);
  32. }
  33. }
  34. void spin_lock(spin_lock_t lock) {
  35. while (arch_atomic_swap(lock, 1)) {
  36. spin_wait(lock, lock+1);
  37. }
  38. }
  39. void spin_init(spin_lock_t lock) {
  40. lock[0] = 0;
  41. lock[1] = 0;
  42. }
  43. void spin_unlock(spin_lock_t lock) {
  44. if (lock[0]) {
  45. arch_atomic_store(lock, 0);
  46. if (lock[1])
  47. switch_task(1);
  48. }
  49. }