1use crate::fs::fuchsia::{BootZxTimer, MonotonicZxTimer};
6use crate::power::OnWakeOps;
7use crate::task::{
8 CurrentTask, EventHandler, Kernel, SignalHandler, SignalHandlerInner, WaitCanceler, Waiter,
9};
10use crate::time::{GenericDuration, HrTimer, TargetTime, Timeline, TimerWakeup};
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::{LockDepMutex, TimerFileInfoLock};
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 wakeup_type: TimerWakeup,
208
209 timer_file_info: Arc<LockDepMutex<TimerFileInfo, TimerFileInfoLock>>,
212}
213
214impl TimerFile {
215 pub fn new_file(
219 current_task: &CurrentTask,
220 wakeup_type: TimerWakeup,
221 timeline: Timeline,
222 flags: OpenFlags,
223 ) -> Result<FileHandle, Errno> {
224 let timer: Arc<dyn TimerOps> = match (wakeup_type, timeline) {
225 (TimerWakeup::Regular, Timeline::Monotonic) => Arc::new(MonotonicZxTimer::new()),
226 (TimerWakeup::Regular, Timeline::BootInstant) => Arc::new(BootZxTimer::new()),
227 (TimerWakeup::Regular, Timeline::RealTime)
228 | (TimerWakeup::Alarm, Timeline::BootInstant | Timeline::RealTime) => {
229 Arc::new(HrTimer::new())
230 }
231 (TimerWakeup::Alarm, Timeline::Monotonic) => {
232 unreachable!("monotonic times cannot be alarm deadlines")
233 }
234 };
235
236 let mut timer_file_info =
237 TimerFileInfo::new(timeline.zero_time(), zx::MonotonicDuration::default());
238
239 if timeline.is_realtime() {
240 timer_file_info
246 .set_timeline_change_observer(timer.get_timeline_change_observer(current_task));
247 }
248
249 Ok(Anon::new_private_file(
250 current_task,
251 Box::new(TimerFile {
252 timer,
253 timeline,
254 wakeup_type,
255 timer_file_info: Arc::new(timer_file_info.into()),
256 }),
257 flags,
258 "[timerfd]",
259 ))
260 }
261
262 pub fn wakeup_type(&self) -> TimerWakeup {
263 self.wakeup_type
264 }
265
266 pub fn current_timer_spec(&self) -> itimerspec {
271 let (deadline, interval) = {
272 let guard = self.timer_file_info.lock();
273 (guard.deadline, guard.interval)
274 };
275 let now = self.timeline.now();
276 let remaining_time = if interval == zx::MonotonicDuration::default() && deadline <= now {
277 timespec_from_duration(zx::MonotonicDuration::default())
278 } else {
279 timespec_from_duration(
280 *deadline.delta(&now).expect("deadline and now come from same timeline"),
281 )
282 };
283
284 itimerspec { it_interval: timespec_from_duration(interval), it_value: remaining_time }
285 }
286
287 pub fn set_timer_spec(
292 &self,
293 current_task: &CurrentTask,
294 file_object: &FileObject,
295 timer_spec: itimerspec,
296 flags: u32,
297 ) -> Result<itimerspec, Errno> {
298 let mut tfi = self.timer_file_info.lock();
299 tfi.set_cancel_on_set(false);
304 let old_itimerspec = tfi.deadline.itimerspec(tfi.interval);
305
306 if timespec_is_zero(timer_spec.it_value) {
307 tfi.set_deadline(self.timeline.zero_time()).set_interval(zx::MonotonicDuration::ZERO);
310 self.timer.stop(current_task.kernel())?;
311
312 if (flags & TFD_TIMER_ABSTIME != 0)
322 && (flags & TFD_TIMER_CANCEL_ON_SET != 0)
323 && self.timeline.is_realtime()
324 {
325 tfi.set_cancel_on_set(true);
330 }
331 } else {
332 let new_deadline = if flags & TFD_TIMER_ABSTIME != 0 {
333 self.timeline.target_from_timespec(timer_spec.it_value)?
336 } else {
337 self.timeline.now()
339 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
340 timer_spec.it_value,
341 )?)
342 };
343 let new_interval = duration_from_timespec(timer_spec.it_interval)?;
344
345 self.timer.start(current_task, Some(file_object.weak_handle.clone()), new_deadline)?;
346 tfi.set_deadline(new_deadline).set_interval(new_interval);
347 }
348
349 Ok(old_itimerspec)
350 }
351
352 fn get_signals_from_events(events: FdEvents) -> zx::Signals {
355 if events.contains(FdEvents::POLLIN) {
356 zx::Signals::TIMER_SIGNALED
357 } else {
358 zx::Signals::NONE
359 }
360 }
361
362 fn get_events_from_signals(signals: zx::Signals) -> FdEvents {
363 let mut events = FdEvents::empty();
364
365 if signals.contains(zx::Signals::TIMER_SIGNALED) {
366 events |= FdEvents::POLLIN;
367 }
368 events
369 }
370
371 fn get_counter_events_from_signals(signals: zx::Signals) -> FdEvents {
375 let mut events = FdEvents::empty();
376
377 if signals.contains(zx::Signals::COUNTER_POSITIVE) {
378 events |= FdEvents::POLLIN;
379 }
380 events
381 }
382}
383
384impl FileOps for TimerFile {
385 fileops_impl_nonseekable!();
386 fileops_impl_noop_sync!();
387
388 fn close(self: Box<Self>, _file: &FileObjectState, current_task: &CurrentTask) {
389 if let Err(e) = self.timer.stop(current_task.kernel()) {
390 log_warn!("Failed to stop the timer when closing the timerfd: {e:?}");
391 }
392 }
393
394 fn write(
395 &self,
396 file: &FileObject,
397 _current_task: &CurrentTask,
398 offset: usize,
399 _data: &mut dyn InputBuffer,
400 ) -> Result<usize, Errno> {
401 debug_assert!(offset == 0);
402 if file.flags().contains(OpenFlags::NONBLOCK) { error!(EINVAL) } else { error!(ESPIPE) }
404 }
405
406 fn read(
407 &self,
408 file: &FileObject,
409 current_task: &CurrentTask,
410 offset: usize,
411 data: &mut dyn OutputBuffer,
412 ) -> Result<usize, Errno> {
413 debug_assert!(offset == 0);
414 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
415 let mut tfi = self.timer_file_info.lock();
416 let is_cancel_on_set = tfi.cancel_on_set;
417 if is_cancel_on_set {
420 if tfi.reset_timeline_change_counter() != 0 {
421 return error!(ECANCELED);
424 }
425 return error!(EAGAIN);
427 }
428
429 if tfi.deadline.is_zero() {
430 return error!(EAGAIN);
431 }
432
433 let now = self.timeline.now();
434 log_debug!(
435 "read:\n\tnow={now:?}\n\ttfi={:?}\n\tnow_boot={:?}",
436 zx::MonotonicInstant::get(),
437 tfi.deadline
438 );
439 if tfi.deadline > now {
440 return error!(EAGAIN);
442 }
443
444 let count: i64 = if tfi.interval > zx::MonotonicDuration::default() {
445 let elapsed_nanos =
446 now.delta(&tfi.deadline).expect("timelines must match").into_nanos();
447 let num_intervals = elapsed_nanos / tfi.interval.into_nanos() + 1;
449 let new_deadline =
450 tfi.deadline + GenericDuration::from(tfi.interval * num_intervals);
451
452 self.timer.start(current_task, Some(file.weak_handle.clone()), new_deadline)?;
455 tfi.set_deadline(new_deadline);
456
457 num_intervals
459 } else {
460 tfi.set_deadline(self.timeline.zero_time())
461 .set_interval(zx::MonotonicDuration::ZERO)
462 .set_cancel_on_set(false);
463 self.timer.stop(current_task.kernel())?;
466
467 1
469 };
470
471 data.write(count.as_bytes())
472 })
473 }
474
475 fn wait_async(
476 &self,
477 _file: &FileObject,
478 _current_task: &CurrentTask,
479 waiter: &Waiter,
480 events: FdEvents,
481 event_handler: EventHandler,
482 ) -> Option<WaitCanceler> {
483 let signal_handler = SignalHandler {
484 inner: SignalHandlerInner::ZxHandle(TimerFile::get_events_from_signals),
485 event_handler: event_handler.clone(),
486 err_code: None,
487 };
488 let canceler = waiter
489 .wake_on_zircon_signals(
490 &self.timer.as_handle_ref(),
491 TimerFile::get_signals_from_events(events),
492 signal_handler,
493 )
494 .expect("TODO return error");
495 let cancel_timeline_change = {
497 if !self.timeline.is_realtime() {
503 None
504 } else {
505 let guard = self.timer_file_info.lock();
506 guard.timeline_change_observer.as_ref().map(|obs| {
507 let handler = SignalHandler {
508 inner: SignalHandlerInner::ZxHandle(
509 TimerFile::get_counter_events_from_signals,
510 ),
511 event_handler,
512 err_code: None,
513 };
514 waiter
515 .wake_on_zircon_signals(
516 obs.get_timeline_change_counter_ref(),
517 zx::Signals::COUNTER_POSITIVE,
518 handler,
519 )
520 .expect("TODO return error")
521 })
522 }
523 };
524 let mut cancel = WaitCanceler::new_port(canceler);
525 if let Some(cancel_timeline_change) = cancel_timeline_change {
526 let cancel_timeline_change = WaitCanceler::new_port(cancel_timeline_change);
527 cancel = cancel.merge(cancel_timeline_change);
528 }
529
530 Some(cancel)
531 }
532
533 fn query_events(
534 &self,
535 _file: &FileObject,
536 _current_task: &CurrentTask,
537 ) -> Result<FdEvents, Errno> {
538 let guard = self.timer_file_info.lock();
539 let counter_signals = guard
540 .timeline_change_observer
541 .as_ref()
542 .map(|observer| {
543 observer
544 .get_timeline_change_counter_ref()
545 .wait_one(zx::Signals::COUNTER_POSITIVE, zx::Instant::ZERO)
546 .to_result()
547 })
548 .unwrap_or_else(|| Ok(zx::Signals::empty()))
550 .unwrap_or_else(|_| zx::Signals::empty());
551 let events_from_counter = TimerFile::get_counter_events_from_signals(counter_signals);
552
553 let timer_signals = match self
554 .timer
555 .as_handle_ref()
556 .wait_one(zx::Signals::TIMER_SIGNALED, zx::MonotonicInstant::ZERO)
557 .to_result()
558 {
559 Err(zx::Status::TIMED_OUT) => zx::Signals::empty(),
560 res => res.unwrap(),
561 };
562 let events_from_timer = TimerFile::get_events_from_signals(timer_signals);
563 Ok(events_from_timer | events_from_counter)
564 }
565}