diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/pthread/timer_create.c')
| -rw-r--r-- | libpthread/nptl/sysdeps/pthread/timer_create.c | 170 | 
1 files changed, 170 insertions, 0 deletions
| diff --git a/libpthread/nptl/sysdeps/pthread/timer_create.c b/libpthread/nptl/sysdeps/pthread/timer_create.c new file mode 100644 index 000000000..2809ac744 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_create.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2000, 2003, 2004 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 Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 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 +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser 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 <unistd.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 (0 +#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 +      || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +      || clock_id == CLOCK_THREAD_CPUTIME_ID +#endif +      ) +    { +      /* We don't allow timers for CPU clocks.  At least not in the +	 moment.  */ +      __set_errno (ENOTSUP); +      return -1; +    } + +  if (clock_id != CLOCK_REALTIME) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  pthread_once (&__timer_init_once_control, __timer_init_once); + +  if (__timer_init_failed) +    { +      __set_errno (ENOMEM); +      return -1; +    } + +  pthread_mutex_lock (&__timer_mutex); + +  newtimer = __timer_alloc (); +  if (__builtin_expect (newtimer == NULL, 0)) +    { +      __set_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_ptr = timer_ptr2id (newtimer); +      newtimer->event.sigev_notify_function = 0; +    } + +  newtimer->event.sigev_notify_attributes = &newtimer->attr; +  newtimer->creator_pid = getpid (); + +  switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) +    { +    case SIGEV_NONE: +    case SIGEV_SIGNAL: +      /* We have a global thread for delivering timed signals. +	 If it is not running, try to start it up.  */ +      thread = &__timer_signal_thread_rclk; +      if (! thread->exists) +	{ +	  if (__builtin_expect (__timer_thread_start (thread), +				1) < 0) +	    { +	      __set_errno (EAGAIN); +	      goto unlock_bail; +            } +        } +      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, clock_id); + +      /* If no existing thread has these attributes, try to allocate one.  */ +      if (thread == NULL) +	thread = __timer_thread_alloc (&newtimer->attr, clock_id); + +      /* Out of luck; no threads are available.  */ +      if (__builtin_expect (thread == NULL, 0)) +	{ +	  __set_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)) +	{ +	  __set_errno (EAGAIN); +	  goto unlock_bail; +	} +      break; + +    default: +      __set_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_delref (newtimer); +	  __timer_dealloc (newtimer); +	} +    } + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} | 
