1use crate::fs::fuchsia::{BootZxTimer, MonotonicZxTimer};
6use crate::power::OnWakeOps;
7use crate::task::{
8 CurrentTask, EventHandler, GenericDuration, HrTimer, Kernel, SignalHandler, SignalHandlerInner,
9 TargetTime, Timeline, TimerWakeup, WaitCanceler, Waiter,
10};
11use crate::vfs::buffers::{InputBuffer, OutputBuffer};
12use crate::vfs::{
13 Anon, FileHandle, FileObject, FileObjectState, FileOps, fileops_impl_nonseekable,
14 fileops_impl_noop_sync,
15};
16use futures::channel::mpsc;
17use starnix_logging::{log_debug, log_warn};
18use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Mutex};
19use starnix_types::time::{duration_from_timespec, timespec_from_duration, timespec_is_zero};
20use starnix_uapi::errors::Errno;
21use starnix_uapi::open_flags::OpenFlags;
22use starnix_uapi::vfs::FdEvents;
23use starnix_uapi::{TFD_TIMER_ABSTIME, TFD_TIMER_CANCEL_ON_SET, error, itimerspec};
24use std::sync::{Arc, Weak};
25use zerocopy::IntoBytes;
26use zx::HandleRef;
27
28pub trait TimerOps: Send + Sync + 'static {
29 fn start(
34 &self,
35 current_task: &CurrentTask,
36 source: Option<Weak<dyn OnWakeOps>>,
37 deadline: TargetTime,
38 ) -> Result<(), Errno>;
39
40 fn stop(&self, kernel: &Arc<Kernel>) -> Result<(), Errno>;
44
45 fn as_handle_ref(&self) -> HandleRef<'_>;
47
48 fn get_timeline_change_observer(
54 &self,
55 current_task: &CurrentTask,
56 ) -> Option<TimelineChangeObserver>;
57}
58
59#[derive(Debug)]
61pub struct TimelineChangeObserver {
62 timeline_change_counter: zx::Counter,
65 timeline_change_registration: mpsc::UnboundedSender<bool>,
67}
68
69impl Drop for TimelineChangeObserver {
70 fn drop(&mut self) {
72 self.set_timeline_change_interest(false);
73 }
74}
75
76impl TimelineChangeObserver {
77 pub fn new(
78 timeline_change_counter: zx::Counter,
79 timeline_change_registration: mpsc::UnboundedSender<bool>,
80 ) -> Self {
81 Self { timeline_change_counter, timeline_change_registration }
82 }
83
84 pub fn reset_timeline_change_counter(&self) -> i64 {
100 let counter = &self.timeline_change_counter;
101 let value = counter.read().expect("it is possible to read the counter");
102 if value != 0 {
103 counter.add(-value).expect("it is possible to set the counter to zero");
111 }
112 return value;
113 }
114
115 pub fn get_timeline_change_counter_ref(&self) -> &zx::Counter {
116 &self.timeline_change_counter
117 }
118
119 pub fn set_timeline_change_interest(&mut self, is_interested: bool) {
120 self.timeline_change_registration.unbounded_send(is_interested).expect("can send");
122 }
123}
124
125#[derive(Debug)]
130pub struct TimerFileInfo {
131 deadline: TargetTime,
133 interval: zx::MonotonicDuration,
135 timeline_change_observer: Option<TimelineChangeObserver>,
140 cancel_on_set: bool,
143}
144
145impl TimerFileInfo {
146 pub fn new(next_deadline: TargetTime, interval_period: zx::MonotonicDuration) -> Self {
147 Self {
148 deadline: next_deadline,
149 interval: interval_period,
150 timeline_change_observer: None,
151 cancel_on_set: false,
152 }
153 }
154
155 pub fn reset_timeline_change_counter(&self) -> i64 {
156 if let Some(observer) = self.timeline_change_observer.as_ref() {
157 return observer.reset_timeline_change_counter();
158 } else {
159 0
160 }
161 }
162
163 pub fn set_deadline(&mut self, new_deadline: TargetTime) -> &mut Self {
164 self.deadline = new_deadline;
165 self
166 }
167
168 pub fn set_interval(&mut self, new_interval: zx::MonotonicDuration) -> &mut Self {
169 self.interval = new_interval;
170 self
171 }
172
173 pub fn set_timeline_change_observer(
176 &mut self,
177 observer: Option<TimelineChangeObserver>,
178 ) -> &mut Self {
179 self.timeline_change_observer = observer;
180 self
181 }
182
183 pub fn set_cancel_on_set(&mut self, value: bool) -> &mut Self {
187 self.cancel_on_set = value;
188 self.timeline_change_observer
189 .as_mut()
190 .map(|observer| observer.set_timeline_change_interest(value));
191 self
192 }
193}
194
195pub struct TimerFile {
200 timer: Arc<dyn TimerOps>,
202
203 timeline: Timeline,
205
206 timer_file_info: Arc<Mutex<TimerFileInfo>>,
209}
210
211impl TimerFile {
212 pub fn new_file<L>(
216 locked: &mut Locked<L>,
217 current_task: &CurrentTask,
218 wakeup_type: TimerWakeup,
219 timeline: Timeline,
220 flags: OpenFlags,
221 ) -> Result<FileHandle, Errno>
222 where
223 L: LockEqualOrBefore<FileOpsCore>,
224 {
225 let timer: Arc<dyn TimerOps> = match (wakeup_type, timeline) {
226 (TimerWakeup::Regular, Timeline::Monotonic) => Arc::new(MonotonicZxTimer::new()),
227 (TimerWakeup::Regular, Timeline::BootInstant) => Arc::new(BootZxTimer::new()),
228 (TimerWakeup::Regular, Timeline::RealTime)
229 | (TimerWakeup::Alarm, Timeline::BootInstant | Timeline::RealTime) => {
230 Arc::new(HrTimer::new())
231 }
232 (TimerWakeup::Alarm, Timeline::Monotonic) => {
233 unreachable!("monotonic times cannot be alarm deadlines")
234 }
235 };
236
237 let mut timer_file_info =
238 TimerFileInfo::new(timeline.zero_time(), zx::MonotonicDuration::default());
239
240 if timeline.is_realtime() {
241 timer_file_info
247 .set_timeline_change_observer(timer.get_timeline_change_observer(current_task));
248 }
249
250 Ok(Anon::new_private_file(
251 locked,
252 current_task,
253 Box::new(TimerFile {
254 timer,
255 timeline,
256 timer_file_info: Arc::new(Mutex::new(timer_file_info)),
257 }),
258 flags,
259 "[timerfd]",
260 ))
261 }
262
263 pub fn current_timer_spec(&self) -> itimerspec {
268 let (deadline, interval) = {
269 let guard = self.timer_file_info.lock();
270 (guard.deadline, guard.interval)
271 };
272 let now = self.timeline.now();
273 let remaining_time = if interval == zx::MonotonicDuration::default() && deadline <= now {
274 timespec_from_duration(zx::MonotonicDuration::default())
275 } else {
276 timespec_from_duration(
277 *deadline.delta(&now).expect("deadline and now come from same timeline"),
278 )
279 };
280
281 itimerspec { it_interval: timespec_from_duration(interval), it_value: remaining_time }
282 }
283
284 pub fn set_timer_spec(
289 &self,
290 current_task: &CurrentTask,
291 file_object: &FileObject,
292 timer_spec: itimerspec,
293 flags: u32,
294 ) -> Result<itimerspec, Errno> {
295 let mut tfi = self.timer_file_info.lock();
296 tfi.set_cancel_on_set(false);
301 let old_itimerspec = tfi.deadline.itimerspec(tfi.interval);
302
303 if timespec_is_zero(timer_spec.it_value) {
304 tfi.set_deadline(self.timeline.zero_time()).set_interval(zx::MonotonicDuration::ZERO);
307 self.timer.stop(current_task.kernel())?;
308
309 if (flags & TFD_TIMER_ABSTIME != 0)
319 && (flags & TFD_TIMER_CANCEL_ON_SET != 0)
320 && self.timeline.is_realtime()
321 {
322 tfi.set_cancel_on_set(true);
327 }
328 } else {
329 let new_deadline = if flags & TFD_TIMER_ABSTIME != 0 {
330 self.timeline.target_from_timespec(timer_spec.it_value)?
333 } else {
334 self.timeline.now()
336 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
337 timer_spec.it_value,
338 )?)
339 };
340 let new_interval = duration_from_timespec(timer_spec.it_interval)?;
341
342 self.timer.start(current_task, Some(file_object.weak_handle.clone()), new_deadline)?;
343 tfi.set_deadline(new_deadline).set_interval(new_interval);
344 }
345
346 Ok(old_itimerspec)
347 }
348
349 fn get_signals_from_events(events: FdEvents) -> zx::Signals {
352 if events.contains(FdEvents::POLLIN) {
353 zx::Signals::TIMER_SIGNALED
354 } else {
355 zx::Signals::NONE
356 }
357 }
358
359 fn get_events_from_signals(signals: zx::Signals) -> FdEvents {
360 let mut events = FdEvents::empty();
361
362 if signals.contains(zx::Signals::TIMER_SIGNALED) {
363 events |= FdEvents::POLLIN;
364 }
365 events
366 }
367
368 fn get_counter_events_from_signals(signals: zx::Signals) -> FdEvents {
372 let mut events = FdEvents::empty();
373
374 if signals.contains(zx::Signals::COUNTER_POSITIVE) {
375 events |= FdEvents::POLLIN;
376 }
377 events
378 }
379}
380
381impl FileOps for TimerFile {
382 fileops_impl_nonseekable!();
383 fileops_impl_noop_sync!();
384
385 fn close(
386 self: Box<Self>,
387 _locked: &mut Locked<FileOpsCore>,
388 _file: &FileObjectState,
389 current_task: &CurrentTask,
390 ) {
391 if let Err(e) = self.timer.stop(current_task.kernel()) {
392 log_warn!("Failed to stop the timer when closing the timerfd: {e:?}");
393 }
394 }
395
396 fn write(
397 &self,
398 _locked: &mut Locked<FileOpsCore>,
399 file: &FileObject,
400 _current_task: &CurrentTask,
401 offset: usize,
402 _data: &mut dyn InputBuffer,
403 ) -> Result<usize, Errno> {
404 debug_assert!(offset == 0);
405 if file.flags().contains(OpenFlags::NONBLOCK) { error!(EINVAL) } else { error!(ESPIPE) }
407 }
408
409 fn read(
410 &self,
411 locked: &mut Locked<FileOpsCore>,
412 file: &FileObject,
413 current_task: &CurrentTask,
414 offset: usize,
415 data: &mut dyn OutputBuffer,
416 ) -> Result<usize, Errno> {
417 debug_assert!(offset == 0);
418 file.blocking_op(locked, current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, |_| {
419 let mut tfi = self.timer_file_info.lock();
420 let is_cancel_on_set = tfi.cancel_on_set;
421 if is_cancel_on_set {
424 if tfi.reset_timeline_change_counter() != 0 {
425 return error!(ECANCELED);
428 }
429 return error!(EAGAIN);
431 }
432
433 if tfi.deadline.is_zero() {
434 return error!(EAGAIN);
435 }
436
437 let now = self.timeline.now();
438 log_debug!(
439 "read:\n\tnow={now:?}\n\ttfi={:?}\n\tnow_boot={:?}",
440 zx::MonotonicInstant::get(),
441 tfi.deadline
442 );
443 if tfi.deadline > now {
444 return error!(EAGAIN);
446 }
447
448 let count: i64 = if tfi.interval > zx::MonotonicDuration::default() {
449 let elapsed_nanos =
450 now.delta(&tfi.deadline).expect("timelines must match").into_nanos();
451 let num_intervals = elapsed_nanos / tfi.interval.into_nanos() + 1;
453 let new_deadline =
454 tfi.deadline + GenericDuration::from(tfi.interval * num_intervals);
455
456 self.timer.start(current_task, Some(file.weak_handle.clone()), new_deadline)?;
459 tfi.set_deadline(new_deadline);
460
461 num_intervals
463 } else {
464 tfi.set_deadline(self.timeline.zero_time())
465 .set_interval(zx::MonotonicDuration::ZERO)
466 .set_cancel_on_set(false);
467 self.timer.stop(current_task.kernel())?;
470
471 1
473 };
474
475 data.write(count.as_bytes())
476 })
477 }
478
479 fn wait_async(
480 &self,
481 _locked: &mut Locked<FileOpsCore>,
482 _file: &FileObject,
483 _current_task: &CurrentTask,
484 waiter: &Waiter,
485 events: FdEvents,
486 event_handler: EventHandler,
487 ) -> Option<WaitCanceler> {
488 let signal_handler = SignalHandler {
489 inner: SignalHandlerInner::ZxHandle(TimerFile::get_events_from_signals),
490 event_handler: event_handler.clone(),
491 err_code: None,
492 };
493 let canceler = waiter
494 .wake_on_zircon_signals(
495 &self.timer.as_handle_ref(),
496 TimerFile::get_signals_from_events(events),
497 signal_handler,
498 )
499 .expect("TODO return error");
500 let cancel_timeline_change = {
502 if !self.timeline.is_realtime() {
508 None
509 } else {
510 let guard = self.timer_file_info.lock();
511 guard.timeline_change_observer.as_ref().map(|obs| {
512 let handler = SignalHandler {
513 inner: SignalHandlerInner::ZxHandle(
514 TimerFile::get_counter_events_from_signals,
515 ),
516 event_handler,
517 err_code: None,
518 };
519 waiter
520 .wake_on_zircon_signals(
521 obs.get_timeline_change_counter_ref(),
522 zx::Signals::COUNTER_POSITIVE,
523 handler,
524 )
525 .expect("TODO return error")
526 })
527 }
528 };
529 let mut cancel = WaitCanceler::new_port(canceler);
530 if let Some(cancel_timeline_change) = cancel_timeline_change {
531 let cancel_timeline_change = WaitCanceler::new_port(cancel_timeline_change);
532 cancel = cancel.merge(cancel_timeline_change);
533 }
534
535 Some(cancel)
536 }
537
538 fn query_events(
539 &self,
540 _locked: &mut Locked<FileOpsCore>,
541 _file: &FileObject,
542 _current_task: &CurrentTask,
543 ) -> Result<FdEvents, Errno> {
544 let guard = self.timer_file_info.lock();
545 let counter_signals = guard
546 .timeline_change_observer
547 .as_ref()
548 .map(|observer| {
549 observer
550 .get_timeline_change_counter_ref()
551 .wait_one(zx::Signals::COUNTER_POSITIVE, zx::Instant::ZERO)
552 .to_result()
553 })
554 .unwrap_or_else(|| Ok(zx::Signals::empty()))
556 .unwrap_or_else(|_| zx::Signals::empty());
557 let events_from_counter = TimerFile::get_counter_events_from_signals(counter_signals);
558
559 let timer_signals = match self
560 .timer
561 .as_handle_ref()
562 .wait_one(zx::Signals::TIMER_SIGNALED, zx::MonotonicInstant::ZERO)
563 .to_result()
564 {
565 Err(zx::Status::TIMED_OUT) => zx::Signals::empty(),
566 res => res.unwrap(),
567 };
568 let events_from_timer = TimerFile::get_events_from_signals(timer_signals);
569 Ok(events_from_timer | events_from_counter)
570 }
571}