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()18Alarm::~Alarm() 19 { 20 Cancel(); 21 } 22 Unlink()23void 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)32void 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()55void Alarm::set_sig() 56 { 57 if (!first) return; 58 signal(SIGALRM, &Alarm::alarm_func); 59 alarm(first->set_interval); 60 } 61 alarm_func(int)62RETSIGTYPE 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()72unsigned 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)81void 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()120void Alarm::Cancel() 121 { 122 cancel_sig(sig_left()); 123 if (set_interval) Unlink(); 124 set_sig(); 125 } 126