@@ -46,7 +46,7 @@ static void timer_init(Unit *u) {
4646 assert (u );
4747 assert (u -> load_state == UNIT_STUB );
4848
49- t -> next_elapse_monotonic = (usec_t ) - 1 ;
49+ t -> next_elapse_monotonic_or_boottime = (usec_t ) - 1 ;
5050 t -> next_elapse_realtime = (usec_t ) - 1 ;
5151 t -> accuracy_usec = USEC_PER_MINUTE ;
5252}
@@ -203,10 +203,14 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
203203 "%sTimer State: %s\n"
204204 "%sResult: %s\n"
205205 "%sUnit: %s\n"
206+ "%sPersistent: %s\n"
207+ "%sWakeSystem: %s\n"
206208 "%sAccuracy: %s\n" ,
207209 prefix , timer_state_to_string (t -> state ),
208210 prefix , timer_result_to_string (t -> result ),
209211 prefix , trigger ? trigger -> id : "n/a" ,
212+ prefix , yes_no (t -> persistent ),
213+ prefix , yes_no (t -> wake_system ),
210214 prefix , format_timespan (buf , sizeof (buf ), t -> accuracy_usec , 1 ));
211215
212216 LIST_FOREACH (value , v , t -> values ) {
@@ -282,15 +286,34 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
282286 timer_set_state (t , t -> result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD );
283287}
284288
289+ static usec_t monotonic_to_boottime (usec_t t ) {
290+ usec_t a , b ;
291+
292+ if (t <= 0 )
293+ return 0 ;
294+
295+ a = now (CLOCK_BOOTTIME );
296+ b = now (CLOCK_MONOTONIC );
297+
298+ if (t + a > b )
299+ return t + a - b ;
300+ else
301+ return 0 ;
302+ }
303+
285304static void timer_enter_waiting (Timer * t , bool initial ) {
286- TimerValue * v ;
287- usec_t base = 0 ;
288- dual_timestamp ts ;
289305 bool found_monotonic = false, found_realtime = false;
306+ usec_t ts_realtime , ts_monotonic ;
307+ usec_t base = 0 ;
308+ TimerValue * v ;
290309 int r ;
291310
292- dual_timestamp_get (& ts );
293- t -> next_elapse_monotonic = t -> next_elapse_realtime = 0 ;
311+ /* If we shall wake the system we use the boottime clock
312+ * rather than the monotonic clock. */
313+
314+ ts_realtime = now (CLOCK_REALTIME );
315+ ts_monotonic = now (t -> wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC );
316+ t -> next_elapse_monotonic_or_boottime = t -> next_elapse_realtime = 0 ;
294317
295318 LIST_FOREACH (value , v , t -> values ) {
296319
@@ -305,7 +328,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
305328 * to that. If we don't just start from
306329 * now. */
307330
308- b = t -> last_trigger .realtime > 0 ? t -> last_trigger .realtime : ts . realtime ;
331+ b = t -> last_trigger .realtime > 0 ? t -> last_trigger .realtime : ts_realtime ;
309332
310333 r = calendar_spec_next_usec (v -> calendar_spec , b , & v -> next_elapse );
311334 if (r < 0 )
@@ -325,7 +348,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
325348 if (state_translation_table [t -> state ] == UNIT_ACTIVE )
326349 base = UNIT (t )-> inactive_exit_timestamp .monotonic ;
327350 else
328- base = ts . monotonic ;
351+ base = ts_monotonic ;
329352 break ;
330353
331354 case TIMER_BOOT :
@@ -365,18 +388,21 @@ static void timer_enter_waiting(Timer *t, bool initial) {
365388 assert_not_reached ("Unknown timer base" );
366389 }
367390
391+ if (t -> wake_system )
392+ base = monotonic_to_boottime (base );
393+
368394 v -> next_elapse = base + v -> value ;
369395
370- if (!initial && v -> next_elapse < ts . monotonic && IN_SET (v -> base , TIMER_ACTIVE , TIMER_BOOT , TIMER_STARTUP )) {
396+ if (!initial && v -> next_elapse < ts_monotonic && IN_SET (v -> base , TIMER_ACTIVE , TIMER_BOOT , TIMER_STARTUP )) {
371397 /* This is a one time trigger, disable it now */
372398 v -> disabled = true;
373399 continue ;
374400 }
375401
376402 if (!found_monotonic )
377- t -> next_elapse_monotonic = v -> next_elapse ;
403+ t -> next_elapse_monotonic_or_boottime = v -> next_elapse ;
378404 else
379- t -> next_elapse_monotonic = MIN (t -> next_elapse_monotonic , v -> next_elapse );
405+ t -> next_elapse_monotonic_or_boottime = MIN (t -> next_elapse_monotonic_or_boottime , v -> next_elapse );
380406
381407 found_monotonic = true;
382408 }
@@ -390,10 +416,13 @@ static void timer_enter_waiting(Timer *t, bool initial) {
390416
391417 if (found_monotonic ) {
392418 char buf [FORMAT_TIMESPAN_MAX ];
393- log_debug_unit (UNIT (t )-> id , "%s: Monotonic timer elapses in %s." , UNIT (t )-> id , format_timespan (buf , sizeof (buf ), t -> next_elapse_monotonic > ts .monotonic ? t -> next_elapse_monotonic - ts .monotonic : 0 , 0 ));
419+
420+ log_debug_unit (UNIT (t )-> id , "%s: Monotonic timer elapses in %s." ,
421+ UNIT (t )-> id ,
422+ format_timespan (buf , sizeof (buf ), t -> next_elapse_monotonic_or_boottime > ts_monotonic ? t -> next_elapse_monotonic_or_boottime - ts_monotonic : 0 , 0 ));
394423
395424 if (t -> monotonic_event_source ) {
396- r = sd_event_source_set_time (t -> monotonic_event_source , t -> next_elapse_monotonic );
425+ r = sd_event_source_set_time (t -> monotonic_event_source , t -> next_elapse_monotonic_or_boottime );
397426 if (r < 0 )
398427 goto fail ;
399428
@@ -402,8 +431,8 @@ static void timer_enter_waiting(Timer *t, bool initial) {
402431 r = sd_event_add_time (
403432 UNIT (t )-> manager -> event ,
404433 & t -> monotonic_event_source ,
405- CLOCK_MONOTONIC ,
406- t -> next_elapse_monotonic , t -> accuracy_usec ,
434+ t -> wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC ,
435+ t -> next_elapse_monotonic_or_boottime , t -> accuracy_usec ,
407436 timer_dispatch , t );
408437 if (r < 0 )
409438 goto fail ;
@@ -429,7 +458,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
429458 r = sd_event_add_time (
430459 UNIT (t )-> manager -> event ,
431460 & t -> realtime_event_source ,
432- CLOCK_REALTIME ,
461+ t -> wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME ,
433462 t -> next_elapse_realtime , t -> accuracy_usec ,
434463 timer_dispatch , t );
435464 if (r < 0 )
0 commit comments