xref: /linux/include/linux/unwind_deferred.h (revision c6439bfaabf25b736154ac5640c677da2c085db4)
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 = &current->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