aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads')
-rw-r--r--linuxthreads/ChangeLog33
-rw-r--r--linuxthreads/sysdeps/pthread/posix-timer.h28
-rw-r--r--linuxthreads/sysdeps/pthread/timer_getoverr.c4
-rw-r--r--linuxthreads/sysdeps/pthread/timer_gettime.c35
-rw-r--r--linuxthreads/sysdeps/pthread/timer_routines.c12
-rw-r--r--linuxthreads/sysdeps/pthread/timer_settime.c13
6 files changed, 96 insertions, 29 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 2322ca91e6..0402c0fdfe 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,36 @@
+2000-06-19 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/pthread/timer_create.c: Use _set_errno instead of assigning
+ to errno directly.
+ * sysdeps/pthread/timer_delete.c: Likewise.
+ * sysdeps/pthread/timer_getoverr.c: Likewise.
+ * sysdeps/pthread/timer_gettime.c: Likewise.
+ * sysdeps/pthread/timer_settime.c: Likewise.
+
+2000-06-13 Kaz Kylheku <kaz@ashi.footprints.net>
+
+ Timer nodes are now reference counted, and can be marked
+ as deleted. This allows for the safe release of the global mutex
+ in the middle without losing the timer being operated on.
+
+ * sysdeps/pthread/posix-timer.h (struct timer_node): The inuse
+ member is now an enum with three values, so that an intermediate
+ state can be represented (deleted but not free for reuse yet).
+ New refcount member added.
+ * sysdeps/pthread/timer_routines.c: Likewise.
+
+ * sysdeps/pthread/posix-timer.h (timer_addref, timer_delref,
+ timer_valid): New inline functions added.
+
+ * sysdeps/pthread/timer_gettime.c (timer_gettime): Function
+ restructured, recursive deadlock bug fixed.
+
+ * sysdeps/pthread/timer_gettime.c (timer_gettime): Uses new
+ timer_addref to ensure that timer won't be deleted while mutex is not
+ held. Also uses timer_invalid to perform validation of timer handle.
+ * sysdeps/pthread/timer_settime.c (timer_settime): Likewise.
+ * sysdeps/pthread/timer_getoverr.c (timer_getoverrun): Likewise.
+
2000-06-14 Ulrich Drepper <drepper@redhat.com>
* shlib-versions: Add entry for SH.
diff --git a/linuxthreads/sysdeps/pthread/posix-timer.h b/linuxthreads/sysdeps/pthread/posix-timer.h
index feeff39fa8..7a2caf28a4 100644
--- a/linuxthreads/sysdeps/pthread/posix-timer.h
+++ b/linuxthreads/sysdeps/pthread/posix-timer.h
@@ -59,9 +59,12 @@ struct timer_node
pthread_attr_t attr;
unsigned int abstime;
unsigned int armed;
- unsigned int inuse;
+ enum {
+ TIMER_FREE, TIMER_INUSE, TIMER_DELETED
+ } inuse;
struct thread_node *thread;
pid_t creator_pid;
+ int refcount;
};
@@ -106,6 +109,28 @@ timer_ptr2id (struct timer_node *timer)
return timer - __timer_array;
}
+/* Check whether timer is valid; global mutex must be held. */
+static inline int
+timer_valid (struct timer_node *timer)
+{
+ return timer && timer->inuse == TIMER_INUSE;
+}
+
+/* Timer refcount functions; need global mutex. */
+extern void __timer_dealloc (struct timer_node *timer);
+
+static inline void
+timer_addref (struct timer_node *timer)
+{
+ timer->refcount++;
+}
+
+static inline void
+timer_delref (struct timer_node *timer)
+{
+ if (--timer->refcount == 0)
+ __timer_dealloc (timer);
+}
/* Timespec helper routines. */
static inline int
@@ -178,7 +203,6 @@ extern struct timer_node *__timer_alloc (void);
extern int __timer_thread_start (struct thread_node *thread);
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, clockid_t);
-extern void __timer_dealloc (struct timer_node *timer);
extern void __timer_thread_dealloc (struct thread_node *thread);
extern int __timer_thread_queue_timer (struct thread_node *thread,
struct timer_node *insert);
diff --git a/linuxthreads/sysdeps/pthread/timer_getoverr.c b/linuxthreads/sysdeps/pthread/timer_getoverr.c
index 8630f57829..520458c712 100644
--- a/linuxthreads/sysdeps/pthread/timer_getoverr.c
+++ b/linuxthreads/sysdeps/pthread/timer_getoverr.c
@@ -34,8 +34,8 @@ timer_getoverrun (timerid)
pthread_mutex_lock (&__timer_mutex);
- if ((timer = timer_id2ptr (timerid)) == NULL || !timer->inuse)
- errno = EINVAL;
+ if (! timer_valid (timer = timer_id2ptr (timerid)))
+ __set_errno (EINVAL);
else
retval = 0; /* TODO: overrun counting not supported */
diff --git a/linuxthreads/sysdeps/pthread/timer_gettime.c b/linuxthreads/sysdeps/pthread/timer_gettime.c
index 43b07598b7..dbee9d915e 100644
--- a/linuxthreads/sysdeps/pthread/timer_gettime.c
+++ b/linuxthreads/sysdeps/pthread/timer_gettime.c
@@ -31,25 +31,30 @@ timer_gettime (timerid, value)
struct itimerspec *value;
{
struct timer_node *timer;
- struct timespec now;
- int retval = -1;
+ struct timespec now, expiry;
+ int retval = -1, armed = 0, valid;
+ clock_t clock = 0;
pthread_mutex_lock (&__timer_mutex);
timer = timer_id2ptr (timerid);
- if (timer == NULL && !timer->inuse)
- /* Invalid timer ID or the timer is not in use. */
- errno = EINVAL;
- else
- {
- value->it_interval = timer->value.it_interval;
+ valid = timer_valid (timer);
+
+ if (valid) {
+ armed = timer->armed;
+ expiry = timer->expirytime;
+ clock = timer->clock;
+ value->it_interval = timer->value.it_interval;
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
- if (timer->armed)
+ if (valid)
+ {
+ if (armed)
{
- pthread_mutex_unlock (&__timer_mutex);
- clock_gettime (timer->clock, &now);
- pthread_mutex_lock (&__timer_mutex);
- timespec_sub (&value->it_value, &timer->expirytime, &now);
+ clock_gettime (clock, &now);
+ timespec_sub (&value->it_value, &expiry, &now);
}
else
{
@@ -59,8 +64,8 @@ timer_gettime (timerid, value)
retval = 0;
}
-
- pthread_mutex_lock (&__timer_mutex);
+ else
+ __set_errno (EINVAL);
return retval;
}
diff --git a/linuxthreads/sysdeps/pthread/timer_routines.c b/linuxthreads/sysdeps/pthread/timer_routines.c
index ddf02fadd6..2d4e325b6d 100644
--- a/linuxthreads/sysdeps/pthread/timer_routines.c
+++ b/linuxthreads/sysdeps/pthread/timer_routines.c
@@ -181,7 +181,7 @@ init_module (void)
for (i = 0; i < TIMER_MAX; ++i)
{
list_append (&timer_free_list, &__timer_array[i].links);
- __timer_array[i].inuse = 0;
+ __timer_array[i].inuse = TIMER_FREE;
}
for (i = 0; i < THREAD_MAXNODES; ++i)
@@ -309,7 +309,7 @@ thread_cleanup (void *val)
static void
thread_expire_timer (struct thread_node *self, struct timer_node *timer)
{
- self->current_timer = timer;
+ self->current_timer = timer; /* Lets timer_delete know timer is running. */
pthread_mutex_unlock (&__timer_mutex);
@@ -443,7 +443,7 @@ 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.
Returns 1 if the timer was inserted at the head of the queue,
causing the queue's next wakeup time to change. */
@@ -551,7 +551,8 @@ __timer_alloc (void)
{
struct timer_node *timer = timer_links2ptr (node);
list_unlink_ip (node);
- timer->inuse = 1;
+ timer->inuse = TIMER_INUSE;
+ timer->refcount = 1;
return timer;
}
@@ -564,8 +565,9 @@ __timer_alloc (void)
void
__timer_dealloc (struct timer_node *timer)
{
+ assert (timer->refcount == 0);
timer->thread = NULL; /* Break association between timer and thread. */
- timer->inuse = 0;
+ timer->inuse = TIMER_FREE;
list_append (&timer_free_list, &timer->links);
}
diff --git a/linuxthreads/sysdeps/pthread/timer_settime.c b/linuxthreads/sysdeps/pthread/timer_settime.c
index 858edc7657..e6c35b4fcf 100644
--- a/linuxthreads/sysdeps/pthread/timer_settime.c
+++ b/linuxthreads/sysdeps/pthread/timer_settime.c
@@ -41,7 +41,7 @@ timer_settime (timerid, flags, value, ovalue)
timer = timer_id2ptr (timerid);
if (timer == NULL)
{
- errno = EINVAL;
+ __set_errno (EINVAL);
goto bail;
}
@@ -50,7 +50,7 @@ timer_settime (timerid, flags, value, ovalue)
|| value->it_value.tv_nsec < 0
|| value->it_value.tv_nsec >= 1000000000)
{
- errno = EINVAL;
+ __set_errno (EINVAL);
goto bail;
}
@@ -64,13 +64,14 @@ timer_settime (timerid, flags, value, ovalue)
}
pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
/* One final check of timer validity; this one is possible only
- until we have the mutex, which guards the inuse flag. */
+ until we have the mutex, because it accesses the inuse flag. */
- if (!timer->inuse)
+ if (! timer_valid(timer))
{
- errno = EINVAL;
+ __set_errno (EINVAL);
goto unlock_bail;
}
@@ -86,6 +87,7 @@ timer_settime (timerid, flags, value, ovalue)
clock_gettime (timer->clock, &now);
have_now = 1;
pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
}
timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
@@ -123,6 +125,7 @@ timer_settime (timerid, flags, value, ovalue)
retval = 0;
unlock_bail:
+ timer_delref (timer);
pthread_mutex_unlock (&__timer_mutex);
bail: