Skip to content

Commit b3de1ca

Browse files
gmarullclaude
andcommitted
subsys/cron: move the cron scheduler out of services
The wall-clock job scheduler has no firmware-specific state and is used by activity, alarms and the timeline peek, so it belongs with the other OS subsystems. src/fw/services/cron becomes subsys/cron, the job API (<pebbleos/cron.h>) and the control API (pbl/services/cron.h) collapse into a single <pbl/cron/cron.h>, and the whole surface takes the pbl namespace: struct pbl_cron_job, pbl_cron_job_cb_t, pbl_cron_job_*(), pbl_cron_init(), pbl_cron_handle_clock_change() and the PBL_CRON_*_ANY and PBL_CRON_WDAY_* selectors. CONFIG_SERVICE_CRON becomes CONFIG_CRON and the log module is now "cron". pbl_cron_handle_clock_change() takes the UTC delta, GMT offset delta and DST flag directly instead of a PebbleSetTimeEvent, so the subsystem no longer includes kernel/events.h. The old header declared cron_job_schedule_after(new_job, job) while the implementation and its only caller used (job, new_job); the header now matches the implementation. Verified with the full unit test suite and an asterix build. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
1 parent 2715ae3 commit b3de1ca

27 files changed

Lines changed: 548 additions & 547 deletions

File tree

docs/architecture/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ implemented under `kernel/`). The main source layers, as described on the
1818
- `src/fw/drivers` — hardware drivers (public interfaces under
1919
`include/pbl/drivers`).
2020
- `subsys/` — OS subsystems shared beyond the firmware tree; currently
21-
logging, included via the `pbl/logging/` header path.
21+
logging and cron, included via the `pbl/logging/` and `pbl/cron/` header
22+
paths.
2223

