xref: /onnv-gate/usr/src/lib/libparted/common/libparted/timer.c (revision 9663:ace9a2ac3683)
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 2001, 2007 Free Software Foundation, Inc.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 /** \file timer.c */
20 
21 /**
22  * \addtogroup PedTimer
23  *
24  * \brief A PedTimer keeps track of the progress of a single (possibly
25  * compound) operation.
26  *
27  * The user of libparted constructs a PedTimer, and passes it to libparted
28  * functions that are likely to be expensive operations
29  * (like ped_file_system_resize).  Use of timers is optional... you may
30  * pass NULL instead.
31  *
32  * When you create a PedTimer, you must specify a timer handler function.
33  * This will be called when there's an update on how work is progressing.
34  *
35  * Timers may be nested.  When a timer is constructed, you can choose
36  * to assign it a parent, along with an estimate of what proportion of
37  * the total (parent's) time will be used in the nested operation.  In
38  * this case, the nested timer's handler is internal to libparted,
39  * and simply updates the parent's progress, and calls its handler.
40  *
41  * @{
42  */
43 
44 
45 #include <config.h>
46 #include <parted/parted.h>
47 #include <parted/debug.h>
48 
49 #define PED_TIMER_START_DELAY	2
50 
51 typedef struct {
52 	PedTimer*	parent;
53 	float		nest_frac;
54 	float		start_frac;
55 } NestedContext;
56 
57 
58 /**
59  * \brief Creates a timer.
60  *
61  * Context will be passed in the \p context
62  *         argument to the \p handler, when it is invoked.
63  *
64  * \return a new PedTimer
65  */
66 PedTimer*
ped_timer_new(PedTimerHandler * handler,void * context)67 ped_timer_new (PedTimerHandler* handler, void* context)
68 {
69 	PedTimer*	timer;
70 
71 	PED_ASSERT (handler != NULL, return NULL);
72 
73 	timer = (PedTimer*) ped_malloc (sizeof (PedTimer));
74 	if (!timer)
75 		return NULL;
76 
77 	timer->handler = handler;
78 	timer->context = context;
79 	ped_timer_reset (timer);
80 	return timer;
81 }
82 
83 
84 /**
85  * \brief Destroys a \p timer.
86  */
87 void
ped_timer_destroy(PedTimer * timer)88 ped_timer_destroy (PedTimer* timer)
89 {
90 	if (!timer)
91 		return;
92 
93 	ped_free (timer);
94 }
95 
96 /* This function is used by ped_timer_new_nested() as the timer->handler
97  * function.
98  */
99 static void
_nest_handler(PedTimer * timer,void * context)100 _nest_handler (PedTimer* timer, void* context)
101 {
102 	NestedContext*	ncontext = (NestedContext*) context;
103 
104 	ped_timer_update (
105 		ncontext->parent,
106 		ncontext->start_frac + ncontext->nest_frac * timer->frac);
107 }
108 
109 
110 /**
111  * \brief Creates a new nested timer.
112  *
113  * This function creates a "nested" timer that describes the progress
114  * of a subtask. \p parent is the parent timer, and \p nested_frac is
115  * the estimated proportion (between 0 and 1) of the time that will be
116  * spent doing the nested timer's operation. The timer should only be
117  * constructed immediately prior to starting the nested operation.
118  * (It will be inaccurate, otherwise).
119  * Updates to the progress of the subtask are propagated
120  * back through to the parent task's timer.
121  *
122  * \return nested timer
123  */
124 PedTimer*
ped_timer_new_nested(PedTimer * parent,float nest_frac)125 ped_timer_new_nested (PedTimer* parent, float nest_frac)
126 {
127 	NestedContext*	context;
128 
129 	if (!parent)
130 		return NULL;
131 
132 	PED_ASSERT (nest_frac >= 0.0, return NULL);
133 	PED_ASSERT (nest_frac <= 1.0, return NULL);
134 
135 	context = (NestedContext*) ped_malloc (sizeof (NestedContext));
136 	if (!context)
137 		return NULL;
138 	context->parent = parent;
139 	context->nest_frac = nest_frac;
140 	context->start_frac = parent->frac;
141 
142 	return ped_timer_new (_nest_handler, context);
143 }
144 
145 /**
146  * \brief Destroys a nested \p timer.
147  */
148 void
ped_timer_destroy_nested(PedTimer * timer)149 ped_timer_destroy_nested (PedTimer* timer)
150 {
151 	if (!timer)
152 		return;
153 
154 	ped_free (timer->context);
155 	ped_timer_destroy (timer);
156 }
157 
158 /**
159  * \internal
160  *
161  * \brief This function calls the update handler, making sure that it has
162  * 	the latest time.
163  *
164  * First it updates \p timer->now and recomputes \p timer->predicted_end,
165  * and then calls the handler.
166  */
167 void
ped_timer_touch(PedTimer * timer)168 ped_timer_touch (PedTimer* timer)
169 {
170 	if (!timer)
171 	       return;
172 
173 	timer->now = time (NULL);
174 	if (timer->now > timer->predicted_end)
175 		timer->predicted_end = timer->now;
176 
177 	timer->handler (timer, timer->context);
178 }
179 
180 /**
181  * \internal
182  *
183  * \brief This function sets the \p timer into a "start of task" position.
184  *
185  * It resets the \p timer, by setting \p timer->start and \p timer->now
186  * to the current time.
187  */
188 void
ped_timer_reset(PedTimer * timer)189 ped_timer_reset (PedTimer* timer)
190 {
191 	if (!timer)
192 	       return;
193 
194 	timer->start = timer->now = timer->predicted_end = time (NULL);
195 	timer->state_name = NULL;
196 	timer->frac = 0;
197 
198 	ped_timer_touch (timer);
199 }
200 
201 /**
202  * \internal
203  *
204  * \brief This function tells a \p timer what fraction \p frac of the task
205  * has been completed.
206  *
207  * Sets the new \p timer->frac, and calls ped_timer_touch().
208  */
209 void
ped_timer_update(PedTimer * timer,float frac)210 ped_timer_update (PedTimer* timer, float frac)
211 {
212 	if (!timer)
213 	       return;
214 
215 	timer->now = time (NULL);
216 	timer->frac = frac;
217 
218 	if (frac)
219 		timer->predicted_end
220 			= timer->start
221 			  + (long) ((timer->now - timer->start) / frac);
222 
223 	ped_timer_touch (timer);
224 }
225 
226 /**
227  * \internal
228  *
229  * \brief This function changes the description of the current task that the
230  * 	\p timer describes.
231  *
232  * Sets a new name - \p state_name - for the current "phase" of the operation,
233  * and calls ped_timer_touch().
234  */
235 void
ped_timer_set_state_name(PedTimer * timer,const char * state_name)236 ped_timer_set_state_name (PedTimer* timer, const char* state_name)
237 {
238 	if (!timer)
239 	       return;
240 
241 	timer->state_name = state_name;
242 	ped_timer_touch (timer);
243 }
244 
245 /** @} */
246