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* 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 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 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* 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 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 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 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 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 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 /** @} */