rcuwait.h 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _LINUX_RCUWAIT_H_
  3. #define _LINUX_RCUWAIT_H_
  4. #include <linux/rcupdate.h>
  5. #include <linux/sched/signal.h>
  6. /*
  7. * rcuwait provides a way of blocking and waking up a single
  8. * task in an rcu-safe manner.
  9. *
  10. * The only time @task is non-nil is when a user is blocked (or
  11. * checking if it needs to) on a condition, and reset as soon as we
  12. * know that the condition has succeeded and are awoken.
  13. */
  14. struct rcuwait {
  15. struct task_struct __rcu *task;
  16. };
  17. #define __RCUWAIT_INITIALIZER(name) \
  18. { .task = NULL, }
  19. static inline void rcuwait_init(struct rcuwait *w)
  20. {
  21. w->task = NULL;
  22. }
  23. /*
  24. * Note: this provides no serialization and, just as with waitqueues,
  25. * requires care to estimate as to whether or not the wait is active.
  26. */
  27. static inline int rcuwait_active(struct rcuwait *w)
  28. {
  29. return !!rcu_access_pointer(w->task);
  30. }
  31. extern int rcuwait_wake_up(struct rcuwait *w);
  32. /*
  33. * The caller is responsible for locking around rcuwait_wait_event(),
  34. * and [prepare_to/finish]_rcuwait() such that writes to @task are
  35. * properly serialized.
  36. */
  37. static inline void prepare_to_rcuwait(struct rcuwait *w)
  38. {
  39. rcu_assign_pointer(w->task, current);
  40. }
  41. static inline void finish_rcuwait(struct rcuwait *w)
  42. {
  43. rcu_assign_pointer(w->task, NULL);
  44. __set_current_state(TASK_RUNNING);
  45. }
  46. #define rcuwait_wait_event(w, condition, state) \
  47. ({ \
  48. int __ret = 0; \
  49. prepare_to_rcuwait(w); \
  50. for (;;) { \
  51. /* \
  52. * Implicit barrier (A) pairs with (B) in \
  53. * rcuwait_wake_up(). \
  54. */ \
  55. set_current_state(state); \
  56. if (condition) \
  57. break; \
  58. \
  59. if (signal_pending_state(state, current)) { \
  60. __ret = -EINTR; \
  61. break; \
  62. } \
  63. \
  64. schedule(); \
  65. } \
  66. finish_rcuwait(w); \
  67. __ret; \
  68. })
  69. #endif /* _LINUX_RCUWAIT_H_ */