This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: The problem with __pthread_manager_adjust_prio
- From: "H . J . Lu" <hjl at lucon dot org>
- To: GNU C Library <libc-alpha at sources dot redhat dot com>
- Date: Thu, 21 Mar 2002 00:24:44 -0800
- Subject: Re: The problem with __pthread_manager_adjust_prio
- References: <20020320165008.A7890@lucon.org>
On Wed, Mar 20, 2002 at 04:50:08PM -0800, H . J . Lu wrote:
> There is a race condition between __pthread_manager_adjust_prio
> called from pthread_setschedparam and pthread_start_thread on
> manager_thread->p_priority. When a thread is calling
> pthread_setschedparam, the new thread may inherit SCHED_FIFO from
> the manager thread. That is
>
> Thread A calls pthread_setschedparam
> calls __pthread_manager_adjust_prio
> calls __sched_setscheduler (SCHED_FIFO) on the manager thread.
> The main thread calls pthread_create
> The manager threads calls pthread_start_thread. It does
>
> if (manager_thread->p_priority > 0)
> __sched_setscheduler (SCHED_OTHER)
>
> Since manager_thread->p_priority may not be changed by
> __pthread_manager_adjust_prio yet, the new thread may inherit
> SCHED_FIFO. Here is a patch. the worst case is pthread_start_thread
> may call __sched_setscheduler (SCHED_OTHER) before
> __sched_setscheduler (SCHED_FIFO) is called on the manager thread.
>
A new patch with spinlock.
H.J.
----
2002-03-20 H.J. Lu <hjl@gnu.org>
* manager.c (pthread_start_thread): Protect accees to
manager_thread->p_priority with manager_thread->p_lock.
(__pthread_manager_adjust_prio): Likewise.
--- linuxthreads/manager.c.sched Wed Mar 20 23:35:52 2002
+++ linuxthreads/manager.c Thu Mar 21 00:05:34 2002
@@ -295,15 +295,24 @@ pthread_start_thread(void *arg)
__sched_setscheduler(THREAD_GETMEM(self, p_pid),
THREAD_GETMEM(self, p_start_args.schedpolicy),
&self->p_start_args.schedparam);
- else if (manager_thread->p_priority > 0)
- /* Default scheduling required, but thread manager runs in realtime
- scheduling: switch new thread to SCHED_OTHER policy */
+ else
{
- struct sched_param default_params;
- default_params.sched_priority = 0;
- __sched_setscheduler(THREAD_GETMEM(self, p_pid),
- SCHED_OTHER, &default_params);
+ int set_sched;
+ __pthread_lock(manager_thread->p_lock, NULL);
+ set_sched = manager_thread->p_priority > 0;
+ __pthread_unlock(manager_thread->p_lock);
+ if (set_sched)
+ /* Default scheduling required, but thread manager runs in
+ realtime scheduling: switch new thread to SCHED_OTHER
+ policy */
+ {
+ struct sched_param default_params;
+ default_params.sched_priority = 0;
+ __sched_setscheduler(THREAD_GETMEM(self, p_pid),
+ SCHED_OTHER, &default_params);
+ }
}
+
/* Make gdb aware of new thread */
if (__pthread_threads_debug && __pthread_sig_debug > 0) {
request.req_thread = self;
@@ -1076,12 +1085,20 @@ void __pthread_manager_sighandler(int si
void __pthread_manager_adjust_prio(int thread_prio)
{
- struct sched_param param;
+ int set_sched;
- if (thread_prio <= manager_thread->p_priority) return;
- param.sched_priority =
- thread_prio < __sched_get_priority_max(SCHED_FIFO)
- ? thread_prio + 1 : thread_prio;
- __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, ¶m);
- manager_thread->p_priority = thread_prio;
+ __pthread_lock(manager_thread->p_lock, NULL);
+ set_sched = thread_prio > manager_thread->p_priority;
+ if (set_sched)
+ manager_thread->p_priority = thread_prio;
+ __pthread_unlock(manager_thread->p_lock);
+
+ if (set_sched)
+ {
+ struct sched_param param;
+ param.sched_priority =
+ thread_prio < __sched_get_priority_max(SCHED_FIFO)
+ ? thread_prio + 1 : thread_prio;
+ __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, ¶m);
+ }
}