]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libpthread/nptl/sysdeps/pthread/tpp.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libpthread / nptl / sysdeps / pthread / tpp.c
1 /* Thread Priority Protect helpers.
2    Copyright (C) 2006, 2007 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 #include "uClibc-glue.h"
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 }