diff --git a/changelog.md b/changelog.md index d9a634cbc8..308cc33d34 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,8 @@ when upgrading from a version of rust-sdl2 to another. ### Unreleased +[PR #1270](https://github.com/Rust-SDL2/rust-sdl2/pull/1270) **BREAKING CHANGE** Remove &mut self requirement in `TimerSubsystem::delay`; Add `TimerSubsystem::ticks64` + [PR #1225](https://github.com/Rust-SDL2/rust-sdl2/pull/1225) Update wgpu to 0.12 and fix raw-window-handle-with-wgpu example [PR #1250](https://github.com/Rust-SDL2/rust-sdl2/pull/1250) Add `lib64` to native library search path when using bundled feature diff --git a/src/sdl2/timer.rs b/src/sdl2/timer.rs index 339af63968..678f36518c 100644 --- a/src/sdl2/timer.rs +++ b/src/sdl2/timer.rs @@ -12,6 +12,9 @@ impl TimerSubsystem { /// /// * when the timer is dropped /// * or when the callback returns a non-positive continuation interval + /// + /// The callback is run in a thread that is created and managed internally + /// by SDL2 from C. The callback *must* not panic! #[must_use = "if unused the Timer will be dropped immediately"] #[doc(alias = "SDL_AddTimer")] pub fn add_timer<'b, 'c>(&'b self, delay: u32, callback: TimerCallback<'c>) -> Timer<'b, 'c> { @@ -34,18 +37,45 @@ impl TimerSubsystem { /// Gets the number of milliseconds elapsed since the timer subsystem was initialized. /// /// It's recommended that you use another library for timekeeping, such as `time`. + /// + /// This function is not recommended in upstream SDL2 as of 2.0.18 and internally + /// calls the 64-bit variant and masks the result. #[doc(alias = "SDL_GetTicks")] pub fn ticks(&self) -> u32 { - // Google says this is probably not thread-safe (TODO: prove/disprove this). + // This is thread-safe as long as the ticks subsystem is inited, and + // tying this to `TimerSubsystem` ensures the timer subsystem can + // safely make calls into the ticks subsystem without invoking a + // thread-unsafe `SDL_TicksInit()`. + // + // This binding is offered for completeness but is debatably a relic. unsafe { sys::SDL_GetTicks() } } + /// Gets the number of milliseconds elapsed since the timer subsystem was initialized. + /// + /// It's recommended that you use another library for timekeeping, such as `time`. + #[doc(alias = "SDL_GetTicks64")] + pub fn ticks64(&self) -> u64 { + // This is thread-safe as long as the ticks subsystem is inited, and + // tying this to `TimerSubsystem` ensures the timer subsystem can + // safely make calls into the ticks subsystem without invoking a + // thread-unsafe `SDL_TicksInit()`. + // + // This binding is offered for completeness but is debatably a relic. + unsafe { sys::SDL_GetTicks64() } + } + /// Sleeps the current thread for the specified amount of milliseconds. /// /// It's recommended that you use `std::thread::sleep()` instead. #[doc(alias = "SDL_Delay")] - pub fn delay(&mut self, ms: u32) { - // Google says this is probably not thread-safe (TODO: prove/disprove this). + pub fn delay(&self, ms: u32) { + // This is thread-safe as long as the ticks subsystem is inited, and + // tying this to `TimerSubsystem` ensures the timer subsystem can + // safely make calls into the ticks subsystem without invoking a + // thread-unsafe `SDL_TicksInit()`. + // + // This binding is offered for completeness but is debatably a relic. unsafe { sys::SDL_Delay(ms) } } @@ -88,6 +118,13 @@ impl<'b, 'a> Drop for Timer<'b, 'a> { } extern "C" fn c_timer_callback(_interval: u32, param: *mut c_void) -> u32 { + // FIXME: This is UB if the callback panics! (But will realistically + // crash on stack underflow.) + // + // I tried using `std::panic::catch_unwind()` here and it compiled but + // would not catch. Maybe wait for `c_unwind` to stabilize? Then the behavior + // will automatically abort the process when panicking over an `extern "C"` + // function. let f = param as *mut TimerCallback<'_>; unsafe { (*f)() } }