2000-06-10  Kaz Kylheku  <kaz@ashi.footprints.net>

	* sysdeps/pthread/timer_create.c: Thread matching now done on
	clock type as well as thread attributes.
	There are individual global signal-delivering threads for
	different clock types.
	* sysdeps/pthread/posix-timer.h: Likewise.
	* sysdeps/pthread/timer_routines.c: Likewise.

	* sysdeps/pthread/timer_routines.c: Thread allocation and
	deallocation function now remembers to put thread on active
	list and remove from active list. 
	Thus now the feature of binding multiple timers
	to a single thread actually works.
This commit is contained in:
Ulrich Drepper 2000-06-10 08:28:06 +00:00
parent 15109bd4aa
commit 45dc1187ee
4 changed files with 89 additions and 41 deletions

View File

@ -1,3 +1,18 @@
2000-06-10 Kaz Kylheku <kaz@ashi.footprints.net>
* sysdeps/pthread/timer_create.c: Thread matching now done on
clock type as well as thread attributes.
There are individual global signal-delivering threads for
different clock types.
* sysdeps/pthread/posix-timer.h: Likewise.
* sysdeps/pthread/timer_routines.c: Likewise.
* sysdeps/pthread/timer_routines.c: Thread allocation and
deallocation function now remembers to put thread on active
list and remove from active list.
Thus now the feature of binding multiple timers
to a single thread actually works.
2000-06-10 Ulrich Drepper <drepper@redhat.com> 2000-06-10 Ulrich Drepper <drepper@redhat.com>
* pthread.c (__pthread_create_2_1): Optimize a bit. * pthread.c (__pthread_create_2_1): Optimize a bit.

View File

@ -44,6 +44,7 @@ struct thread_node
pthread_cond_t cond; pthread_cond_t cond;
struct timer_node *current_timer; struct timer_node *current_timer;
pthread_t captured; pthread_t captured;
clockid_t clock_id;
}; };
@ -76,8 +77,16 @@ extern pthread_once_t __timer_init_once_control;
/* Nonzero if initialization of timer implementation failed. */ /* Nonzero if initialization of timer implementation failed. */
extern int __timer_init_failed; extern int __timer_init_failed;
/* Node for the thread used to deliver signals. */ /* Nodes for the threads used to deliver signals. */
extern struct thread_node __timer_signal_thread; /* A distinct thread is used for each clock type. */
extern struct thread_node __timer_signal_thread_rclk;
#ifdef _POSIX_CPUTIME
extern struct thread_node __timer_signal_thread_pclk;
#endif
#ifdef _POSIX_THREAD_CPUTIME
extern struct thread_node __timer_signal_thread_tclk;
#endif
/* Return pointer to timer structure corresponding to ID. */ /* Return pointer to timer structure corresponding to ID. */
@ -160,10 +169,10 @@ extern void __timer_mutex_cancel_handler (void *arg);
extern void __timer_init_once (void); extern void __timer_init_once (void);
extern struct timer_node *__timer_alloc (void); extern struct timer_node *__timer_alloc (void);
extern int __timer_thread_start (struct thread_node *thread); extern int __timer_thread_start (struct thread_node *thread);
extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr); extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr); extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
extern void __timer_dealloc (struct timer_node *timer); extern void __timer_dealloc (struct timer_node *timer);
extern void __timer_thread_dealloc (struct thread_node *thread); extern void __timer_thread_dealloc (struct thread_node *thread);
extern int __timer_thread_queue_timer (struct thread_node *thread, extern void __timer_thread_queue_timer (struct thread_node *thread,
struct timer_node *insert); struct timer_node *insert);
extern void __timer_thread_wakeup (struct thread_node *thread); extern void __timer_thread_wakeup (struct thread_node *thread);

View File

