1 #include	"config.h"
2 #include	<iostream>
3 
4 static const char rcsid[]="$Id: alarm.C,v 1.3 2001/04/21 02:03:17 mrsam Exp $";
5 
6 #if HAVE_UNISTD_H
7 #include	<unistd.h>
8 #else
9 extern "C" long alarm(long);
10 #endif
11 
12 #include	<signal.h>
13 #include	"alarm.h"
14 
15 Alarm *Alarm::first=0;
16 Alarm *Alarm::last=0;
17 
~Alarm()18 Alarm::~Alarm()
19 {
20 	Cancel();
21 }
22 
Unlink()23 void Alarm::Unlink()
24 {
25 	set_interval=0;
26 	if (prev)	prev->next=next;
27 	else		first=next;
28 	if (next)	next->prev=prev;
29 	else		last=prev;
30 }
31 
cancel_sig(unsigned seconds_left)32 void Alarm::cancel_sig(unsigned seconds_left)
33 {
34 Alarm	*p;
35 Alarm	*alarm_chain=0;
36 
37 	while ((p=first) != 0 && p->set_interval <= seconds_left)
38 			// Marginal case
39 	{
40 		p->Unlink();
41 		p->next=alarm_chain;
42 		alarm_chain=p;
43 	}
44 
45 	for (p=first; p; p=p->next)
46 		p->set_interval -= seconds_left;
47 
48 	while ((p=alarm_chain) != 0)
49 	{
50 		alarm_chain=p->next;
51 		p->handler();
52 	}
53 }
54 
set_sig()55 void Alarm::set_sig()
56 {
57 	if (!first)	return;
58 	signal(SIGALRM, &Alarm::alarm_func);
59 	alarm(first->set_interval);
60 }
61 
alarm_func(int)62 RETSIGTYPE Alarm::alarm_func(int)
63 {
64 	if (first)	cancel_sig(first->set_interval);
65 	set_sig();
66 
67 #if RETSIGTYPE != void
68 	return (0);
69 #endif
70 }
71 
sig_left()72 unsigned Alarm::sig_left()
73 {
74 	if (!first)	return (0);
75 
76 unsigned n=alarm(0);
77 
78 	return (n ? n <= first->set_interval ? first->set_interval - n:0:0);
79 }
80 
Set(unsigned nseconds)81 void Alarm::Set(unsigned nseconds)
82 {
83 	Cancel();		// Just in case
84 	if (nseconds == 0)
85 	{
86 		handler();	// Fooey.
87 		return;
88 	}
89 
90 	cancel_sig(sig_left());
91 
92 Alarm	*p;
93 
94 	for (p=first; p; p=p->next)
95 		if (p->set_interval > nseconds)
96 			break;
97 
98 	if (!p)
99 	{
100 		next=0;
101 		if ((prev=last) != 0)
102 			prev->next=this;
103 		else
104 			first=this;
105 		last=this;
106 	}
107 	else
108 	{
109 		if ((prev=p->prev) != 0)
110 			prev->next=this;
111 		else
112 			first=this;
113 		next=p;
114 		p->prev=this;
115 	}
116 	set_interval=nseconds;
117 	set_sig();
118 }
119 
Cancel()120 void Alarm::Cancel()
121 {
122 	cancel_sig(sig_left());
123 	if (set_interval) Unlink();
124 	set_sig();
125 }
126