xref: /linux-6.15/kernel/sched/core_sched.c (revision 6e33cad0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include "sched.h"
4 
5 /*
6  * A simple wrapper around refcount. An allocated sched_core_cookie's
7  * address is used to compute the cookie of the task.
8  */
9 struct sched_core_cookie {
10 	refcount_t refcnt;
11 };
12 
13 unsigned long sched_core_alloc_cookie(void)
14 {
15 	struct sched_core_cookie *ck = kmalloc(sizeof(*ck), GFP_KERNEL);
16 	if (!ck)
17 		return 0;
18 
19 	refcount_set(&ck->refcnt, 1);
20 	sched_core_get();
21 
22 	return (unsigned long)ck;
23 }
24 
25 void sched_core_put_cookie(unsigned long cookie)
26 {
27 	struct sched_core_cookie *ptr = (void *)cookie;
28 
29 	if (ptr && refcount_dec_and_test(&ptr->refcnt)) {
30 		kfree(ptr);
31 		sched_core_put();
32 	}
33 }
34 
35 unsigned long sched_core_get_cookie(unsigned long cookie)
36 {
37 	struct sched_core_cookie *ptr = (void *)cookie;
38 
39 	if (ptr)
40 		refcount_inc(&ptr->refcnt);
41 
42 	return cookie;
43 }
44 
45 /*
46  * sched_core_update_cookie - replace the cookie on a task
47  * @p: the task to update
48  * @cookie: the new cookie
49  *
50  * Effectively exchange the task cookie; caller is responsible for lifetimes on
51  * both ends.
52  *
53  * Returns: the old cookie
54  */
55 unsigned long sched_core_update_cookie(struct task_struct *p, unsigned long cookie)
56 {
57 	unsigned long old_cookie;
58 	struct rq_flags rf;
59 	struct rq *rq;
60 	bool enqueued;
61 
62 	rq = task_rq_lock(p, &rf);
63 
64 	/*
65 	 * Since creating a cookie implies sched_core_get(), and we cannot set
66 	 * a cookie until after we've created it, similarly, we cannot destroy
67 	 * a cookie until after we've removed it, we must have core scheduling
68 	 * enabled here.
69 	 */
70 	SCHED_WARN_ON((p->core_cookie || cookie) && !sched_core_enabled(rq));
71 
72 	enqueued = sched_core_enqueued(p);
73 	if (enqueued)
74 		sched_core_dequeue(rq, p);
75 
76 	old_cookie = p->core_cookie;
77 	p->core_cookie = cookie;
78 
79 	if (enqueued)
80 		sched_core_enqueue(rq, p);
81 
82 	/*
83 	 * If task is currently running, it may not be compatible anymore after
84 	 * the cookie change, so enter the scheduler on its CPU to schedule it
85 	 * away.
86 	 */
87 	if (task_running(rq, p))
88 		resched_curr(rq);
89 
90 	task_rq_unlock(rq, p, &rf);
91 
92 	return old_cookie;
93 }
94 
95 static unsigned long sched_core_clone_cookie(struct task_struct *p)
96 {
97 	unsigned long cookie, flags;
98 
99 	raw_spin_lock_irqsave(&p->pi_lock, flags);
100 	cookie = sched_core_get_cookie(p->core_cookie);
101 	raw_spin_unlock_irqrestore(&p->pi_lock, flags);
102 
103 	return cookie;
104 }
105 
106 void sched_core_free(struct task_struct *p)
107 {
108 	sched_core_put_cookie(p->core_cookie);
109 }
110