@ -89,16 +89,33 @@ timer_create (clock_id, evp, timerid)
case SIGEV_SIGNAL: case SIGEV_SIGNAL:
/* We have a global thread for delivering timed signals. /* We have a global thread for delivering timed signals.
If it is not running, try to start it up. */ If it is not running, try to start it up. */
if (! __timer_signal_thread.exists) switch (clock_id)
{ {
if (__builtin_expect (__timer_thread_start (&__timer_signal_thread), case CLOCK_REALTIME:
default:
thread = &__timer_signal_thread_rclk;
break;
#ifdef _POSIX_CPUTIME
case CLOCK_PROCESS_CPUTIME_ID:
thread = &__timer_signal_thread_pclk;
break;
#endif
#ifdef _POSIX_THREAD_CPUTIME
case CLOCK_THREAD_CPUTIME_ID:
thread = &__timer_signal_thread_tclk;
break;
#endif
}
if (! thread->exists)
{
if (__builtin_expect (__timer_thread_start (thread),
1) < 0) 1) < 0)
{ {
errno = EAGAIN; errno = EAGAIN;
goto unlock_bail; goto unlock_bail;
} }
} }
thread = &__timer_signal_thread;
break; break;
case SIGEV_THREAD: case SIGEV_THREAD:
@ -112,11 +129,11 @@ timer_create (clock_id, evp, timerid)
pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
/* Try to find existing thread having the right attributes. */ /* Try to find existing thread having the right attributes. */
thread = __timer_thread_find_matching (&newtimer->attr); thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
/* If no existing thread has these attributes, try to allocate one. */ /* If no existing thread has these attributes, try to allocate one. */
if (thread == NULL) if (thread == NULL)
thread = __timer_thread_alloc (&newtimer->attr); thread = __timer_thread_alloc (&newtimer->attr, clock_id);
/* Out of luck; no threads are available. */ /* Out of luck; no threads are available. */
if (__builtin_expect (thread == NULL, 0)) if (__builtin_expect (thread == NULL, 0))

View File

