1 /* Thread Priority Protect helpers.
2 Copyright (C) 2006-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
28 int __sched_fifo_min_prio
= -1;
29 libc_hidden_data_def (__sched_fifo_min_prio
)
30 int __sched_fifo_max_prio
= -1;
31 libc_hidden_data_def (__sched_fifo_max_prio
)
33 /* We only want to initialize __sched_fifo_min_prio and __sched_fifo_max_prio
34 once. The standard solution would be similar to pthread_once, but then
35 readers would need to use an acquire fence. In this specific case,
36 initialization is comprised of just idempotent writes to two variables
37 that have an initial value of -1. Therefore, we can treat each variable as
38 a separate, at-least-once initialized value. This enables using just
39 relaxed MO loads and stores, but requires that consumers check for
40 initialization of each value that is to be used; see
41 __pthread_tpp_change_priority for an example.
44 __init_sched_fifo_prio (void)
46 atomic_store_relaxed (&__sched_fifo_max_prio
,
47 __sched_get_priority_max (SCHED_FIFO
));
48 atomic_store_relaxed (&__sched_fifo_min_prio
,
49 __sched_get_priority_min (SCHED_FIFO
));
51 libc_hidden_def (__init_sched_fifo_prio
)
54 __pthread_tpp_change_priority (int previous_prio
, int new_prio
)
56 struct pthread
*self
= THREAD_SELF
;
57 struct priority_protection_data
*tpp
= THREAD_GETMEM (self
, tpp
);
58 int fifo_min_prio
= atomic_load_relaxed (&__sched_fifo_min_prio
);
59 int fifo_max_prio
= atomic_load_relaxed (&__sched_fifo_max_prio
);
63 /* See __init_sched_fifo_prio. We need both the min and max prio,
64 so need to check both, and run initialization if either one is
65 not initialized. The memory model's write-read coherence rule
67 if (fifo_min_prio
== -1 || fifo_max_prio
== -1)
69 __init_sched_fifo_prio ();
70 fifo_min_prio
= atomic_load_relaxed (&__sched_fifo_min_prio
);
71 fifo_max_prio
= atomic_load_relaxed (&__sched_fifo_max_prio
);
74 size_t size
= sizeof *tpp
;
75 size
+= (fifo_max_prio
- fifo_min_prio
+ 1)
76 * sizeof (tpp
->priomap
[0]);
77 tpp
= calloc (size
, 1);
80 tpp
->priomax
= fifo_min_prio
- 1;
81 THREAD_SETMEM (self
, tpp
, tpp
);
84 assert (new_prio
== -1
85 || (new_prio
>= fifo_min_prio
86 && new_prio
<= fifo_max_prio
));
87 assert (previous_prio
== -1
88 || (previous_prio
>= fifo_min_prio
89 && previous_prio
<= fifo_max_prio
));
91 int priomax
= tpp
->priomax
;
92 int newpriomax
= priomax
;
95 if (tpp
->priomap
[new_prio
- fifo_min_prio
] + 1 == 0)
97 ++tpp
->priomap
[new_prio
- fifo_min_prio
];
98 if (new_prio
> priomax
)
99 newpriomax
= new_prio
;
102 if (previous_prio
!= -1)
104 if (--tpp
->priomap
[previous_prio
- fifo_min_prio
] == 0
105 && priomax
== previous_prio
106 && previous_prio
> new_prio
)
109 for (i
= previous_prio
- 1; i
>= fifo_min_prio
; --i
)
110 if (tpp
->priomap
[i
- fifo_min_prio
])
116 if (priomax
== newpriomax
)
119 /* See CREATE THREAD NOTES in nptl/pthread_create.c. */
120 lll_lock (self
->lock
, LLL_PRIVATE
);
122 tpp
->priomax
= newpriomax
;
126 if ((self
->flags
& ATTR_FLAG_SCHED_SET
) == 0)
128 if (__sched_getparam (self
->tid
, &self
->schedparam
) != 0)
131 self
->flags
|= ATTR_FLAG_SCHED_SET
;
134 if ((self
->flags
& ATTR_FLAG_POLICY_SET
) == 0)
136 self
->schedpolicy
= __sched_getscheduler (self
->tid
);
137 if (self
->schedpolicy
== -1)
140 self
->flags
|= ATTR_FLAG_POLICY_SET
;
145 struct sched_param sp
= self
->schedparam
;
146 if (sp
.sched_priority
< newpriomax
|| sp
.sched_priority
< priomax
)
148 if (sp
.sched_priority
< newpriomax
)
149 sp
.sched_priority
= newpriomax
;
151 if (__sched_setscheduler (self
->tid
, self
->schedpolicy
, &sp
) < 0)
156 lll_unlock (self
->lock
, LLL_PRIVATE
);
160 libc_hidden_def (__pthread_tpp_change_priority
)
163 __pthread_current_priority (void)
165 struct pthread
*self
= THREAD_SELF
;
166 if ((self
->flags
& (ATTR_FLAG_POLICY_SET
| ATTR_FLAG_SCHED_SET
))
167 == (ATTR_FLAG_POLICY_SET
| ATTR_FLAG_SCHED_SET
))
168 return self
->schedparam
.sched_priority
;
172 /* See CREATE THREAD NOTES in nptl/pthread_create.c. */
173 lll_lock (self
->lock
, LLL_PRIVATE
);
175 if ((self
->flags
& ATTR_FLAG_SCHED_SET
) == 0)
177 if (__sched_getparam (self
->tid
, &self
->schedparam
) != 0)
180 self
->flags
|= ATTR_FLAG_SCHED_SET
;
183 if ((self
->flags
& ATTR_FLAG_POLICY_SET
) == 0)
185 self
->schedpolicy
= __sched_getscheduler (self
->tid
);
186 if (self
->schedpolicy
== -1)
189 self
->flags
|= ATTR_FLAG_POLICY_SET
;
193 result
= self
->schedparam
.sched_priority
;
195 lll_unlock (self
->lock
, LLL_PRIVATE
);
199 libc_hidden_def (__pthread_current_priority
)