rcuwait.h 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  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. extern void finish_rcuwait(struct rcuwait *w);
  42. #define rcuwait_wait_event(w, condition, state) \
  43. ({ \
  44. int __ret = 0; \
  45. prepare_to_rcuwait(w); \
  46. for (;;) { \
  47. /* \
  48. * Implicit barrier (A) pairs with (B) in \
  49. * rcuwait_wake_up(). \
  50. */ \
  51. set_current_state(state); \
  52. if (condition) \
  53. break; \
  54. \
  55. if (signal_pending_state(state, current)) { \
  56. __ret = -EINTR; \
  57. break; \
  58. } \
  59. \
  60. schedule(); \
  61. } \
  62. finish_rcuwait(w); \
  63. __ret; \
  64. })
  65. #endif /* _LINUX_RCUWAIT_H_ */