futex.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #ifndef _ASM_GENERIC_FUTEX_H
  2. #define _ASM_GENERIC_FUTEX_H
  3. #include <linux/futex.h>
  4. #include <linux/uaccess.h>
  5. #include <asm/errno.h>
  6. #ifndef CONFIG_SMP
  7. /*
  8. * The following implementation only for uniprocessor machines.
  9. * It relies on preempt_disable() ensuring mutual exclusion.
  10. *
  11. */
  12. /**
  13. * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
  14. * argument and comparison of the previous
  15. * futex value with another constant.
  16. *
  17. * @encoded_op: encoded operation to execute
  18. * @uaddr: pointer to user space address
  19. *
  20. * Return:
  21. * 0 - On success
  22. * <0 - On error
  23. */
  24. static inline int
  25. arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
  26. {
  27. int oldval, ret;
  28. u32 tmp;
  29. preempt_disable();
  30. pagefault_disable();
  31. ret = -EFAULT;
  32. if (unlikely(get_user(oldval, uaddr) != 0))
  33. goto out_pagefault_enable;
  34. ret = 0;
  35. tmp = oldval;
  36. switch (op) {
  37. case FUTEX_OP_SET:
  38. tmp = oparg;
  39. break;
  40. case FUTEX_OP_ADD:
  41. tmp += oparg;
  42. break;
  43. case FUTEX_OP_OR:
  44. tmp |= oparg;
  45. break;
  46. case FUTEX_OP_ANDN:
  47. tmp &= ~oparg;
  48. break;
  49. case FUTEX_OP_XOR:
  50. tmp ^= oparg;
  51. break;
  52. default:
  53. ret = -ENOSYS;
  54. }
  55. if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
  56. ret = -EFAULT;
  57. out_pagefault_enable:
  58. pagefault_enable();
  59. preempt_enable();
  60. if (ret == 0)
  61. *oval = oldval;
  62. return ret;
  63. }
  64. /**
  65. * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
  66. * uaddr with newval if the current value is
  67. * oldval.
  68. * @uval: pointer to store content of @uaddr
  69. * @uaddr: pointer to user space address
  70. * @oldval: old value
  71. * @newval: new value to store to @uaddr
  72. *
  73. * Return:
  74. * 0 - On success
  75. * <0 - On error
  76. */
  77. static inline int
  78. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  79. u32 oldval, u32 newval)
  80. {
  81. u32 val;
  82. preempt_disable();
  83. if (unlikely(get_user(val, uaddr) != 0)) {
  84. preempt_enable();
  85. return -EFAULT;
  86. }
  87. if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
  88. preempt_enable();
  89. return -EFAULT;
  90. }
  91. *uval = val;
  92. preempt_enable();
  93. return 0;
  94. }
  95. #else
  96. static inline int
  97. arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
  98. {
  99. int oldval = 0, ret;
  100. pagefault_disable();
  101. switch (op) {
  102. case FUTEX_OP_SET:
  103. case FUTEX_OP_ADD:
  104. case FUTEX_OP_OR:
  105. case FUTEX_OP_ANDN:
  106. case FUTEX_OP_XOR:
  107. default:
  108. ret = -ENOSYS;
  109. }
  110. pagefault_enable();
  111. if (!ret)
  112. *oval = oldval;
  113. return ret;
  114. }
  115. static inline int
  116. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  117. u32 oldval, u32 newval)
  118. {
  119. return -ENOSYS;
  120. }
  121. #endif /* CONFIG_SMP */
  122. #endif