summaryrefslogtreecommitdiff
path: root/src/libnml/os_intf/timer.cc
blob: 21bf221f1ef2c44dedd7b0dd0413a9db19bbf440 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/********************************************************************
* Description: timer.cc
*   A TIMER object lets you wait on the expiration of a cyclic
*   period, to the resolution of the system clock.
*
*   Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: LGPL Version 2
* System: Linux
*    
* Copyright (c) 2004 All rights reserved.
*
* Last change: 
********************************************************************/

extern "C" {
#include <stdlib.h>		// atof()
#include <string.h>		// strtok(), strncmp()
#include <stdio.h>		/* NULL */

#include <stdlib.h>		/* exit() */
#include <signal.h>		/* struct sigaction, sigaction(), SIGALRM,
				   sigset_t */
#include <errno.h>		/* perror(), EINTR */
#include <unistd.h>		/* select(), sysconf(), _SC_CLK_TCK */
#include <sys/time.h>		/* struct timeval, gettimeofday(), struct
				   itimerval, setitimer(), ITIMER_REAL */
#include <sys/types.h>
#include <sys/wait.h>		// waitpid()
}

#include "timer.hh"
#include "_timer.h"

/* RCS_TIMER class */
RCS_TIMER::RCS_TIMER(const char *process_name, const char *config_file)
{
    zero_timer();
    set_timeout(0);
}

RCS_TIMER::RCS_TIMER(double _timeout, const char *process_name, const char *config_file)
{
    zero_timer();
    set_timeout(_timeout);
}

void
  RCS_TIMER::set_timeout(double _timeout)
{
    timeout = _timeout;
    if (timeout < clk_tck()) {
	counts_per_real_sleep = (int) (clk_tck() / _timeout) + 1;
    } else {
	counts_per_real_sleep = 0;
    }
}


void RCS_TIMER::zero_timer()
{
    num_sems = 0;
#if USE_SEMS_FOR_TIMER
    sems = NULL;
#endif
    id = 0;
    function = NULL;
    arg = NULL;
    last_time = etime();	/* initialize start time and last time called
				   to current time since epoch */
    idle = 0.0;			/* set accumulated idle time to 0.0 */
    counts = 0;			/* set accumulated waits to 0 */
    start_time = etime();	/* set creation time to now */
    time_since_real_sleep = start_time;
    counts_per_real_sleep = 0;
    counts_since_real_sleep = 0;
    clk_tck_val = clk_tck();
    timeout = clk_tck_val;
}

void RCS_TIMER::init(double _timeout, int _id)
{
    zero_timer();
    id = _id;
    set_timeout(_timeout);

}

RCS_TIMER::RCS_TIMER(double _timeout, RCS_TIMERFUNC _function, void *_arg)
{
    zero_timer();
    counts_per_real_sleep = 0;
    counts_since_real_sleep = 0;

    if (_timeout < clk_tck_val) {
	counts_per_real_sleep = (int) (clk_tck_val / _timeout);
	/* bump interval up to minimum system clock tick */
	timeout = clk_tck_val;
    } else {
	timeout = _timeout;
    }
    function = _function;
    arg = _arg;
    time_since_real_sleep = start_time;
}

/* Restart the timing interval. */
void
  RCS_TIMER::sync()
{
    last_time = etime();	/* initialize start time and last time called
				   to current time since epoch */
}

int RCS_TIMER::wait()
{
    double interval;		/* interval between this and last wakeup */
    double numcycles;		/* interval, in units of timeout */
    int missed = 0;		/* cycles missed */
    double remaining = 0.0;	/* time remaining until timeout */
    double time_in = 0.0;	/* time wait() was entered */
    double time_done = 0.0;	/* time user function finished */
    /* first call the user timing function, if any */
    if (function != NULL) {
	/* set time in */
	time_in = etime();

	if ((*function) (arg) == -1) {
	    return -1;		/* fatal error in timing function */
	}
	time_done = etime();
    } else {
	/* set time in, time done not used */
	time_in = etime();
    }

    /* calculate the interval-- for user timing functions, this is how long
       between this wakeup and the last wakeup.  For internal timers, this is 
       how long we need to sleep to make it to the next interval on time. */
    interval = time_in - last_time;
    numcycles = interval / timeout;

    /* synchronize and set last_time correctly; update idle time */
    counts++;
    if (function != NULL) {
	missed = (int) (numcycles - (clk_tck_val / timeout));
	idle += interval;
	last_time = time_done;
        remaining = 0.0;
    } else {
	missed = (int) (numcycles); 
	remaining = timeout * (1.0 - (numcycles - (int) numcycles));
	idle += interval;
    }
    esleep(remaining);
    last_time = etime();
    return missed;
}

double RCS_TIMER::load()
{
    if (counts * timeout != 0.0)
	return idle / (counts * timeout);
    return -1.0;
}

RCS_TIMER::~RCS_TIMER()
{
}