mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 21:10:07 +00:00
Update.
* sysdeps/pthread/Makefile: New file. Add rules to build timer functionality. * sysdeps/unix/sysv/linux/bits/local_lim.h: Add TIMER_MAX. 2000-06-04 Kaz Kylheku <kaz@ashi.footprints.net> * sysdeps/pthread/posix-timer.h: New file. * sysdeps/pthread/timer_create.c: New file. * sysdeps/pthread/timer_delete.c: New file. * sysdeps/pthread/timer_getoverr.c: New file. * sysdeps/pthread/timer_gettime.c: New file. * sysdeps/pthread/timer_routines.c: New file. * sysdeps/pthread/timer_settime.c: New file. * sysdeps/pthread/tst-timer.c: New file. 2000-06-08 Ulrich Drepper <drepper@redhat.com>
This commit is contained in:
parent
47bc7a9be1
commit
2715f28ad4
@ -1,3 +1,20 @@
|
||||
2000-06-08 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/pthread/Makefile: New file. Add rules to build timer
|
||||
functionality.
|
||||
* sysdeps/unix/sysv/linux/bits/local_lim.h: Add TIMER_MAX.
|
||||
|
||||
2000-06-04 Kaz Kylheku <kaz@ashi.footprints.net>
|
||||
|
||||
* sysdeps/pthread/posix-timer.h: New file.
|
||||
* sysdeps/pthread/timer_create.c: New file.
|
||||
* sysdeps/pthread/timer_delete.c: New file.
|
||||
* sysdeps/pthread/timer_getoverr.c: New file.
|
||||
* sysdeps/pthread/timer_gettime.c: New file.
|
||||
* sysdeps/pthread/timer_routines.c: New file.
|
||||
* sysdeps/pthread/timer_settime.c: New file.
|
||||
* sysdeps/pthread/tst-timer.c: New file.
|
||||
|
||||
2000-06-08 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/bits/local_lim.h: Remove OPEN_MAX and
|
||||
|
13
linuxthreads/sysdeps/pthread/Makefile
Normal file
13
linuxthreads/sysdeps/pthread/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
ifeq ($(subdir),rt)
|
||||
librt-routines += timer_routines
|
||||
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += tst-timer
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
$(objpfx)tst-timer: $(objpfx)librt.so $(shared-thread-library)
|
||||
else
|
||||
$(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library)
|
||||
endif
|
||||
endif
|
168
linuxthreads/sysdeps/pthread/posix-timer.h
Normal file
168
linuxthreads/sysdeps/pthread/posix-timer.h
Normal file
@ -0,0 +1,168 @@
|
||||
/* Definitions for POSIX timer implementation on top of LinuxThreads.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* Double linked list. */
|
||||
struct list_links
|
||||
{
|
||||
struct list_links *next;
|
||||
struct list_links *prev;
|
||||
};
|
||||
|
||||
|
||||
/* Forward declaration. */
|
||||
struct timer_node;
|
||||
|
||||
|
||||
/* Definitions for an internal thread of the POSIX timer implementation. */
|
||||
struct thread_node
|
||||
{
|
||||
struct list_links links;
|
||||
pthread_attr_t attr;
|
||||
pthread_t id;
|
||||
unsigned int exists;
|
||||
struct list_links timer_queue;
|
||||
pthread_cond_t cond;
|
||||
struct timer_node *current_timer;
|
||||
pthread_t captured;
|
||||
};
|
||||
|
||||
|
||||
/* Internal representation of a timer. */
|
||||
struct timer_node
|
||||
{
|
||||
struct list_links links;
|
||||
struct sigevent event;
|
||||
clockid_t clock;
|
||||
struct itimerspec value;
|
||||
struct timespec expirytime;
|
||||
pthread_attr_t attr;
|
||||
unsigned int abstime;
|
||||
unsigned int armed;
|
||||
unsigned int inuse;
|
||||
struct thread_node *thread;
|
||||
};
|
||||
|
||||
|
||||
/* Static array with the structures for all the timers. */
|
||||
extern struct timer_node __timer_array[TIMER_MAX];
|
||||
|
||||
/* Global lock to protect operation on the lists. */
|
||||
extern pthread_mutex_t __timer_mutex;
|
||||
|
||||
/* Variable to protext initialization. */
|
||||
extern pthread_once_t __timer_init_once_control;
|
||||
|
||||
/* Nonzero if initialization of timer implementation failed. */
|
||||
extern int __timer_init_failed;
|
||||
|
||||
/* Node for the thread used to deliver signals. */
|
||||
extern struct thread_node __timer_signal_thread;
|
||||
|
||||
|
||||
/* Return pointer to timer structure corresponding to ID. */
|
||||
static inline struct timer_node *
|
||||
timer_id2ptr (timer_t timerid)
|
||||
{
|
||||
if (timerid >= 0 && timerid < TIMER_MAX && __timer_array[timerid].inuse)
|
||||
return &__timer_array[timerid];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return ID of TIMER. */
|
||||
static inline int
|
||||
timer_ptr2id (struct timer_node *timer)
|
||||
{
|
||||
return __timer_array - timer;
|
||||
}
|
||||
|
||||
|
||||
/* Timespec helper routines. */
|
||||
static inline int
|
||||
timespec_compare (const struct timespec *left, const struct timespec *right)
|
||||
{
|
||||
if (left->tv_sec < right->tv_sec)
|
||||
return -1;
|
||||
if (left->tv_sec > right->tv_sec)
|
||||
return 1;
|
||||
|
||||
if (left->tv_nsec < right->tv_nsec)
|
||||
return -1;
|
||||
if (left->tv_nsec > right->tv_nsec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
timespec_add (struct timespec *sum, const struct timespec *left,
|
||||
const struct timespec *right)
|
||||
{
|
||||
sum->tv_sec = left->tv_sec + right->tv_sec;
|
||||
sum->tv_nsec = left->tv_nsec + right->tv_nsec;
|
||||
|
||||
if (sum->tv_nsec >= 1000000000)
|
||||
{
|
||||
++sum->tv_sec;
|
||||
sum->tv_nsec -= 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
timespec_sub (struct timespec *diff, const struct timespec *left,
|
||||
const struct timespec *right)
|
||||
{
|
||||
diff->tv_sec = left->tv_sec - right->tv_sec;
|
||||
diff->tv_nsec = left->tv_nsec - right->tv_nsec;
|
||||
|
||||
if (diff->tv_nsec < 0)
|
||||
{
|
||||
--diff->tv_sec;
|
||||
diff->tv_nsec += 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We need one of the list functions in the other modules. */
|
||||
static inline void
|
||||
list_unlink (struct list_links *list)
|
||||
{
|
||||
list->next->prev = list->prev;
|
||||
list->prev->next = list->next;
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
|
||||
/* Functions in the helper file. */
|
||||
extern void __timer_mutex_cancel_handler (void *arg);
|
||||
extern void __timer_init_once (void);
|
||||
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);
|
||||
extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr);
|
||||
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);
|
||||
extern void __timer_thread_wakeup (struct thread_node *thread);
|
153
linuxthreads/sysdeps/pthread/timer_create.c
Normal file
153
linuxthreads/sysdeps/pthread/timer_create.c
Normal file
@ -0,0 +1,153 @@
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Create new per-process timer using CLOCK. */
|
||||
int
|
||||
timer_create (clock_id, evp, timerid)
|
||||
clockid_t clock_id;
|
||||
struct sigevent *evp;
|
||||
timer_t *timerid;
|
||||
{
|
||||
int retval = -1;
|
||||
struct timer_node *newtimer = NULL;
|
||||
struct thread_node *thread = NULL;
|
||||
|
||||
if (clock_id != CLOCK_REALTIME)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_once (&__timer_init_once_control, __timer_init_once);
|
||||
|
||||
if (__timer_init_failed)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
newtimer = __timer_alloc ();
|
||||
if (__builtin_expect (newtimer == NULL, 0))
|
||||
{
|
||||
errno = EAGAIN;
|
||||
goto unlock_bail;
|
||||
}
|
||||
|
||||
if (evp != NULL)
|
||||
newtimer->event = *evp;
|
||||
else
|
||||
{
|
||||
newtimer->event.sigev_notify = SIGEV_SIGNAL;
|
||||
newtimer->event.sigev_signo = SIGALRM;
|
||||
newtimer->event.sigev_value.sival_int = timer_ptr2id (newtimer);
|
||||
newtimer->event.sigev_notify_function = 0;
|
||||
}
|
||||
|
||||
newtimer->event.sigev_notify_attributes = &newtimer->attr;
|
||||
|
||||
switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
|
||||
{
|
||||
case SIGEV_NONE:
|
||||
/* This is a strange choice! */
|
||||
break;
|
||||
|
||||
case SIGEV_SIGNAL:
|
||||
/* We have a global thread for delivering timed signals.
|
||||
If it is not running, try to start it up. */
|
||||
if (! __timer_signal_thread.exists)
|
||||
{
|
||||
if (__builtin_expect (__timer_thread_start (&__timer_signal_thread),
|
||||
1) < 0)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
goto unlock_bail;
|
||||
}
|
||||
}
|
||||
thread = &__timer_signal_thread;
|
||||
break;
|
||||
|
||||
case SIGEV_THREAD:
|
||||
/* Copy over thread attributes or set up default ones. */
|
||||
if (evp->sigev_notify_attributes)
|
||||
newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
|
||||
else
|
||||
pthread_attr_init (&newtimer->attr);
|
||||
|
||||
/* Ensure thread attributes call for deatched thread. */
|
||||
pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
/* Try to find existing thread having the right attributes. */
|
||||
thread = __timer_thread_find_matching (&newtimer->attr);
|
||||
|
||||
/* If no existing thread has these attributes, try to allocate one. */
|
||||
if (thread == NULL)
|
||||
thread = __timer_thread_alloc (&newtimer->attr);
|
||||
|
||||
/* Out of luck; no threads are available. */
|
||||
if (__builtin_expect (thread == NULL, 0))
|
||||
{
|
||||
errno = EAGAIN;
|
||||
goto unlock_bail;
|
||||
}
|
||||
|
||||
/* If the thread is not running already, try to start it. */
|
||||
if (! thread->exists
|
||||
&& __builtin_expect (! __timer_thread_start (thread), 0))
|
||||
{
|
||||
errno = EAGAIN;
|
||||
goto unlock_bail;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
goto unlock_bail;
|
||||
}
|
||||
|
||||
newtimer->clock = clock_id;
|
||||
newtimer->abstime = 0;
|
||||
newtimer->armed = 0;
|
||||
newtimer->thread = thread;
|
||||
|
||||
*timerid = timer_ptr2id (newtimer);
|
||||
retval = 0;
|
||||
|
||||
if (__builtin_expect (retval, 0) == -1)
|
||||
{
|
||||
unlock_bail:
|
||||
if (thread != NULL)
|
||||
__timer_thread_dealloc (thread);
|
||||
if (newtimer != NULL)
|
||||
__timer_dealloc (newtimer);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
69
linuxthreads/sysdeps/pthread/timer_delete.c
Normal file
69
linuxthreads/sysdeps/pthread/timer_delete.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Delete timer TIMERID. */
|
||||
int
|
||||
timer_delete (timerid)
|
||||
timer_t timerid;
|
||||
{
|
||||
struct timer_node *timer;
|
||||
int retval = -1;
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
timer = timer_id2ptr (timerid);
|
||||
if (timer == NULL)
|
||||
/* Invalid timer ID or the timer is not in use. */
|
||||
errno = EINVAL;
|
||||
else
|
||||
{
|
||||
if (timer->armed)
|
||||
{
|
||||
struct thread_node *thread = timer->thread;
|
||||
assert (thread != NULL);
|
||||
|
||||
/* If thread is cancelled while waiting for handler to terminate,
|
||||
the mutex is unlocked and timer_delete is aborted. */
|
||||
pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex);
|
||||
|
||||
/* If timer is currently being serviced, wait for it to finish. */
|
||||
while (thread->current_timer == timer)
|
||||
pthread_cond_wait (&thread->cond, &__timer_mutex);
|
||||
|
||||
pthread_cleanup_pop (0);
|
||||
}
|
||||
|
||||
/* Remove timer from whatever queue it may be on and deallocate it. */
|
||||
list_unlink (&timer->links);
|
||||
__timer_dealloc (timer);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
46
linuxthreads/sysdeps/pthread/timer_getoverr.c
Normal file
46
linuxthreads/sysdeps/pthread/timer_getoverr.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Get expiration overrun for timer TIMERID. */
|
||||
int
|
||||
timer_getoverrun (timerid)
|
||||
timer_t timerid;
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
if (timer_id2ptr (timerid) == NULL)
|
||||
errno = EINVAL;
|
||||
else
|
||||
{
|
||||
retval = 0; /* TODO: overrun counting not supported */
|
||||
}
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
64
linuxthreads/sysdeps/pthread/timer_gettime.c
Normal file
64
linuxthreads/sysdeps/pthread/timer_gettime.c
Normal file
@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Get current value of timer TIMERID and store it in VLAUE. */
|
||||
int
|
||||
timer_gettime (timerid, value)
|
||||
timer_t timerid;
|
||||
struct itimerspec *value;
|
||||
{
|
||||
struct timer_node *timer;
|
||||
struct timespec now;
|
||||
int retval = -1;
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
timer = timer_id2ptr (timerid);
|
||||
if (timer == NULL)
|
||||
/* Invalid timer ID or the timer is not in use. */
|
||||
errno = EINVAL;
|
||||
else
|
||||
{
|
||||
value->it_interval = timer->value.it_interval;
|
||||
|
||||
if (timer->armed)
|
||||
{
|
||||
clock_gettime (timer->clock, &now);
|
||||
timespec_sub (&value->it_value, &timer->expirytime, &now);
|
||||
}
|
||||
else
|
||||
{
|
||||
value->it_value.tv_sec = 0;
|
||||
value->it_value.tv_nsec = 0;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
528
linuxthreads/sysdeps/pthread/timer_routines.c
Normal file
528
linuxthreads/sysdeps/pthread/timer_routines.c
Normal file
@ -0,0 +1,528 @@
|
||||
/* Helper code for POSIX timer implementation on LinuxThreads.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Number of threads used. */
|
||||
#define THREAD_MAXNODES 16
|
||||
|
||||
/* Array containing the descriptors for the used threads. */
|
||||
static struct thread_node thread_array[THREAD_MAXNODES];
|
||||
|
||||
/* Static array with the structures for all the timers. */
|
||||
struct timer_node __timer_array[TIMER_MAX];
|
||||
|
||||
/* Global lock to protect operation on the lists. */
|
||||
pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Variable to protext initialization. */
|
||||
pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Nonzero if initialization of timer implementation failed. */
|
||||
int __timer_init_failed;
|
||||
|
||||
/* Node for the thread used to deliver signals. */
|
||||
struct thread_node __timer_signal_thread;
|
||||
|
||||
/* Lists to keep free and used timers and threads. */
|
||||
struct list_links timer_free_list;
|
||||
struct list_links thread_free_list;
|
||||
struct list_links thread_active_list;
|
||||
|
||||
|
||||
/* List handling functions. */
|
||||
static inline void
|
||||
list_init (struct list_links *list)
|
||||
{
|
||||
list->next = list->prev = list;
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_append (struct list_links *list, struct list_links *newp)
|
||||
{
|
||||
newp->prev = list->prev;
|
||||
newp->next = list;
|
||||
list->prev->next = newp;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_insbefore (struct list_links *list, struct list_links *newp)
|
||||
{
|
||||
list_append (list, newp);
|
||||
}
|
||||
|
||||
static inline struct list_links *
|
||||
list_first (struct list_links *list)
|
||||
{
|
||||
return list->next;
|
||||
}
|
||||
|
||||
static inline struct list_links *
|
||||
list_null (struct list_links *list)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
static inline struct list_links *
|
||||
list_next (struct list_links *list)
|
||||
{
|
||||
return list->next;
|
||||
}
|
||||
|
||||
static inline int
|
||||
list_isempty (struct list_links *list)
|
||||
{
|
||||
return list->next == list;
|
||||
}
|
||||
|
||||
|
||||
/* Functions build on top of the list functions. */
|
||||
static inline struct thread_node *
|
||||
thread_links2ptr (struct list_links *list)
|
||||
{
|
||||
return (struct thread_node *) ((char *) list
|
||||
- offsetof (struct thread_node, links));
|
||||
}
|
||||
|
||||
static inline struct timer_node *
|
||||
timer_links2ptr (struct list_links *list)
|
||||
{
|
||||
return (struct timer_node *) ((char *) list
|
||||
- offsetof (struct timer_node, links));
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a newly allocated thread structure. */
|
||||
static void
|
||||
thread_init (struct thread_node *thread, const pthread_attr_t *attr)
|
||||
{
|
||||
if (attr != NULL)
|
||||
thread->attr = *attr;
|
||||
else
|
||||
{
|
||||
pthread_attr_init (&thread->attr);
|
||||
pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
|
||||
}
|
||||
|
||||
thread->exists = 0;
|
||||
list_init (&thread->timer_queue);
|
||||
pthread_cond_init (&thread->cond, 0);
|
||||
thread->current_timer = 0;
|
||||
thread->captured = pthread_self ();
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the global lists, and acquire global resources. Error
|
||||
reporting is done by storing a non-zero value to the global variable
|
||||
timer_init_failed. */
|
||||
static void
|
||||
init_module (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
list_init (&timer_free_list);
|
||||
list_init (&thread_free_list);
|
||||
list_init (&thread_active_list);
|
||||
|
||||
for (i = 0; i < TIMER_MAX; ++i)
|
||||
{
|
||||
list_append (&timer_free_list, &__timer_array[i].links);
|
||||
__timer_array[i].inuse = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < THREAD_MAXNODES - 1; ++i)
|
||||
list_append (&thread_free_list, &thread_array[i].links);
|
||||
|
||||
thread_init (&__timer_signal_thread, 0);
|
||||
}
|
||||
|
||||
|
||||
/* This is a handler executed in a child process after a fork()
|
||||
occurs. It reinitializes the module, resetting all of the data
|
||||
structures to their initial state. The mutex is initialized in
|
||||
case it was locked in the parent process. */
|
||||
static void
|
||||
reinit_after_fork (void)
|
||||
{
|
||||
init_module ();
|
||||
pthread_mutex_init (&__timer_mutex, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Called once form pthread_once in timer_init. This initializes the
|
||||
module and ensures that reinit_after_fork will be executed in any
|
||||
child process. */
|
||||
void
|
||||
__timer_init_once (void)
|
||||
{
|
||||
init_module ();
|
||||
pthread_atfork (0, 0, reinit_after_fork);
|
||||
}
|
||||
|
||||
|
||||
/* Deinitialize a thread that is about to be deallocated. */
|
||||
static void
|
||||
thread_deinit (struct thread_node *thread)
|
||||
{
|
||||
assert (list_isempty (&thread->timer_queue));
|
||||
pthread_cond_destroy (&thread->cond);
|
||||
}
|
||||
|
||||
|
||||
/* Allocate a thread structure from the global free list. Global
|
||||
mutex lock must be held by caller. */
|
||||
struct thread_node *
|
||||
__timer_thread_alloc (const pthread_attr_t *desired_attr)
|
||||
{
|
||||
struct list_links *node = list_first (&thread_free_list);
|
||||
|
||||
if (node != list_null (&thread_free_list))
|
||||
{
|
||||
struct thread_node *thread = thread_links2ptr (node);
|
||||
list_unlink (node);
|
||||
thread_init (thread, desired_attr);
|
||||
return thread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a thread structure to the global free list. Global lock
|
||||
must be held by caller. */
|
||||
void
|
||||
__timer_thread_dealloc (struct thread_node *thread)
|
||||
{
|
||||
thread_deinit (thread);
|
||||
list_append (&thread_free_list, &thread->links);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Each of our threads which terminates executes this cleanup handler. We never
|
||||
* terminate threads ourselves; if a thread gets here it means that the evil
|
||||
* application has killed it. If the thread has timers, these require
|
||||
* servicing and so we must hire a replacement thread right away.
|
||||
* We must also unblock another thread that may have been waiting for
|
||||
* this thread to finish servicing a timer (see timer_delete()).
|
||||
*/
|
||||
|
||||
static void
|
||||
thread_cleanup (void *val)
|
||||
{
|
||||
if (val != NULL)
|
||||
{
|
||||
struct thread_node *thread = val;
|
||||
|
||||
/* How did the signal thread get killed? */
|
||||
assert (thread != &__timer_signal_thread);
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
thread->exists = 0;
|
||||
|
||||
/* We are no longer processing a timer event. */
|
||||
thread->current_timer = 0;
|
||||
|
||||
if (list_isempty (&thread->timer_queue))
|
||||
{
|
||||
list_unlink (&thread->links);
|
||||
__timer_thread_dealloc (thread);
|
||||
}
|
||||
else
|
||||
(void) __timer_thread_start (thread);
|
||||
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
|
||||
/* Unblock potentially blocked timer_delete(). */
|
||||
pthread_cond_broadcast (&thread->cond);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Handle a timer which is supposed to go off now. */
|
||||
static void
|
||||
thread_expire_timer (struct thread_node *self, struct timer_node *timer)
|
||||
{
|
||||
self->current_timer = timer;
|
||||
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
|
||||
switch (timer->event.sigev_notify)
|
||||
{
|
||||
case SIGEV_NONE:
|
||||
assert (! "timer_create should never have created such a timer");
|
||||
break;
|
||||
|
||||
case SIGEV_SIGNAL:
|
||||
if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
|
||||
{
|
||||
if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
|
||||
abort ();
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGEV_THREAD:
|
||||
timer->event.sigev_notify_function (timer->event.sigev_value);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (! "unknown event");
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
self->current_timer = 0;
|
||||
|
||||
pthread_cond_broadcast (&self->cond);
|
||||
}
|
||||
|
||||
|
||||
/* Thread function; executed by each timer thread. The job of this
|
||||
function is to wait on the thread's timer queue and expire the
|
||||
timers in chronological order as close to their scheduled time as
|
||||
possible. */
|
||||
static void *
|
||||
thread_func (void *arg)
|
||||
{
|
||||
struct thread_node *self = arg;
|
||||
|
||||
/* Register cleanup handler, in case rogue application terminates
|
||||
this thread. (This cannot happen to __timer_signal_thread, which
|
||||
doesn't invoke application callbacks). */
|
||||
|
||||
pthread_cleanup_push (thread_cleanup, self);
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct list_links *first;
|
||||
struct timer_node *timer = NULL;
|
||||
|
||||
/* While the timer queue is not empty, inspect the first node. */
|
||||
first = list_first (&self->timer_queue);
|
||||
if (first != list_null (&self->timer_queue))
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
timer = timer_links2ptr (first);
|
||||
|
||||
/* This assumes that the elements of the list of one thread
|
||||
are all for the same clock. */
|
||||
clock_gettime (timer->clock, &now);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* If the timer is due or overdue, remove it from the queue.
|
||||
If it's a periodic timer, re-compute its new time and
|
||||
requeue it. Either way, perform the timer expiry. */
|
||||
if (timespec_compare (&now, &timer->expirytime) < 0)
|
||||
break;
|
||||
|
||||
list_unlink (first);
|
||||
|
||||
if (timer->value.it_interval.tv_sec
|
||||
|| timer->value.it_interval.tv_nsec)
|
||||
{
|
||||
timespec_add (&timer->expirytime, &now,
|
||||
&timer->value.it_interval);
|
||||
(void) __timer_thread_queue_timer (self, timer);
|
||||
}
|
||||
|
||||
thread_expire_timer (self, timer);
|
||||
|
||||
first = list_first (&self->timer_queue);
|
||||
if (first == list_null (&self->timer_queue))
|
||||
break;
|
||||
|
||||
timer = timer_links2ptr (first);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the queue is not empty, wait until the expiry time of the
|
||||
first node. Otherwise wait indefinitely. Insertions at the
|
||||
head of the queue must wake up the thread by broadcasting
|
||||
this condition variable. */
|
||||
if (timer != NULL)
|
||||
pthread_cond_timedwait (&self->cond, &__timer_mutex,
|
||||
&timer->expirytime);
|
||||
else
|
||||
pthread_cond_wait (&self->cond, &__timer_mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
pthread_cleanup_pop (1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Enqueue a timer in wakeup order in the thread's timer queue. */
|
||||
int
|
||||
__timer_thread_queue_timer (struct thread_node *thread,
|
||||
struct timer_node *insert)
|
||||
{
|
||||
struct list_links *iter;
|
||||
struct timer_node *matching = NULL;
|
||||
struct timer_node *timer = NULL;
|
||||
|
||||
for (iter = list_first (&thread->timer_queue);
|
||||
iter != list_null (&thread->timer_queue);
|
||||
iter = list_next (iter))
|
||||
{
|
||||
timer = timer_links2ptr (iter);
|
||||
|
||||
if (insert->clock == timer->clock)
|
||||
{
|
||||
matching = timer;
|
||||
if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert->clock != timer->clock)
|
||||
{
|
||||
if (matching == NULL)
|
||||
/* We cannot queue this timer. */
|
||||
return -1;
|
||||
|
||||
timer = matching;
|
||||
}
|
||||
|
||||
list_insbefore (iter, &insert->links);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Start a thread and associate it with the given thread node. Global
|
||||
lock must be held by caller. */
|
||||
int
|
||||
__timer_thread_start (struct thread_node *thread)
|
||||
{
|
||||
int retval = 1;
|
||||
|
||||
assert (!thread->exists);
|
||||
|
||||
thread->exists = 1;
|
||||
|
||||
if (pthread_create (&thread->id, &thread->attr, thread_func, thread) != 0)
|
||||
{
|
||||
thread->exists = 0;
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__timer_thread_wakeup (struct thread_node *thread)
|
||||
{
|
||||
pthread_cond_broadcast (&thread->cond);
|
||||
}
|
||||
|
||||
|
||||
/* Compare two pthread_attr_t thread attributes for exact equality.
|
||||
Returns 1 if they are equal, otherwise zero if they are not equal or
|
||||
contain illegal values. This version is LinuxThreads-specific for
|
||||
performance reason. One could use the access functions to get the
|
||||
values of all the fields of the attribute structure. */
|
||||
static int
|
||||
thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
|
||||
{
|
||||
return (left->__detachstate == right->__detachstate
|
||||
&& left->__schedpolicy == right->__schedpolicy
|
||||
&& (left->__schedparam.sched_priority
|
||||
== right->__schedparam.sched_priority)
|
||||
&& left->__inheritsched == right->__inheritsched
|
||||
&& left->__scope == right->__scope);
|
||||
}
|
||||
|
||||
|
||||
/* Search the list of active threads and find one which has matching
|
||||
attributes. Global mutex lock must be held by caller. */
|
||||
struct thread_node *
|
||||
__timer_thread_find_matching (const pthread_attr_t *desired_attr)
|
||||
{
|
||||
struct list_links *iter = list_first (&thread_active_list);
|
||||
|
||||
while (iter != list_null (&thread_active_list))
|
||||
{
|
||||
struct thread_node *candidate = thread_links2ptr (iter);
|
||||
|
||||
if (thread_attr_compare (desired_attr, &candidate->attr))
|
||||
{
|
||||
list_unlink (iter);
|
||||
return candidate;
|
||||
}
|
||||
|
||||
iter = list_next (iter);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Grab a free timer structure from the global free list. The global
|
||||
lock must be held by the caller. */
|
||||
struct timer_node *
|
||||
__timer_alloc (void)
|
||||
{
|
||||
struct list_links *node = list_first (&timer_free_list);
|
||||
|
||||
if (node != list_null (&timer_free_list))
|
||||
{
|
||||
struct timer_node *timer = timer_links2ptr (node);
|
||||
list_unlink (node);
|
||||
timer->inuse = 1;
|
||||
return timer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return a timer structure to the global free list. The global lock
|
||||
must be held by the caller. */
|
||||
void
|
||||
__timer_dealloc (struct timer_node *timer)
|
||||
{
|
||||
timer->thread = NULL; /* Break association between timer and thread. */
|
||||
timer->inuse = 0;
|
||||
list_append (&timer_free_list, &timer->links);
|
||||
}
|
||||
|
||||
|
||||
/* Thread cancellation handler which unlocks a mutex. */
|
||||
void
|
||||
__timer_mutex_cancel_handler (void *arg)
|
||||
{
|
||||
pthread_mutex_unlock (arg);
|
||||
}
|
112
linuxthreads/sysdeps/pthread/timer_settime.c
Normal file
112
linuxthreads/sysdeps/pthread/timer_settime.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "posix-timer.h"
|
||||
|
||||
|
||||
/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */
|
||||
int
|
||||
timer_settime (timerid, flags, value, ovalue)
|
||||
timer_t timerid;
|
||||
int flags;
|
||||
const struct itimerspec *value;
|
||||
struct itimerspec *ovalue;
|
||||
{
|
||||
struct timer_node *timer;
|
||||
struct thread_node *thread = NULL;
|
||||
struct timespec now;
|
||||
int have_now = 0;
|
||||
int retval = -1;
|
||||
|
||||
pthread_mutex_lock (&__timer_mutex);
|
||||
|
||||
timer = timer_id2ptr (timerid);
|
||||
if (timer == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (value->it_interval.tv_nsec < 0
|
||||
|| value->it_interval.tv_nsec >= 1000000000
|
||||
|| value->it_value.tv_nsec < 0
|
||||
|| value->it_value.tv_nsec >= 1000000000)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ovalue != NULL)
|
||||
{
|
||||
ovalue->it_interval = timer->value.it_interval;
|
||||
|
||||
if (timer->armed)
|
||||
{
|
||||
clock_gettime (timer->clock, &now);
|
||||
have_now = 1;
|
||||
timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
|
||||
}
|
||||
else
|
||||
{
|
||||
ovalue->it_value.tv_sec = 0;
|
||||
ovalue->it_value.tv_nsec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
timer->value = *value;
|
||||
|
||||
list_unlink (&timer->links);
|
||||
timer->armed = 0;
|
||||
|
||||
thread = timer->thread;
|
||||
|
||||
if (value->it_value.tv_sec != 0
|
||||
|| __builtin_expect (value->it_value.tv_nsec != 0, 1))
|
||||
{
|
||||
if ((flags & TIMER_ABSTIME) != 0)
|
||||
/* The user specified the expiration time. */
|
||||
timer->expirytime = value->it_value;
|
||||
else
|
||||
{
|
||||
if (! have_now)
|
||||
clock_gettime (timer->clock, &now);
|
||||
|
||||
timespec_add (&timer->expirytime, &now, &value->it_value);
|
||||
}
|
||||
|
||||
__timer_thread_queue_timer (thread, timer);
|
||||
timer->armed = 1;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
||||
bail:
|
||||
pthread_mutex_unlock (&__timer_mutex);
|
||||
|
||||
/* TODO: optimize this. Only need to wake up the thread if inserting
|
||||
a new timer at the head of the queue. */
|
||||
if (thread != NULL)
|
||||
__timer_thread_wakeup (thread);
|
||||
|
||||
return retval;
|
||||
}
|
116
linuxthreads/sysdeps/pthread/tst-timer.c
Normal file
116
linuxthreads/sysdeps/pthread/tst-timer.c
Normal file
@ -0,0 +1,116 @@
|
||||
/* Tests for POSIX timer implementation.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static void
|
||||
notify_func (union sigval sigval)
|
||||
{
|
||||
puts ("notify_func");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
signal_func (int sig)
|
||||
{
|
||||
static const char text[] = "signal_func\n";
|
||||
signal (sig, signal_func);
|
||||
write (STDOUT_FILENO, text, sizeof text - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
intr_sleep (int sec)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = sec;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
while (nanosleep (&ts, &ts) == -1 && errno == EINTR)
|
||||
;
|
||||
}
|
||||
|
||||
#define ZSIGALRM 14
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct timespec ts;
|
||||
timer_t timer_sig, timer_thr1, timer_thr2;
|
||||
int retval;
|
||||
struct sigevent sigev1 = { SIGEV_SIGNAL, ZSIGALRM, { 0 }, notify_func, 0 };
|
||||
struct sigevent sigev2 = { SIGEV_THREAD, 0, { 0 }, notify_func, 0 };
|
||||
struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } };
|
||||
struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } };
|
||||
struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } };
|
||||
struct itimerspec old;
|
||||
|
||||
retval = clock_gettime (CLOCK_REALTIME, &ts);
|
||||
|
||||
setvbuf (stdout, 0, _IOLBF, 0);
|
||||
|
||||
printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n",
|
||||
retval, ts.tv_sec, ts.tv_nsec);
|
||||
|
||||
retval = clock_getres (CLOCK_REALTIME, &ts);
|
||||
|
||||
printf ("clock_getres returned %d, timespec = { %ld, %ld }\n",
|
||||
retval, ts.tv_sec, ts.tv_nsec);
|
||||
|
||||
#if 1
|
||||
timer_create (CLOCK_REALTIME, &sigev1, &timer_sig);
|
||||
#else
|
||||
timer_create (CLOCK_REALTIME, 0, &timer_sig);
|
||||
#endif
|
||||
|
||||
timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1);
|
||||
timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2);
|
||||
|
||||
#if 0
|
||||
if (fork ())
|
||||
exit (1);
|
||||
#endif
|
||||
|
||||
timer_settime (timer_thr1, 0, &itimer2, &old);
|
||||
timer_settime (timer_thr2, 0, &itimer3, &old);
|
||||
|
||||
signal (ZSIGALRM, signal_func);
|
||||
|
||||
timer_settime (timer_sig, 0, &itimer1, &old);
|
||||
|
||||
timer_delete (-1);
|
||||
|
||||
intr_sleep (3);
|
||||
|
||||
timer_delete (timer_sig);
|
||||
timer_delete (timer_thr1);
|
||||
|
||||
intr_sleep (3);
|
||||
|
||||
timer_delete (timer_thr2);
|
||||
|
||||
return 0;
|
||||
}
|
@ -72,3 +72,6 @@
|
||||
|
||||
/* Minimum size for a thread. We are free to choose a reasonable value. */
|
||||
#define PTHREAD_STACK_MIN 16384
|
||||
|
||||
/* Maximum number of POSIX timers available. */
|
||||
#define TIMER_MAX 256
|
||||
|
Loading…
Reference in New Issue
Block a user