Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/timers.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
#include <ast.h>
23
#include <sig.h>
24
#include <error.h>
25
#include "fault.h"
26
#include "defs.h"
27
#include "FEATURE/sigfeatures"
28
#include "FEATURE/time"
29
30
typedef struct _timer
31
{
32
double wakeup;
33
double incr;
34
struct _timer *next;
35
void (*action)(void*);
36
void *handle;
37
} Timer_t;
38
39
#define IN_ADDTIMEOUT 1
40
#define IN_SIGALRM 2
41
#define DEFER_SIGALRM 4
42
#define SIGALRM_CALL 8
43
44
static Timer_t *tptop, *tpmin, *tpfree;
45
static char time_state;
46
47
static double getnow(void)
48
{
49
register double now;
50
#ifdef timeofday
51
struct timeval tp;
52
timeofday(&tp);
53
now = tp.tv_sec + 1.e-6*tp.tv_usec;
54
55
#else
56
now = (double)time((time_t*)0);
57
#endif /* timeofday */
58
return(now+.001);
59
}
60
61
/*
62
* set an alarm for <t> seconds
63
*/
64
static double setalarm(register double t)
65
{
66
#if defined(_lib_setitimer) && defined(ITIMER_REAL)
67
struct itimerval tnew, told;
68
tnew.it_value.tv_sec = t;
69
tnew.it_value.tv_usec = 1.e6*(t- (double)tnew.it_value.tv_sec);
70
if(t && tnew.it_value.tv_sec==0 && tnew.it_value.tv_usec<1000)
71
tnew.it_value.tv_usec = 1000;
72
tnew.it_interval.tv_sec = 0;
73
tnew.it_interval.tv_usec = 0;
74
if(setitimer(ITIMER_REAL,&tnew,&told) < 0)
75
errormsg(SH_DICT,ERROR_system(1),e_alarm);
76
t = told.it_value.tv_sec + 1.e-6*told.it_value.tv_usec;
77
#else
78
unsigned seconds = (unsigned)t;
79
if(t && seconds<1)
80
seconds=1;
81
t = (double)alarm(seconds);
82
#endif
83
return(t);
84
}
85
86
/* signal handler for alarm call */
87
static void sigalrm(int sig)
88
{
89
register Timer_t *tp, *tplast, *tpold, *tpnext;
90
double now;
91
static double left;
92
NOT_USED(sig);
93
left = 0;
94
if(time_state&SIGALRM_CALL)
95
time_state &= ~SIGALRM_CALL;
96
else if(alarm(0))
97
kill(getpid(),SIGALRM|SH_TRAP);
98
if(time_state)
99
{
100
if(time_state&IN_ADDTIMEOUT)
101
time_state |= DEFER_SIGALRM;
102
errno = EINTR;
103
return;
104
}
105
time_state |= IN_SIGALRM;
106
sigrelease(SIGALRM);
107
while(1)
108
{
109
now = getnow();
110
tpold = tpmin = 0;
111
for(tplast=0,tp=tptop; tp; tp=tpnext)
112
{
113
tpnext = tp->next;
114
if(tp->action)
115
{
116
if(tp->wakeup <=now)
117
{
118
if(!tpold || tpold->wakeup>tp->wakeup)
119
tpold = tp;
120
}
121
else
122
{
123
if(!tpmin || tpmin->wakeup>tp->wakeup)
124
tpmin=tp;
125
}
126
tplast = tp;
127
}
128
else
129
{
130
if(tplast)
131
tplast->next = tp->next;
132
else
133
tptop = tp->next;
134
tp->next = tpfree;
135
tpfree = tp;
136
}
137
}
138
if((tp=tpold) && tp->incr)
139
{
140
while((tp->wakeup += tp->incr) <= now);
141
if(!tpmin || tpmin->wakeup>tp->wakeup)
142
tpmin=tp;
143
}
144
if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left))))
145
{
146
if(left==0)
147
signal(SIGALRM,sigalrm);
148
left = setalarm(tpmin->wakeup-now);
149
if(left && (now+left) < tpmin->wakeup)
150
setalarm(left);
151
else
152
left=tpmin->wakeup-now;
153
}
154
if(tp)
155
{
156
void (*action)(void*);
157
action = tp->action;
158
if(!tp->incr)
159
tp->action = 0;
160
errno = EINTR;
161
time_state &= ~IN_SIGALRM;
162
(*action)(tp->handle);
163
time_state |= IN_SIGALRM;
164
}
165
else
166
break;
167
}
168
if(!tpmin)
169
signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
170
time_state &= ~IN_SIGALRM;
171
errno = EINTR;
172
}
173
174
static void oldalrm(void *handle)
175
{
176
Handler_t fn = *(Handler_t*)handle;
177
free(handle);
178
(*fn)(SIGALRM);
179
}
180
181
void *sh_timeradd(unsigned long msec,int flags,void (*action)(void*),void *handle)
182
{
183
register Timer_t *tp;
184
double t;
185
Handler_t fn;
186
t = ((double)msec)/1000.;
187
if(t<=0 || !action)
188
return((void*)0);
189
if(tp=tpfree)
190
tpfree = tp->next;
191
else if(!(tp=(Timer_t*)malloc(sizeof(Timer_t))))
192
return((void*)0);
193
tp->wakeup = getnow() + t;
194
tp->incr = (flags?t:0);
195
tp->action = action;
196
tp->handle = handle;
197
time_state |= IN_ADDTIMEOUT;
198
tp->next = tptop;
199
tptop = tp;
200
if(!tpmin || tp->wakeup < tpmin->wakeup)
201
{
202
tpmin = tp;
203
fn = (Handler_t)signal(SIGALRM,sigalrm);
204
if((t= setalarm(t))>0 && fn && fn!=(Handler_t)sigalrm)
205
{
206
Handler_t *hp = (Handler_t*)malloc(sizeof(Handler_t));
207
if(hp)
208
{
209
*hp = fn;
210
sh_timeradd((long)(1000*t), 0, oldalrm, (void*)hp);
211
}
212
}
213
tp = tptop;
214
}
215
else if(tpmin && !tpmin->action)
216
time_state |= DEFER_SIGALRM;
217
time_state &= ~IN_ADDTIMEOUT;
218
if(time_state&DEFER_SIGALRM)
219
{
220
time_state=SIGALRM_CALL;
221
sigalrm(SIGALRM);
222
if(tp!=tptop)
223
tp=0;
224
}
225
return((void*)tp);
226
}
227
228
/*
229
* delete timer <tp>. If <tp> is NULL, all timers are deleted
230
*/
231
void timerdel(void *handle)
232
{
233
register Timer_t *tp = (Timer_t*)handle;
234
if(tp)
235
tp->action = 0;
236
else
237
{
238
for(tp=tptop; tp; tp=tp->next)
239
tp->action = 0;
240
if(tpmin)
241
{
242
tpmin = 0;
243
setalarm((double)0);
244
}
245
signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
246
}
247
}
248
249
250