Back to index

glibc  2.9
timer_create.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public License as
00007    published by the Free Software Foundation; either version 2.1 of the
00008    License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00017    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.  */
00019 
00020 #include <errno.h>
00021 #include <signal.h>
00022 #include <pthread.h>
00023 #include <time.h>
00024 #include <unistd.h>
00025 
00026 #include "posix-timer.h"
00027 
00028 
00029 /* Create new per-process timer using CLOCK.  */
00030 int
00031 timer_create (clock_id, evp, timerid)
00032      clockid_t clock_id;
00033      struct sigevent *evp;
00034      timer_t *timerid;
00035 {
00036   int retval = -1;
00037   struct timer_node *newtimer = NULL;
00038   struct thread_node *thread = NULL;
00039 
00040   if (0
00041 #ifdef _POSIX_CPUTIME
00042       || clock_id == CLOCK_PROCESS_CPUTIME_ID
00043 #endif
00044 #ifdef _POSIX_THREAD_CPUTIME
00045       || clock_id == CLOCK_THREAD_CPUTIME_ID
00046 #endif
00047       )
00048     {
00049       /* We don't allow timers for CPU clocks.  At least not in the
00050         moment.  */
00051       __set_errno (ENOTSUP);
00052       return -1;
00053     }
00054 
00055   if (clock_id != CLOCK_REALTIME)
00056     {
00057       __set_errno (EINVAL);
00058       return -1;
00059     }
00060 
00061   pthread_once (&__timer_init_once_control, __timer_init_once);
00062 
00063   if (__timer_init_failed)
00064     {
00065       __set_errno (ENOMEM);
00066       return -1;
00067     }
00068 
00069   pthread_mutex_lock (&__timer_mutex);
00070 
00071   newtimer = __timer_alloc ();
00072   if (__builtin_expect (newtimer == NULL, 0))
00073     {
00074       __set_errno (EAGAIN);
00075       goto unlock_bail;
00076     }
00077 
00078   if (evp != NULL)
00079     newtimer->event = *evp;
00080   else
00081     {
00082       newtimer->event.sigev_notify = SIGEV_SIGNAL;
00083       newtimer->event.sigev_signo = SIGALRM;
00084       newtimer->event.sigev_value.sival_int = timer_ptr2id (newtimer);
00085       newtimer->event.sigev_notify_function = 0;
00086     }
00087 
00088   newtimer->event.sigev_notify_attributes = &newtimer->attr;
00089   newtimer->creator_pid = getpid ();
00090 
00091   switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
00092     {
00093     case SIGEV_NONE:
00094     case SIGEV_SIGNAL:
00095       /* We have a global thread for delivering timed signals.
00096         If it is not running, try to start it up.  */
00097       thread = &__timer_signal_thread_rclk;
00098       if (! thread->exists)
00099        {
00100          if (__builtin_expect (__timer_thread_start (thread),
00101                             1) < 0)
00102            {
00103              __set_errno (EAGAIN);
00104              goto unlock_bail;
00105             }
00106         }
00107       break;
00108 
00109     case SIGEV_THREAD:
00110       /* Copy over thread attributes or set up default ones.  */
00111       if (evp->sigev_notify_attributes)
00112        newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
00113       else
00114        pthread_attr_init (&newtimer->attr);
00115 
00116       /* Ensure thread attributes call for deatched thread.  */
00117       pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
00118 
00119       /* Try to find existing thread having the right attributes.  */
00120       thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
00121 
00122       /* If no existing thread has these attributes, try to allocate one.  */
00123       if (thread == NULL)
00124        thread = __timer_thread_alloc (&newtimer->attr, clock_id);
00125 
00126       /* Out of luck; no threads are available.  */
00127       if (__builtin_expect (thread == NULL, 0))
00128        {
00129          __set_errno (EAGAIN);
00130          goto unlock_bail;
00131        }
00132 
00133       /* If the thread is not running already, try to start it.  */
00134       if (! thread->exists
00135          && __builtin_expect (! __timer_thread_start (thread), 0))
00136        {
00137          __set_errno (EAGAIN);
00138          goto unlock_bail;
00139        }
00140       break;
00141 
00142     default:
00143       __set_errno (EINVAL);
00144       goto unlock_bail;
00145     }
00146 
00147   newtimer->clock = clock_id;
00148   newtimer->abstime = 0;
00149   newtimer->armed = 0;
00150   newtimer->thread = thread;
00151 
00152   *timerid = timer_ptr2id (newtimer);
00153   retval = 0;
00154 
00155   if (__builtin_expect (retval, 0) == -1)
00156     {
00157     unlock_bail:
00158       if (thread != NULL)
00159        __timer_thread_dealloc (thread);
00160       if (newtimer != NULL)
00161        {
00162          timer_delref (newtimer);
00163          __timer_dealloc (newtimer);
00164        }
00165     }
00166 
00167   pthread_mutex_unlock (&__timer_mutex);
00168 
00169   return retval;
00170 }