2324
Alongside these sit `src/fw/shell` (launcher/watchface UX flow),
2425
`src/fw/process_management` (app lifecycle) and `src/fw/comm` (phone

include/pbl/cron/cron.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/* SPDX-FileCopyrightText: 2024 Google LLC */
2+
/* SPDX-License-Identifier: Apache-2.0 */
3+
4+
#pragma once
5+
6+
#include <stdbool.h>
7+
#include <stdint.h>
8+
#include <time.h>
9+
10+
#include "pbl/util/list.h"
11+
12+
//! @file cron.h
13+
//! Wall-clock based timer system. Designed for use in things such as alarms, calendar events, etc.
14+
//! Properly handles DST, etc.
15+
16+
struct pbl_cron_job;
17+
18+
typedef void (*pbl_cron_job_cb_t)(struct pbl_cron_job *job, void *data);
19+
20+
//! Matches any possible value.
21+
#define PBL_CRON_MINUTE_ANY (-1)
22+
#define PBL_CRON_HOUR_ANY (-1)
23+
#define PBL_CRON_MDAY_ANY (-1)
24+
#define PBL_CRON_MONTH_ANY (-1)
25+
26+
#define PBL_CRON_WDAY_SUNDAY (1 << 0)
27+
#define PBL_CRON_WDAY_MONDAY (1 << 1)
28+
#define PBL_CRON_WDAY_TUESDAY (1 << 2)
29+
#define PBL_CRON_WDAY_WEDNESDAY (1 << 3)
30+
#define PBL_CRON_WDAY_THURSDAY (1 << 4)
31+
#define PBL_CRON_WDAY_FRIDAY (1 << 5)
32+
#define PBL_CRON_WDAY_SATURDAY (1 << 6)
33+
34+
#define PBL_CRON_WDAY_WEEKDAYS \
35+
(PBL_CRON_WDAY_MONDAY | PBL_CRON_WDAY_TUESDAY | PBL_CRON_WDAY_WEDNESDAY | \
36+
PBL_CRON_WDAY_THURSDAY | PBL_CRON_WDAY_FRIDAY)
37+
#define PBL_CRON_WDAY_WEEKENDS (PBL_CRON_WDAY_SUNDAY | PBL_CRON_WDAY_SATURDAY)
38+
#define PBL_CRON_WDAY_ANY (PBL_CRON_WDAY_WEEKENDS | PBL_CRON_WDAY_WEEKDAYS)
39+
40+
struct pbl_cron_job {
41+
//! internal, no touchy
42+
ListNode list_node;
43+
44+
//! Cached execution timestamp in UTC.
45+
//! This is set by `pbl_cron_job_schedule`, and is required to never be changed once the job has
46+
//! been added.
47+
time_t cached_execute_time;
48+
49+
//! Callback that is called when the job fires.
50+
pbl_cron_job_cb_t cb;
51+
void *cb_data;
52+
53+
//! Occasionally, the system gets a clock change event for various reasons:
54+
//! - User changed time-zones or a DST transition happened
55+
//! - User changed the time
56+
//! - Phone sent the current time and was different from ours, so we took theirs.
57+
//! In the first case, the cron job's execute time will always be recalculated.
58+
//! In the other two, we see if the time difference from the old time is >= this.
59+
//! If it is, then we'll recalculate. Otherwise, we leave the calculated time alone.
60+
//! In this way, 0 will always recalculate, and UINT32_MAX will never recalculate.
61+
//!
62+
//! Recalculating would essentially mean that a job that was "skipped over" will not fire until
63+
//! the next match. If recalculation is not done, but the job was skipped over, it will fire
64+
//! instantly.
65+
//!
66+
//! This value is specified in seconds.
67+
uint32_t clock_change_tolerance;
68+
69+
int8_t minute; //!< 0-59, or PBL_CRON_MINUTE_ANY
70+
int8_t hour; //!< 0-23, or PBL_CRON_HOUR_ANY
71+
int8_t mday; //!< 0-30, or PBL_CRON_MDAY_ANY
72+
int8_t month; //!< 0-11, or PBL_CRON_MONTH_ANY
73+
74+
//! Seconds to offset the cron execution time applied after regular cron job time calculation.
75+
//! For example, a cron scheduled for Monday at 0:15 with an offset of negative 30min will fire
76+
//! on Sunday at 23:45.
77+
int32_t offset_seconds;
78+
79+
union {
80+
uint8_t flags;
81+
82+
struct {
83+
//! This should be any combination of PBL_CRON_WDAY_*. If zero, acts like PBL_CRON_WDAY_ANY.
84+
uint8_t wday : 7;
85+
86+
//! If this flag is set, the resulting execution time may be equal to the local epoch.
87+
//! Having it set could be used for some event that must happen at the specified time even if
88+
//! that time is right now.
89+
bool may_be_instant : 1;
90+
};
91+
};
92+
};
93+
94+
//! Initialize the cron subsystem.
95+
void pbl_cron_init(void);
96+
97+
//! Adjust all cron jobs, as the wall clock has changed.
98+
//! @param utc_time_delta seconds the UTC time moved by.
99+
//! @param gmt_offset_delta seconds the GMT offset moved by; non-zero forces recalculation.
100+
//! @param dst_changed whether the DST state changed; true forces recalculation.
101+
void pbl_cron_handle_clock_change(int32_t utc_time_delta, int32_t gmt_offset_delta,
102+
bool dst_changed);
103+
104+
//! Add a cron job. This will make the subsystem hold a reference to the specified job, so it must
105+
//! not leave scope or be destroyed until it is unscheduled.
106+
//! The job only gets scheduled once. For re-scheduling, you can call this on the job again.
107+
//! @param job pointer to the job to be scheduled.
108+
//! @returns time_t for when the job is destined to go off.
109+
time_t pbl_cron_job_schedule(struct pbl_cron_job *job);
110+
111+
//! Schedule a cron job to run after another cron job.
112+
//! This will make the subsystem hold a reference to the new job, so it must
113+
//! not leave scope or be destroyed until it is unscheduled.
114+
//! @param job pointer to the job after which we want our job to run. job must be scheduled.
115+
//! @param new_job pointer to the job to be scheduled. new_job must be unscheduled.
116+
//! @returns time_t for when the job is destined to go off.
117+
//! @note This API makes no guarantee that the two jobs will be scheduled back to back,
118+
//! only that new_job will have the same scheduled time as job and that it will trigger
119+
//! strictly after job.
120+
time_t pbl_cron_job_schedule_after(struct pbl_cron_job *job, struct pbl_cron_job *new_job);
121+
122+
//! Remove a scheduled cron job.
123+
//! @param job pointer to the job to be unscheduled.
124+
//! @return true if the job was successfully removed (false may indicate no job was
125+
//! scheduled at all or the cb is currently executing)
126+
bool pbl_cron_job_unschedule(struct pbl_cron_job *job);
127+
128+
//! Check if a cron job is scheduled.
129+
//! @param job pointer to the job to be checked for being scheduled.
130+
//! @returns true if scheduled or pending deletion, false otherwise
131+
bool pbl_cron_job_is_scheduled(struct pbl_cron_job *job);
132+
133+
//! Calculate cron job's destined execution time, from the current time.
134+
//! @param job pointer to the job to get the execution time for.
135+
//! @returns time_t for when the job is destined to go off.
136+
time_t pbl_cron_job_get_execute_time(const struct pbl_cron_job *job);
137+
138+
//! Calculate cron job's destined execution time if it were scheduled at the given time.
139+
//! @param job pointer to the job to get the execution time for.
140+
//! @param local_epoch the epoch for getting the job's execution time.
141+
//! @returns time_t for when the job is destined to go off.
142+
time_t pbl_cron_job_get_execute_time_from_epoch(const struct pbl_cron_job *job, time_t local_epoch);
143+
144+
#if UNITTEST
145+
//! Remove all jobs.
146+
void pbl_cron_clear_all_jobs(void);
147+
148+
//! Clean up the cron subsystem.
149+
void pbl_cron_deinit(void);
150+
151+
//! The number of registered cron jobs.
152+
uint32_t pbl_cron_get_job_count(void);
153+
154+
//! Run the cron timers if they've fired.
155+
void pbl_cron_wakeup(void);
156+
157+
//! Execute time of the earliest scheduled job, or 0 when none is scheduled.
158+
time_t pbl_cron_get_next_execute_time(void);
159+
#endif

include/pbl/services/cron.h

Lines changed: 0 additions & 38 deletions
This file was deleted.

include/pebbleos/cron.h

Lines changed: 0 additions & 128 deletions
This file was deleted.

src/fw/kernel/event_loop.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include "pbl/services/battery/battery_monitor.h"
3535
#include "pbl/services/clock.h"
3636
#include "pbl/services/compositor/compositor.h"
37-
#include "pbl/services/cron.h"
37+
#include <pbl/cron/cron.h>
3838
#include "pbl/services/debounced_connection_service.h"
3939
#include "pbl/services/ecompass.h"
4040
#include "pbl/services/event_service.h"
@@ -468,7 +468,8 @@ static PBL_NOINLINE void prv_extended_event_handler(PebbleEvent *e) {
468468
ABS(set_time_info->utc_time_delta) > 15) {
469469
alarm_handle_clock_change();
470470
wakeup_handle_significant_clock_change();
471-
cron_service_handle_clock_change(set_time_info);
471+
pbl_cron_handle_clock_change(set_time_info->utc_time_delta, set_time_info->gmt_offset_delta,
472+
set_time_info->dst_changed);
472473
}
473474

474475
// Always reschedule wakeup timers on any time change to prevent timers from

0 commit comments

Comments
 (0)