@ -49,7 +49,13 @@ pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
int __timer_init_failed; int __timer_init_failed;
/* Node for the thread used to deliver signals. */ /* Node for the thread used to deliver signals. */
struct thread_node __timer_signal_thread; struct thread_node __timer_signal_thread_rclk;
#ifdef _POSIX_CPUTIME
struct thread_node __timer_signal_thread_pclk;
#endif
#ifdef _POSIX_THREAD_CPUTIME
struct thread_node __timer_signal_thread_tclk;
#endif
/* Lists to keep free and used timers and threads. */ /* Lists to keep free and used timers and threads. */
struct list_links timer_free_list; struct list_links timer_free_list;
@ -127,7 +133,7 @@ timer_links2ptr (struct list_links *list)
/* Initialize a newly allocated thread structure. */ /* Initialize a newly allocated thread structure. */
static void static void
thread_init (struct thread_node *thread, const pthread_attr_t *attr) thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
{ {
if (attr != NULL) if (attr != NULL)
thread->attr = *attr; thread->attr = *attr;
@ -142,6 +148,7 @@ thread_init (struct thread_node *thread, const pthread_attr_t *attr)
pthread_cond_init (&thread->cond, 0); pthread_cond_init (&thread->cond, 0);
thread->current_timer = 0; thread->current_timer = 0;
thread->captured = pthread_self (); thread->captured = pthread_self ();
thread->clock_id = clock_id;
} }
@ -166,7 +173,13 @@ init_module (void)
for (i = 0; i < THREAD_MAXNODES; ++i) for (i = 0; i < THREAD_MAXNODES; ++i)
list_append (&thread_free_list, &thread_array[i].links); list_append (&thread_free_list, &thread_array[i].links);
thread_init (&__timer_signal_thread, 0); thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
#ifdef _POSIX_CPUTIME
thread_init (&__timer_signal_thread_pclk, 0, CLOCK_PROCESS_CPUTIME_ID);
#endif
#ifdef _POSIX_THREAD_CPUTIME
thread_init (&__timer_signal_thread_tclk, 0, CLOCK_THREAD_CPUTIME_ID);
#endif
} }
@ -203,9 +216,10 @@ thread_deinit (struct thread_node *thread)
/* Allocate a thread structure from the global free list. Global /* Allocate a thread structure from the global free list. Global
mutex lock must be held by caller. */ mutex lock must be held by caller. The thread is moved to
the active list. */
struct thread_node * struct thread_node *
__timer_thread_alloc (const pthread_attr_t *desired_attr) __timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
{ {
struct list_links *node = list_first (&thread_free_list); struct list_links *node = list_first (&thread_free_list);
@ -213,7 +227,8 @@ __timer_thread_alloc (const pthread_attr_t *desired_attr)
{ {
struct thread_node *thread = thread_links2ptr (node); struct thread_node *thread = thread_links2ptr (node);
list_unlink (node); list_unlink (node);
thread_init (thread, desired_attr); thread_init (thread, desired_attr, clock_id);
list_append (&thread_active_list, node);
return thread; return thread;
} }
@ -227,6 +242,7 @@ void
__timer_thread_dealloc (struct thread_node *thread) __timer_thread_dealloc (struct thread_node *thread)
{ {
thread_deinit (thread); thread_deinit (thread);
list_unlink (&thread->links);
list_append (&thread_free_list, &thread->links); list_append (&thread_free_list, &thread->links);
} }
@ -247,7 +263,13 @@ thread_cleanup (void *val)
struct thread_node *thread = val; struct thread_node *thread = val;
/* How did the signal thread get killed? */ /* How did the signal thread get killed? */
assert (thread != &__timer_signal_thread); assert (thread != &__timer_signal_thread_rclk);
#ifdef _POSIX_CPUTIME
assert (thread != &__timer_signal_thread_pclk);
#endif
#ifdef _POSIX_THREAD_CPUTIME
assert (thread != &__timer_signal_thread_tclk);
#endif
pthread_mutex_lock (&__timer_mutex); pthread_mutex_lock (&__timer_mutex);
@ -379,7 +401,7 @@ thread_func (void *arg)
{ {
timespec_add (&timer->expirytime, &now, timespec_add (&timer->expirytime, &now,
&timer->value.it_interval); &timer->value.it_interval);
(void) __timer_thread_queue_timer (self, timer); __timer_thread_queue_timer (self, timer);
} }
thread_expire_timer (self, timer); thread_expire_timer (self, timer);
@ -411,40 +433,23 @@ thread_func (void *arg)
/* Enqueue a timer in wakeup order in the thread's timer queue. */ /* Enqueue a timer in wakeup order in the thread's timer queue. */
int void
__timer_thread_queue_timer (struct thread_node *thread, __timer_thread_queue_timer (struct thread_node *thread,
struct timer_node *insert) struct timer_node *insert)
{ {
struct list_links *iter; struct list_links *iter;
struct list_links *matching = NULL;
struct timer_node *timer = NULL;
for (iter = list_first (&thread->timer_queue); for (iter = list_first (&thread->timer_queue);
iter != list_null (&thread->timer_queue); iter != list_null (&thread->timer_queue);
iter = list_next (iter)) iter = list_next (iter))
{ {
timer = timer_links2ptr (iter); struct timer_node *timer = timer_links2ptr (iter);
if (insert->clock == timer->clock) if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
{ break;
matching = iter;
if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
break;
}
}
if (timer != NULL && insert->clock != timer->clock)
{
if (matching == NULL)
/* We cannot queue this timer. */
return -1;
iter = matching;
} }
list_insbefore (iter, &insert->links); list_insbefore (iter, &insert->links);
return 0;
} }
@ -495,7 +500,8 @@ thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
/* Search the list of active threads and find one which has matching /* Search the list of active threads and find one which has matching
attributes. Global mutex lock must be held by caller. */ attributes. Global mutex lock must be held by caller. */
struct thread_node * struct thread_node *
__timer_thread_find_matching (const pthread_attr_t *desired_attr) __timer_thread_find_matching (const pthread_attr_t *desired_attr,
clockid_t desired_clock_id)
{ {
struct list_links *iter = list_first (&thread_active_list); struct list_links *iter = list_first (&thread_active_list);
@ -503,7 +509,8 @@ __timer_thread_find_matching (const pthread_attr_t *desired_attr)
{ {
struct thread_node *candidate = thread_links2ptr (iter); struct thread_node *candidate = thread_links2ptr (iter);
if (thread_attr_compare (desired_attr, &candidate->attr)) if (thread_attr_compare (desired_attr, &candidate->attr)
&& desired_clock_id == candidate->clock_id)
{ {
list_unlink (iter); list_unlink (iter);
return candidate; return candidate;