00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <iostream>
00029 #include <stdio.h>
00030 #include <sys/time.h>
00031 #include <signal.h>
00032 #include <unistd.h>
00033
00034
00035 #include <sys/syscall.h>
00036
00037 #include "timer.h"
00038 #include "vsisemaphore.h"
00039 #include "RioError.h"
00040
00041 const int ERROR1 = -1;
00042 const int ERROR2 = -2;
00043 const int ERROR3 = -3;
00044 const int ERROR4 = -4;
00045 const int ERROR5 = -5;
00046 const int ERROR6 = -6;
00047 const int ERROR7 = -7;
00048 const int ERROR8 = -8;
00049 const int ERROR9 = -9;
00050
00051 const int TIMER_PRECISION = 100;
00052
00053 static CvsiSemaphore Semaphore(0);
00054
00055 static void TimerSignalHandler( int s )
00056 {
00057 Semaphore.V();
00058 }
00059
00060
00061
00062 CTimer::CTimer()
00063 {
00064 m_Table = NULL;
00065 m_Free = -1;
00066 m_First = -1;
00067 m_nTimers = 0;
00068
00069 m_StartTime.tv_sec = 0;
00070 m_StartTime.tv_usec = 0;
00071
00072 m_Initialized = false;
00073 m_StopThread = false;
00074
00075
00076 }
00077
00078 CTimer::~CTimer()
00079 {
00080 if( m_Table != 0 )
00081 {
00082 delete[] m_Table;
00083 m_Table = 0;
00084 }
00085 }
00086
00087
00088 int CTimer::Initialize( const int nTimers )
00089 {
00090
00091
00092 if( nTimers < 1 )
00093 return (ERROR3);
00094
00095
00096 if( !m_Mutex.IsOpen() )
00097 return (ERROR1);
00098
00099
00100 if( !m_Mutex.IsOpen() )
00101 return (ERROR9);
00102
00103
00104 m_Mutex.Wait();
00105
00106 if( m_First >= 0 )
00107 {
00108 m_Mutex.Release();
00109 return (ERROR2);
00110 }
00111
00112 if( m_Thread.IsActive() )
00113 {
00114 m_StopThread = true;
00115 Semaphore.V();
00116 m_Mutex.Release();
00117 m_Thread.Join(0);
00118 m_Mutex.Wait();
00119 }
00120
00121 if( m_Table != 0 )
00122 {
00123 delete[] m_Table;
00124 m_Table = 0;
00125 }
00126
00127 m_nTimers = nTimers;
00128 m_Table = new TimerEntry[nTimers];
00129
00130 for( int i = 0; i < nTimers; i++ )
00131 {
00132 m_Table[i].Next = i+1;
00133 m_Table[i].Previous = i-1;
00134 m_Table[i].Status = TimerStatusFree;
00135 }
00136
00137 m_Table[nTimers-1].Next = -1;
00138 m_Free = 0;
00139
00140 int result = 0;
00141 if( m_Thread.Create( Thread, (void*)this ) < 0 )
00142 result = ERROR4;
00143
00144
00145 gettimeofday( &m_StartTime, 0 );
00146
00147 m_Initialized = true;
00148
00149
00150 m_Mutex.Release();
00151
00152 return result;
00153 }
00154
00155
00156 int CTimer::Stop()
00157 {
00158
00159 m_Mutex.Wait();
00160
00161
00162 if( !m_Initialized )
00163 {
00164 m_Mutex.Release();
00165 return ERROR5;
00166 }
00167
00168
00169 m_StopThread = true;
00170 Semaphore.V();
00171 m_Mutex.Release();
00172 m_Thread.Join(0);
00173
00174
00175 m_Mutex.Wait();
00176 if( m_Table != 0 )
00177 {
00178 delete[] m_Table;
00179 m_Table = 0;
00180 }
00181
00182
00183 m_Free = -1;
00184 m_First = -1;
00185 m_nTimers = 0;
00186 m_Initialized = false;
00187 m_StopThread = false;
00188
00189
00190 m_Mutex.Release();
00191
00192 return 0;
00193
00194 }
00195
00196
00197 int CTimer::GetTimer( callback_t callback )
00198 {
00199 int Id;
00200
00201
00202 m_Mutex.Wait();
00203
00204
00205 if( !m_Initialized )
00206 {
00207 m_Mutex.Release();
00208 return ERROR5;
00209 }
00210
00211 if( m_Free == -1 )
00212 {
00213 m_Mutex.Release();
00214 return ERROR6;
00215 }
00216
00217 Id = m_Free;
00218
00219 m_Free = m_Table[Id].Next;
00220
00221 if( m_Free >= 0 )
00222 {
00223 m_Table[m_Free].Previous = -1;
00224 }
00225
00226 m_Table[Id].Status = TimerStatusInactive;
00227 m_Table[Id].Callback = callback;
00228
00229
00230 m_Mutex.Release();
00231
00232 return Id;
00233 }
00234
00235
00236 int CTimer::FreeTimer( const int TimerId )
00237 {
00238
00239
00240 m_Mutex.Wait();
00241
00242
00243 if( !m_Initialized )
00244 {
00245 m_Mutex.Release();
00246 return ERROR5;
00247 }
00248
00249
00250 if( ( TimerId < 0 ) || ( TimerId >= m_nTimers ) )
00251 {
00252 m_Mutex.Release();
00253 return ERROR7;
00254 }
00255
00256
00257 if( m_Table[TimerId].Status == TimerStatusFree )
00258 {
00259 m_Mutex.Release();
00260 return ERROR8;
00261 }
00262
00263
00264 if( m_Table[TimerId].Status == TimerStatusActive )
00265 {
00266 Remove( TimerId );
00267 }
00268
00269
00270 m_Table[TimerId].Status = TimerStatusFree;
00271
00272
00273 m_Table[TimerId].Previous = -1;
00274 m_Table[TimerId].Next = m_Free;
00275 if( m_Free >= 0 )
00276 {
00277 m_Table[m_Free].Previous = TimerId;
00278 }
00279 m_Free = TimerId;
00280
00281
00282 m_Mutex.Release();
00283
00284 return 0;
00285 }
00286
00287
00288 int CTimer::StartTimer( const int TimerId, struct timeval Interval,
00289 TimerType Type, void* Param )
00290 {
00291
00292 m_Mutex.Wait();
00293
00294
00295 if( !m_Initialized )
00296 {
00297 m_Mutex.Release();
00298 return ERROR5;
00299 }
00300
00301
00302 if( ( TimerId < 0 ) || ( TimerId >= m_nTimers ) )
00303 {
00304 m_Mutex.Release();
00305 return ERROR7;
00306 }
00307
00308
00309 if( m_Table[TimerId].Status == TimerStatusFree )
00310 {
00311 m_Mutex.Release();
00312 return ERROR8;
00313 }
00314
00315
00316 if( m_Table[TimerId].Status == TimerStatusActive )
00317 {
00318 Remove(TimerId);
00319 }
00320
00321
00322 m_Table[TimerId].Interval = Interval;
00323 m_Table[TimerId].Type = Type;
00324
00325 struct timeval initial_time, current_time;
00326 current_time = CurrentTime();
00327 initial_time.tv_sec = current_time.tv_sec + Interval.tv_sec;
00328 initial_time.tv_usec = current_time.tv_usec + Interval.tv_usec;
00329 if( initial_time.tv_usec > 1000000 )
00330 {
00331 initial_time.tv_sec += 1;
00332 initial_time.tv_usec -= 1000000;
00333 }
00334 m_Table[TimerId].Time = initial_time;
00335
00336
00337 m_Table[TimerId].Param = Param;
00338
00339 Insert( TimerId );
00340
00341
00342
00343
00344 if( m_First == TimerId )
00345 {
00346 ReprogramTimer();
00347 }
00348
00349 m_Mutex.Release();
00350 return 0;
00351 }
00352
00353
00354 int CTimer::StopTimer(const int TimerId)
00355 {
00356
00357 m_Mutex.Wait();
00358
00359
00360 if( !m_Initialized )
00361 {
00362 m_Mutex.Release();
00363 return ERROR5;
00364 }
00365
00366
00367 if( ( TimerId < 0 ) || ( TimerId >= m_nTimers ) )
00368 {
00369 m_Mutex.Release();
00370 return ERROR7;
00371 }
00372
00373
00374 if( m_Table[TimerId].Status == TimerStatusFree )
00375 {
00376 m_Mutex.Release();
00377 return ERROR8;
00378 }
00379
00380
00381 if( m_Table[TimerId].Status == TimerStatusActive )
00382 {
00383 Remove( TimerId );
00384 }
00385
00386
00387 m_Mutex.Release();
00388
00389 return 0;
00390 }
00391
00392
00393
00394 void CTimer::Remove( int TimerId )
00395 {
00396 int Next = m_Table[TimerId].Next;
00397 int Previous = m_Table[TimerId].Previous;
00398
00399 if( Next >= 0 )
00400 {
00401 m_Table[Next].Previous = Previous;
00402 }
00403
00404 if( Previous >= 0 )
00405 {
00406 m_Table[Previous].Next = Next;
00407 }
00408 else
00409 {
00410 m_First = Next;
00411 }
00412
00413 m_Table[TimerId].Status = TimerStatusInactive;
00414 return;
00415 }
00416
00417
00418
00419
00420 void CTimer::Insert( int TimerId )
00421 {
00422 int Next = m_First;
00423 int Previous = -1;
00424
00425 struct timeval Time = m_Table[TimerId].Time;
00426
00427
00428
00429
00430 while( Next >= 0 )
00431 {
00432 if( ( m_Table[Next].Time.tv_sec > Time.tv_sec ) ||
00433 (( m_Table[Next].Time.tv_sec == Time.tv_sec ) &&
00434 ( m_Table[Next].Time.tv_usec > Time.tv_usec )))
00435 break;
00436 Previous = Next;
00437 Next = m_Table[Next].Next;
00438 }
00439
00440
00441 m_Table[TimerId].Next = Next;
00442 m_Table[TimerId].Previous = Previous;
00443
00444
00445 if( Previous >= 0 )
00446 {
00447 m_Table[Previous].Next = TimerId;
00448 }
00449 else
00450 {
00451 m_First = TimerId;
00452 }
00453 if( Next >= 0 )
00454 {
00455 m_Table[Next].Previous = TimerId;
00456 }
00457
00458 m_Table[TimerId].Status = TimerStatusActive;
00459 return;
00460 }
00461
00462
00463 struct timeval CTimer::CurrentTime()
00464 {
00465 struct timeval val, current_time;
00466
00467 gettimeofday( &val, 0 );
00468
00469 current_time.tv_sec = val.tv_sec - m_StartTime.tv_sec;
00470 current_time.tv_usec = val.tv_usec - m_StartTime.tv_usec;
00471 if( current_time.tv_usec < 0 )
00472 {
00473 current_time.tv_sec -= 1;
00474 current_time.tv_usec += 1000000;
00475 }
00476
00477 return ( current_time );
00478 }
00479
00480
00481 void CTimer::InitTimerSignalAction( void )
00482 {
00483 struct sigaction action;
00484 action.sa_handler = TimerSignalHandler;
00485 action.sa_flags = SA_RESTART;
00486 sigemptyset( &action.sa_mask );
00487 sigaction( SIGALRM, &action, NULL );
00488 }
00489
00490
00491 void CTimer::ProgramTimer( struct timeval Time )
00492 {
00493 struct itimerval TimerValue;
00494 struct timeval current_time, timer;
00495
00496 TimerValue.it_interval.tv_sec = 0;
00497 TimerValue.it_interval.tv_usec = 0;
00498
00499 current_time = CurrentTime();
00500
00501 timer.tv_sec = Time.tv_sec - current_time.tv_sec;
00502 timer.tv_usec = Time.tv_usec - current_time.tv_usec;
00503 if( timer.tv_usec < 0 )
00504 {
00505 timer.tv_sec -= 1;
00506 timer.tv_usec += 1000000;
00507 }
00508
00509 if( ( timer.tv_sec < 0 ) || (( timer.tv_sec == 0 )&&( timer.tv_usec <= 0 )) )
00510 {
00511 timer.tv_sec = 0;
00512 timer.tv_usec = 1;
00513 }
00514
00515 if( ( timer.tv_sec == 0 ) && ( timer.tv_usec < 1000000 ) )
00516 {
00517 TimerValue.it_value.tv_sec = 0;
00518 TimerValue.it_value.tv_usec = timer.tv_usec;
00519 }
00520 else
00521 {
00522 TimerValue.it_value.tv_sec = timer.tv_sec;
00523 TimerValue.it_value.tv_usec = timer.tv_usec;
00524
00525 }
00526 setitimer( ITIMER_REAL, &TimerValue, NULL );
00527 }
00528
00529
00530
00531 void* CTimer::Thread( void* param )
00532 {
00533 CTimer* Timer= (CTimer*) param;
00534 Timer->TimerThread();
00535 return 0;
00536 }
00537
00538
00539 void CTimer::TimerThread()
00540 {
00541
00542 RioErr << "TIMERTHREADID " << syscall( SYS_gettid ) << endl;
00543
00544 InitTimerSignalAction();
00545 while( 1 )
00546 {
00547
00548 if( m_StopThread )
00549 {
00550 return;
00551 }
00552
00553
00554 Semaphore.P();
00555
00556 if( m_StopThread )
00557 {
00558 return;
00559 }
00560
00561 m_Mutex.Wait();
00562
00563 ProcessExpiredTimers();
00564 ReprogramTimer();
00565
00566 m_Mutex.Release();
00567 }
00568 }
00569
00570
00571 void CTimer::ProcessExpiredTimers()
00572 {
00573 int Current = m_First;
00574 int Next;
00575
00576 struct timeval current_time, time;
00577
00578 Current = m_First;
00579 while( Current >= 0 )
00580 {
00581 Next = m_Table[Current].Next;
00582
00583 time.tv_sec = m_Table[Current].Time.tv_sec;
00584 time.tv_usec = m_Table[Current].Time.tv_usec;
00585
00586 time.tv_usec -= TIMER_PRECISION;
00587 if( time.tv_usec < 0 )
00588 {
00589 time.tv_sec -= 1;
00590 time.tv_usec += 1000000;
00591 }
00592
00593 current_time = CurrentTime();
00594
00595 if( ( current_time.tv_sec > time.tv_sec) ||
00596 (( current_time.tv_sec == time.tv_sec ) &&
00597 ( current_time.tv_usec > time.tv_usec )))
00598 {
00599 Remove( Current );
00600
00601 m_Mutex.Release();
00602 (m_Table[Current].Callback)(m_Table[Current].Param);
00603 m_Mutex.Wait();
00604 if( m_Table[Current].Type == TimerTypePeriodic )
00605 {
00606 m_Table[Current].Time.tv_sec += m_Table[Current].Interval.tv_sec;
00607 m_Table[Current].Time.tv_usec += m_Table[Current].Interval.tv_usec;
00608 if( m_Table[Current].Time.tv_usec > 1000000 )
00609 {
00610 m_Table[Current].Time.tv_sec += 1;
00611 m_Table[Current].Time.tv_usec -= 1000000;
00612 }
00613 Insert( Current );
00614 }
00615 }
00616 else
00617 {
00618 return;
00619 }
00620 Current = Next;
00621 }
00622 }
00623
00624
00625 void CTimer::ReprogramTimer()
00626 {
00627 if( m_First >= 0 )
00628 ProgramTimer( m_Table[m_First].Time );
00629 }
00630