1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2013 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 #include "SMTask.h"
22 #include "Timer.h"
23 #include "xstring.h"
24 #include "misc.h"
25 
26 #define now SMTask::now
27 
28 xlist_head<Timer> Timer::all_timers;
29 xheap<Timer> Timer::running_timers;
30 int Timer::infty_count;
31 
GetTimeoutTV()32 timeval Timer::GetTimeoutTV()
33 {
34    Timer *t;
35    while((t=running_timers.get_min())!=0 && t->Stopped())
36       running_timers.pop_min();
37    if(!t) {
38       timeval tv={infty_count?HOUR:-1, 0};
39       return tv;
40    }
41    TimeDiff remains(t->stop,now);
42    return remains.toTimeval();
43 }
44 
TimeLeft() const45 TimeInterval Timer::TimeLeft() const
46 {
47    if(IsInfty())
48       return TimeInterval();
49    if(now>=stop)
50       return TimeInterval(0,0);
51    return TimeInterval(stop-now);
52 }
set_last_setting(const TimeInterval & i)53 void Timer::set_last_setting(const TimeInterval &i)
54 {
55    infty_count-=IsInfty();
56    last_setting=i;
57    infty_count+=IsInfty();
58    re_set();
59 }
add_random()60 void Timer::add_random()
61 {
62    if(random_max>0.0001) {
63       stop+=TimeDiff::valueOf(random_max*random01());
64    }
65 }
re_set()66 void Timer::re_set()
67 {
68    stop=start;
69    stop+=last_setting;
70    add_random();
71    re_sort();
72 }
AddRandom(double r)73 void Timer::AddRandom(double r) {
74    random_max=r;
75    add_random();
76    re_sort();
77 }
Set(const TimeInterval & i)78 void Timer::Set(const TimeInterval &i)
79 {
80    resource.unset();
81    closure.unset();
82    start=SMTask::now;
83    set_last_setting(i);
84 }
Reset(const Time & t)85 void Timer::Reset(const Time &t)
86 {
87    if(start>=t && stop>t)
88       return;
89    start=t;
90    re_set();
91 }
ResetDelayed(int s)92 void Timer::ResetDelayed(int s)
93 {
94    Reset(SMTask::now+TimeDiff(s,0));
95 }
StopDelayed(int s)96 void Timer::StopDelayed(int s)
97 {
98    stop=SMTask::now+TimeDiff(s,0);
99    re_sort();
100 }
SetResource(const char * r,const char * c)101 void Timer::SetResource(const char *r,const char *c)
102 {
103    if(resource!=r || closure!=c)
104    {
105       resource.set(r);
106       closure.set(c);
107       start=now;
108       reconfig(r);
109    }
110    else
111    {
112       Reset();
113    }
114 }
Stopped() const115 bool Timer::Stopped() const
116 {
117    if(IsInfty())
118       return false;
119    return now>=stop;
120 }
reconfig(const char * r)121 void Timer::reconfig(const char *r)
122 {
123    if(resource && (!r || !strcmp(r,resource)))
124       set_last_setting(TimeIntervalR(ResMgr::Query(resource,closure)));
125 }
init()126 void Timer::init()
127 {
128    random_max=0;
129    all_timers.add(all_timers_node);
130 }
~Timer()131 Timer::~Timer()
132 {
133    running_timers.remove(running_timers_node);
134    all_timers_node.remove();
135    infty_count-=IsInfty();
136 }
Timer()137 Timer::Timer() : last_setting(1,0),
138    all_timers_node(this), running_timers_node(this)
139 {
140    init();
141 }
Timer(const TimeInterval & d)142 Timer::Timer(const TimeInterval &d) : last_setting(d),
143    all_timers_node(this), running_timers_node(this)
144 {
145    init();
146    infty_count+=IsInfty();
147    re_set();
148 }
Timer(const char * r,const char * c)149 Timer::Timer(const char *r,const char *c) : last_setting(0,0),
150    all_timers_node(this), running_timers_node(this)
151 {
152    init();
153    resource.set(r);
154    closure.set(c);
155    start=now;
156    reconfig(r);
157 }
Timer(int s,int ms)158 Timer::Timer(int s,int ms) :
159    all_timers_node(this), running_timers_node(this)
160 {
161    init();
162    Set(TimeInterval(s,ms));
163 }
re_sort()164 void Timer::re_sort()
165 {
166    running_timers.remove(running_timers_node);
167    if(now<stop && !IsInfty())
168       running_timers.add(running_timers_node);
169 }
ReconfigAll(const char * r)170 void Timer::ReconfigAll(const char *r)
171 {
172    xlist_for_each(Timer,all_timers,node,scan)
173       scan->reconfig(r);
174 }
175 
operator <(const Timer & a,const Timer & b)176 bool operator<(const Timer& a,const Timer& b)
177 {
178    return a.TimeLeft()<b.TimeLeft();
179 }
180