]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/tpp.c
b2429f97df958377bcd62697db4a57d7ef873aaf
[thirdparty/glibc.git] / nptl / tpp.c
1 /* Thread Priority Protect helpers.
2 Copyright (C) 2006-2013 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
5
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.
10
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.
15
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 <http://www.gnu.org/licenses/>. */
19
20 #include <assert.h>
21 #include <atomic.h>
22 #include <errno.h>
23 #include <pthreadP.h>
24 #include <sched.h>
25 #include <stdlib.h>
26
27
28 int __sched_fifo_min_prio = -1;
29 int __sched_fifo_max_prio = -1;
30
31 void
32 __init_sched_fifo_prio (void)
33 {
34 __sched_fifo_max_prio = sched_get_priority_max (SCHED_FIFO);
35 atomic_write_barrier ();
36 __sched_fifo_min_prio = sched_get_priority_min (SCHED_FIFO);
37 }
38
39 int
40 __pthread_tpp_change_priority (int previous_prio, int new_prio)
41 {
42 struct pthread *self = THREAD_SELF;
43 struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp);
44
45 if (tpp == NULL)
46 {
47 if (__sched_fifo_min_prio == -1)
48 __init_sched_fifo_prio ();
49
50 size_t size = sizeof *tpp;
51 size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1)
52 * sizeof (tpp->priomap[0]);
53 tpp = calloc (size, 1);
54 if (tpp == NULL)
55 return ENOMEM;
56 tpp->priomax = __sched_fifo_min_prio - 1;
57 THREAD_SETMEM (self, tpp, tpp);
58 }
59
60 assert (new_prio == -1
61 || (new_prio >= __sched_fifo_min_prio
62 && new_prio <= __sched_fifo_max_prio));
63 assert (previous_prio == -1
64 || (previous_prio >= __sched_fifo_min_prio
65 && previous_prio <= __sched_fifo_max_prio));
66
67 int priomax = tpp->priomax;
68 int newpriomax = priomax;
69 if (new_prio != -1)
70 {
71 if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0)
72 return EAGAIN;
73 ++tpp->priomap[new_prio - __sched_fifo_min_prio];
74 if (new_prio > priomax)
75 newpriomax = new_prio;
76 }
77
78 if (previous_prio != -1)
79 {
80 if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0
81 && priomax == previous_prio
82 && previous_prio > new_prio)
83 {
84 int i;
85 for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i)
86 if (tpp->priomap[i - __sched_fifo_min_prio])
87 break;
88 newpriomax = i;
89 }
90 }
91
92 if (priomax == newpriomax)
93 return 0;
94
95 lll_lock (self->lock, LLL_PRIVATE);
96
97 tpp->priomax = newpriomax;
98
99 int result = 0;
100
101 if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
102 {
103 if (__sched_getparam (self->tid, &self->schedparam) != 0)
104 result = errno;
105 else
106 self->flags |= ATTR_FLAG_SCHED_SET;
107 }
108
109 if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
110 {
111 self->schedpolicy = __sched_getscheduler (self->tid);
112 if (self->schedpolicy == -1)
113 result = errno;
114 else
115 self->flags |= ATTR_FLAG_POLICY_SET;
116 }
117
118 if (result == 0)
119 {
120 struct sched_param sp = self->schedparam;
121 if (sp.sched_priority < newpriomax || sp.sched_priority < priomax)
122 {
123 if (sp.sched_priority < newpriomax)
124 sp.sched_priority = newpriomax;
125
126 if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0)
127 result = errno;
128 }
129 }
130
131 lll_unlock (self->lock, LLL_PRIVATE);
132
133 return result;
134 }
135
136 int
137 __pthread_current_priority (void)
138 {
139 struct pthread *self = THREAD_SELF;
140 if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
141 == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
142 return self->schedparam.sched_priority;
143
144 int result = 0;
145
146 lll_lock (self->lock, LLL_PRIVATE);
147
148 if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
149 {
150 if (__sched_getparam (self->tid, &self->schedparam) != 0)
151 result = -1;
152 else
153 self->flags |= ATTR_FLAG_SCHED_SET;
154 }
155
156 if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
157 {
158 self->schedpolicy = __sched_getscheduler (self->tid);
159 if (self->schedpolicy == -1)
160 result = -1;
161 else
162 self->flags |= ATTR_FLAG_POLICY_SET;
163 }
164
165 if (result != -1)
166 result = self->schedparam.sched_priority;
167
168 lll_unlock (self->lock, LLL_PRIVATE);
169
170 return result;
171 }