Back to index

glibc  2.9
tpp.c
Go to the documentation of this file.
00001 /* Thread Priority Protect helpers.
00002    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <assert.h>
00022 #include <atomic.h>
00023 #include <errno.h>
00024 #include <pthreadP.h>
00025 #include <sched.h>
00026 #include <stdlib.h>
00027 
00028 
00029 int __sched_fifo_min_prio = -1;
00030 int __sched_fifo_max_prio = -1;
00031 
00032 void
00033 __init_sched_fifo_prio (void)
00034 {
00035   __sched_fifo_max_prio = sched_get_priority_max (SCHED_FIFO);
00036   atomic_write_barrier ();
00037   __sched_fifo_min_prio = sched_get_priority_min (SCHED_FIFO);
00038 }
00039 
00040 int
00041 __pthread_tpp_change_priority (int previous_prio, int new_prio)
00042 {
00043   struct pthread *self = THREAD_SELF;
00044   struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp);
00045 
00046   if (tpp == NULL)
00047     {
00048       if (__sched_fifo_min_prio == -1)
00049        __init_sched_fifo_prio ();
00050 
00051       size_t size = sizeof *tpp;
00052       size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1)
00053              * sizeof (tpp->priomap[0]);
00054       tpp = calloc (size, 1);
00055       if (tpp == NULL)
00056        return ENOMEM;
00057       tpp->priomax = __sched_fifo_min_prio - 1;
00058       THREAD_SETMEM (self, tpp, tpp);
00059     }
00060 
00061   assert (new_prio == -1
00062          || (new_prio >= __sched_fifo_min_prio
00063              && new_prio <= __sched_fifo_max_prio));
00064   assert (previous_prio == -1
00065          || (previous_prio >= __sched_fifo_min_prio
00066              && previous_prio <= __sched_fifo_max_prio));
00067 
00068   int priomax = tpp->priomax;
00069   int newpriomax = priomax;
00070   if (new_prio != -1)
00071     {
00072       if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0)
00073        return EAGAIN;
00074       ++tpp->priomap[new_prio - __sched_fifo_min_prio];
00075       if (new_prio > priomax)
00076        newpriomax = new_prio;
00077     }
00078 
00079   if (previous_prio != -1)
00080     {
00081       if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0
00082          && priomax == previous_prio
00083          && previous_prio > new_prio)
00084        {
00085          int i;
00086          for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i)
00087            if (tpp->priomap[i - __sched_fifo_min_prio])
00088              break;
00089          newpriomax = i;
00090        }
00091     }
00092 
00093   if (priomax == newpriomax)
00094     return 0;
00095 
00096   lll_lock (self->lock, LLL_PRIVATE);
00097 
00098   tpp->priomax = newpriomax;
00099 
00100   int result = 0;
00101 
00102   if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
00103     {
00104       if (__sched_getparam (self->tid, &self->schedparam) != 0)
00105        result = errno;
00106       else
00107        self->flags |= ATTR_FLAG_SCHED_SET;
00108     }
00109 
00110   if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
00111     {
00112       self->schedpolicy = __sched_getscheduler (self->tid);
00113       if (self->schedpolicy == -1)
00114        result = errno;
00115       else
00116        self->flags |= ATTR_FLAG_POLICY_SET;
00117     }
00118 
00119   if (result == 0)
00120     {
00121       struct sched_param sp = self->schedparam;
00122       if (sp.sched_priority < newpriomax || sp.sched_priority < priomax)
00123        {
00124          if (sp.sched_priority < newpriomax)
00125            sp.sched_priority = newpriomax;
00126 
00127          if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0)
00128            result = errno;
00129        }
00130     }
00131 
00132   lll_unlock (self->lock, LLL_PRIVATE);
00133 
00134   return result;
00135 }
00136 
00137 int
00138 __pthread_current_priority (void)
00139 {
00140   struct pthread *self = THREAD_SELF;
00141   if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
00142       == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
00143     return self->schedparam.sched_priority;
00144 
00145   int result = 0;
00146 
00147   lll_lock (self->lock, LLL_PRIVATE);
00148 
00149   if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
00150     {
00151       if (__sched_getparam (self->tid, &self->schedparam) != 0)
00152        result = -1;
00153       else
00154        self->flags |= ATTR_FLAG_SCHED_SET;
00155     }
00156 
00157   if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
00158     {
00159       self->schedpolicy = __sched_getscheduler (self->tid);
00160       if (self->schedpolicy == -1)
00161        result = -1;
00162       else
00163        self->flags |= ATTR_FLAG_POLICY_SET;
00164     }
00165 
00166   if (result != -1)
00167     result = self->schedparam.sched_priority;
00168 
00169   lll_unlock (self->lock, LLL_PRIVATE);
00170 
00171   return result;
00172 }