| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
|---|---|
| 2 | #ifndef _LINUX_UNWIND_USER_DEFERRED_H |
| 3 | #define _LINUX_UNWIND_USER_DEFERRED_H |
| 4 | |
| 5 | #include <linux/task_work.h> |
| 6 | #include <linux/unwind_user.h> |
| 7 | #include <linux/unwind_deferred_types.h> |
| 8 | |
| 9 | #ifdef CONFIG_UNWIND_USER |
| 10 | |
| 11 | enum { |
| 12 | UNWIND_PENDING_BIT = 0, |
| 13 | UNWIND_USED_BIT, |
| 14 | }; |
| 15 | |
| 16 | enum { |
| 17 | UNWIND_PENDING = BIT(UNWIND_PENDING_BIT), |
| 18 | |
| 19 | /* Set if the unwinding was used (directly or deferred) */ |
| 20 | UNWIND_USED = BIT(UNWIND_USED_BIT) |
| 21 | }; |
| 22 | |
| 23 | void unwind_task_init(struct task_struct *task); |
| 24 | void unwind_task_free(struct task_struct *task); |
| 25 | |
| 26 | int unwind_user_faultable(struct unwind_stacktrace *trace); |
| 27 | |
| 28 | int unwind_deferred_init(struct unwind_work *work, unwind_callback_t func); |
| 29 | int unwind_deferred_request(struct unwind_work *work, u64 *cookie); |
| 30 | void unwind_deferred_cancel(struct unwind_work *work); |
| 31 | |
| 32 | void unwind_deferred_task_exit(struct task_struct *task); |
| 33 | |
| 34 | static __always_inline void unwind_reset_info(void) |
| 35 | { |
| 36 | struct unwind_task_info *info = ¤t->unwind_info; |
| 37 | unsigned long bits = atomic_long_read(v: &info->unwind_mask); |
| 38 | |
| 39 | /* Was there any unwinding? */ |
| 40 | if (likely(!bits)) |
| 41 | return; |
| 42 | |
| 43 | do { |
| 44 | /* Is a task_work going to run again before going back */ |
| 45 | if (bits & UNWIND_PENDING) |
| 46 | return; |
| 47 | } while (!atomic_long_try_cmpxchg(v: &info->unwind_mask, old: &bits, new: 0UL)); |
| 48 | current->unwind_info.id.id = 0; |
| 49 | |
| 50 | if (unlikely(info->cache)) { |
| 51 | info->cache->nr_entries = 0; |
| 52 | info->cache->unwind_completed = 0; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | #else /* !CONFIG_UNWIND_USER */ |
| 57 | |
| 58 | static inline void unwind_task_init(struct task_struct *task) {} |
| 59 | static inline void unwind_task_free(struct task_struct *task) {} |
| 60 | |
| 61 | static inline int unwind_user_faultable(struct unwind_stacktrace *trace) |
| 62 | { return -ENOSYS; } |
| 63 | |
| 64 | static inline int |
| 65 | unwind_deferred_init(struct unwind_work *work, unwind_callback_t func) |
| 66 | { return -ENOSYS; } |
| 67 | |
| 68 | static inline int |
| 69 | unwind_deferred_request(struct unwind_work *work, u64 *timestamp) |
| 70 | { return -ENOSYS; } |
| 71 | |
| 72 | static inline void unwind_deferred_cancel(struct unwind_work *work) {} |
| 73 | |
| 74 | static inline void unwind_deferred_task_exit(struct task_struct *task) {} |
| 75 | static inline void unwind_reset_info(void) {} |
| 76 | |
| 77 | #endif /* !CONFIG_UNWIND_USER */ |
| 78 | |
| 79 | #endif /* _LINUX_UNWIND_USER_DEFERRED_H */ |
| 80 |
