1 /* Downloads progression stuff. */
9 #include "network/progress.h"
10 #include "util/error.h"
11 #include "util/memory.h"
12 #include "util/time.h"
14 #define SPD_DISP_TIME ((milliseconds_T) 100)
15 #define CURRENT_SPD_AFTER ((milliseconds_T) 100)
19 has_progress(struct progress
*progress
)
21 timeval_T current_speed_after
;
23 timeval_from_milliseconds(¤t_speed_after
, CURRENT_SPD_AFTER
);
25 return (timeval_cmp(&progress
->elapsed
, ¤t_speed_after
) >= 0);
29 init_progress(off_t start
)
31 struct progress
*progress
= mem_calloc(1, sizeof(*progress
));
34 progress
->start
= start
;
35 progress
->timer
= TIMER_ID_UNDEF
;
42 done_progress(struct progress
*progress
)
44 assert(progress
->timer
== TIMER_ID_UNDEF
);
48 /** Timer callback for progress.timer. As explained in install_timer(),
49 * this function must erase the expired timer ID from all variables. */
51 progress_timeout(void *progress_voidptr
)
53 struct progress
*const progress
= progress_voidptr
;
55 progress
->timer
= TIMER_ID_UNDEF
;
56 /* The expired timer ID has now been erased. */
58 progress
->timer_func(progress
->timer_func_data
);
61 /* Usually called from the timer callback of @progress->timer. */
63 update_progress(struct progress
*progress
, off_t loaded
, off_t size
, off_t pos
)
66 timeval_T now
, elapsed
, dis_b_max
, dis_b_interval
;
69 timeval_sub(&elapsed
, &progress
->last_time
, &now
);
70 timeval_copy(&progress
->last_time
, &now
);
72 progress
->loaded
= loaded
;
73 bytes_delta
= progress
->loaded
- progress
->last_loaded
;
74 progress
->last_loaded
= progress
->loaded
;
76 timeval_add_interval(&progress
->elapsed
, &elapsed
);
78 timeval_add_interval(&progress
->dis_b
, &elapsed
);
79 timeval_from_milliseconds(&dis_b_max
, mult_ms(SPD_DISP_TIME
, CURRENT_SPD_SEC
));
80 timeval_from_milliseconds(&dis_b_interval
, SPD_DISP_TIME
);
82 while (timeval_cmp(&progress
->dis_b
, &dis_b_max
) >= 0) {
83 progress
->cur_loaded
-= progress
->data_in_secs
[0];
84 memmove(progress
->data_in_secs
, progress
->data_in_secs
+ 1,
85 sizeof(*progress
->data_in_secs
) * (CURRENT_SPD_SEC
- 1));
86 progress
->data_in_secs
[CURRENT_SPD_SEC
- 1] = 0;
87 timeval_sub_interval(&progress
->dis_b
, &dis_b_interval
);
89 progress
->data_in_secs
[CURRENT_SPD_SEC
- 1] += bytes_delta
;
90 progress
->cur_loaded
+= bytes_delta
;
92 progress
->current_speed
= progress
->cur_loaded
/ (CURRENT_SPD_SEC
* ((long) SPD_DISP_TIME
) / 1000);
95 progress
->size
= size
;
96 if (progress
->size
!= -1 && progress
->size
< progress
->pos
)
97 progress
->size
= progress
->pos
;
99 progress
->average_speed
= timeval_div_off_t(progress
->loaded
, &progress
->elapsed
);
100 if (progress
->average_speed
) /* Division by zero risk */
101 timeval_from_seconds(&progress
->estimated_time
,
102 (progress
->size
- progress
->pos
) / progress
->average_speed
);
104 install_timer(&progress
->timer
, SPD_DISP_TIME
,
105 progress_timeout
, progress
);
108 /*! Unlike in install_timer(), @a timer_func need not erase the
109 * expired timer ID from @a progress->timer. update_progress()
110 * installs the timer with a wrapper function that takes care of
111 * erasing the timer ID. */
113 start_update_progress(struct progress
*progress
, void (*timer_func
)(void *),
114 void *timer_func_data
)
116 if (!progress
->valid
) {
119 /* Just copy useful fields from invalid progress. */
120 memset(&tmp
, 0, sizeof(tmp
));
121 tmp
.start
= progress
->start
;
122 tmp
.seek
= progress
->seek
;
125 memcpy(progress
, &tmp
, sizeof(*progress
));
127 timeval_now(&progress
->last_time
);
128 progress
->last_loaded
= progress
->loaded
;
129 progress
->timer_func
= timer_func
;
130 progress
->timer_func_data
= timer_func_data
;