timer.cpp

00001 /*   
00002  *   (c) Copyright 2008 Philipp Skadorov (philipp_s@users.sourceforge.net)
00003  *
00004  *   This file is part of FREESECS.
00005  *
00006  *   FREESECS is free software: you can redistribute it and/or modify
00007  *   it under the terms of the GNU General Public License as published by
00008  *   the Free Software Foundation, either version 3 of the License, or
00009  *   (at your option) any later version.
00010  *
00011  *   FREESECS is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details.
00015  *
00016  *   You should have received a copy of the GNU General Public License
00017  *   along with FREESECS, see COPYING.
00018  *   If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 #include <sys/socket.h>
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <errno.h>
00025 
00026 #include "async_reception.h"
00027 #include "hsms_signums.h"
00028 #include "timer.h"
00029 
00030 
00031 #define BILLION     1000000000L
00032 #define MILLION     1000000L
00033 #define THOUSAND    1000L
00034 
00035 using namespace freesecs;
00036 
00037 int ms_timer_t::_subscr_count = 0;
00038 struct sigaction ms_timer_t::_old_act = {};
00039 
00040 static char ar_data[1] = {0};
00041 
00042 void 
00043 ms_timer_t::interrupt(int signo, siginfo_t *info, void *context)
00044 {
00045     char data[1] = {0};
00046 
00047     ms_timer_t *tmr = (ms_timer_t*)info->si_value.sival_ptr;
00048     
00049     ::write(tmr->_timeout_fd[0], data, 1);
00050 }
00051 
00052 ms_timer_t::ms_timer_t()
00053 {
00054     struct sigevent sigev;
00055     struct sigaction act;
00056 
00057     if(0 == _subscr_count)
00058     {
00059         memset(&act, 0, sizeof(struct sigaction));
00060         act.sa_flags = SA_SIGINFO;
00061         act.sa_sigaction = interrupt;
00062 
00063         if((-1 == sigemptyset(&act.sa_mask)) ||
00064               (-1 == sigaction(TIMEOUT_SIGNAL, &act, &_old_act)))
00065         {
00066             throw 1;
00067         }
00068     }
00069     _subscr_count++;
00070 
00071     memset(&sigev, 0, sizeof(sigev));
00072     sigev.sigev_notify = SIGEV_SIGNAL;
00073     //sigev.sigev_notify = SIGEV_THREAD;
00074     sigev.sigev_signo = TIMEOUT_SIGNAL;
00075     sigev.sigev_value.sival_ptr = (void*)this;
00076 
00077     if(socketpair(PF_UNIX, SOCK_DGRAM, 0, _timeout_fd))
00078     {
00079         throw;
00080     }
00081 
00082     _ar = new async_reception_t(_timeout_fd[1], "timeout");
00083     _ar->data_recvd_signal.add_handler(this, &ms_timer_t::ar_handler);
00084     
00085     if(timer_create(CLOCK_REALTIME, &sigev, &_id))
00086     {
00087         throw;
00088     }
00089 }
00090 
00091 ms_timer_t::~ms_timer_t()
00092 {
00093     _ar->stop_recv();
00094     delete _ar;
00095 
00096     timer_delete(_id);
00097 
00098     /*restore signal handler*/
00099     if(0 == (_subscr_count--))
00100     {
00101         sigaction(TIMEOUT_SIGNAL, &_old_act, NULL);
00102     }
00103 }
00104 
00105 int ms_timer_t::start(unsigned long timeout_ms)
00106 {
00107     itimerspec value;
00108     memset(&value, 0, sizeof(itimerspec));
00109     value.it_value.tv_sec = long(timeout_ms/THOUSAND);
00110     value.it_value.tv_nsec = long(timeout_ms*MILLION 
00111                                 - value.it_value.tv_sec*BILLION);
00112 
00113     _ar->start_recv(ar_data, 1);
00114 
00115     return timer_settime(_id, 0, &value, NULL);
00116 }
00117 
00118 int ms_timer_t::stop()
00119 {
00120     itimerspec value;
00121     memset(&value, 0, sizeof(itimerspec));
00122 
00123     if(0 != timer_gettime(_id, &value))
00124     {
00125         return errno;
00126     }
00127 
00128     //check if the timer is running
00129     if(0 == value.it_value.tv_sec && value.it_value.tv_nsec == 0)
00130     {
00131         return EPERM;
00132     }
00133 
00134     _ar->stop_recv();
00135 
00136     return timer_settime(_id, 0, &value, NULL);
00137 }
00138 
00139 int 
00140 ms_timer_t::ar_handler(const size_t&)
00141 {
00142     return _cb();
00143 }
00144 
00145 
00146 #if 0
00147 class dummy_t
00148 {
00149 public:
00150    int callback()
00151    {
00152         printf("dummy callback.\n");fflush(stdout);
00153         return 0;
00154    }
00155 };
00156 
00157 int main(int argc, char *argv[])
00158 {
00159     dummy_t dummy;
00160 /*    ms_timer_t t1;
00161     t1.add_handler(&dummy, &dummy_t::callback);
00162 
00163     int error = t1.start(2000);
00164     printf("start 2 sec (%d)-->\n",error);fflush(stdout);
00165     error = t1.stop();
00166     printf("stop: %d\n", error);
00167     error = t1.start(10000);
00168     printf("start 10 sec (%d)-->\n",error);fflush(stdout);
00169     for(;;){}*/
00170     int error, ix = 0;
00171     while (1)
00172     {
00173         printf("cycle %d: ",ix++);fflush(stdout);
00174         ms_timer_t *t1 = new ms_timer_t;
00175         t1->add_handler(&dummy, &dummy_t::callback);
00176         error = t1->start(1000);
00177         printf("%d\n",error);fflush(stdout);
00178         if(error)
00179         {
00180            break;
00181         }
00182     }
00183 }
00184 #endif

Generated on Fri Oct 3 15:30:01 2008 for FREESECS hsms by  doxygen 1.5.1