int __pthread_tpp_change_priority (int previous_prio, int new_prio) { struct pthread *self = THREAD_SELF; struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp); if (tpp == NULL) { if (__sched_fifo_min_prio == -1) __init_sched_fifo_prio (); size_t size = sizeof *tpp; size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1) * sizeof (tpp->priomap[0]); tpp = calloc (size, 1); if (tpp == NULL) return ENOMEM; tpp->priomax = __sched_fifo_min_prio - 1; THREAD_SETMEM (self, tpp, tpp); } assert (new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)); assert (previous_prio == -1 || (previous_prio >= __sched_fifo_min_prio && previous_prio <= __sched_fifo_max_prio)); int priomax = tpp->priomax; int newpriomax = priomax; if (new_prio != -1) { if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0) return EAGAIN; ++tpp->priomap[new_prio - __sched_fifo_min_prio]; if (new_prio > priomax) newpriomax = new_prio; } if (previous_prio != -1) { if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0 && priomax == previous_prio && previous_prio > new_prio) { int i; for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i) if (tpp->priomap[i - __sched_fifo_min_prio]) break; newpriomax = i; } } if (priomax == newpriomax) return 0; lll_lock (self->lock, LLL_PRIVATE); tpp->priomax = newpriomax; int result = 0; #ifdef TPP_PTHREAD_SCHED int policy; struct sched_param param; #endif if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) { #ifndef TPP_PTHREAD_SCHED if (__sched_getparam (self->tid, &self->schedparam) != 0) #else if (__pthread_getschedparam (self->tid, &policy, &self->schedparam) != 0) #endif result = errno; else self->flags |= ATTR_FLAG_SCHED_SET; } if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) { #ifndef TPP_PTHREAD_SCHED self->schedpolicy = __sched_getscheduler (self->tid); #else if (__pthread_getschedparam (self->tid, &self->schedpolicy, ¶m) != 0) self->schedpolicy = -1; #endif if (self->schedpolicy == -1) result = errno; else self->flags |= ATTR_FLAG_POLICY_SET; } if (result == 0) { struct sched_param sp = self->schedparam; if (sp.sched_priority < newpriomax || sp.sched_priority < priomax) { if (sp.sched_priority < newpriomax) sp.sched_priority = newpriomax; #ifndef TPP_PTHREAD_SCHED if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0) #else if (__pthread_setschedparam (self->tid, self->schedpolicy, &sp) < 0) #endif result = errno; } } lll_unlock (self->lock, LLL_PRIVATE); return result; }
int __pthread_tpp_change_priority (int previous_prio, int new_prio) { struct pthread *self = THREAD_SELF; struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp); int fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); int fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); if (tpp == NULL) { /* See __init_sched_fifo_prio. We need both the min and max prio, so need to check both, and run initialization if either one is not initialized. The memory model's write-read coherence rule makes this work. */ if (fifo_min_prio == -1 || fifo_max_prio == -1) { __init_sched_fifo_prio (); fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); } size_t size = sizeof *tpp; size += (fifo_max_prio - fifo_min_prio + 1) * sizeof (tpp->priomap[0]); tpp = calloc (size, 1); if (tpp == NULL) return ENOMEM; tpp->priomax = fifo_min_prio - 1; THREAD_SETMEM (self, tpp, tpp); } assert (new_prio == -1 || (new_prio >= fifo_min_prio && new_prio <= fifo_max_prio)); assert (previous_prio == -1 || (previous_prio >= fifo_min_prio && previous_prio <= fifo_max_prio)); int priomax = tpp->priomax; int newpriomax = priomax; if (new_prio != -1) { if (tpp->priomap[new_prio - fifo_min_prio] + 1 == 0) return EAGAIN; ++tpp->priomap[new_prio - fifo_min_prio]; if (new_prio > priomax) newpriomax = new_prio; } if (previous_prio != -1) { if (--tpp->priomap[previous_prio - fifo_min_prio] == 0 && priomax == previous_prio && previous_prio > new_prio) { int i; for (i = previous_prio - 1; i >= fifo_min_prio; --i) if (tpp->priomap[i - fifo_min_prio]) break; newpriomax = i; } } if (priomax == newpriomax) return 0; /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ lll_lock (self->lock, LLL_PRIVATE); tpp->priomax = newpriomax; int result = 0; if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) { if (__sched_getparam (self->tid, &self->schedparam) != 0) result = errno; else self->flags |= ATTR_FLAG_SCHED_SET; } if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) { self->schedpolicy = __sched_getscheduler (self->tid); if (self->schedpolicy == -1) result = errno; else self->flags |= ATTR_FLAG_POLICY_SET; } if (result == 0) { struct sched_param sp = self->schedparam; if (sp.sched_priority < newpriomax || sp.sched_priority < priomax) { if (sp.sched_priority < newpriomax) sp.sched_priority = newpriomax; if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0) result = errno; } } lll_unlock (self->lock, LLL_PRIVATE); return result; }