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