[plt-scheme] High precision timing and MrEd/OSX

From: Rohan Drape (rd at alphalink.com.au)
Date: Tue Dec 21 19:13:58 EST 2004

On Tue, 21 Dec 2004 07:13:59 -0700, Matthew Flatt wrote
> Just to make sure I understand, this is as measured by semaphore 
> posts through `high-precision-time:set-timer' callbacks?


> Now that I look, I see lots of problems with posting a semaphore 
> from a signal handler. MzScheme doesn't expect calls to 
> scheme_sema_post() from other thread or from signal handlers. 
> In other words, MzScheme's semaphores are only thread-safe with 
> respect to MzScheme threads. Also, posting the semaphore won't 
> necessarily wake up the thread scheduler (though because the 
> scheduler sleeps with select() under Linux and for MzScheme 
> under OS X, then a signal will often wake up the scheduler). 

Well, when I first wrote this, perhaps 18 months ago now, I was
very impressed at the responsiveness of the thread system, and
it has always worked as well if not better than I expected.  
I would be very happy to learn a better solution though.

> I think that `current-inexact-milliseconds' returns the same 
> value as `high-precision-time:get-time', and `sleep' effectively 
> uses `current-inexact-milliseconds'. Could you get the result 
> you want with a background thread that calls `sleep' and 
> `semaphore-post', instead of a timer signal and signal handler 
> that calls `semaphore-post'? 

The module is used to implement a scheduler.  When a new item is 
added to the front of the schedule, high-precision-time:set-timer 
is called with the interval to the new entry.  The setitimer 
semantics allow the timer to be reset by subsequent calls.  (The 
scheduler has an epsilon value to avoid rescheduling below the 
timing threshold of the system.)

I don't see how sleep by itself can be made to work efficiently
in this scenario?  If mzscheme implemented a set-timer primitive
with millisecond accuracy I would use it!  If I knew a better 
approach I would use it!

Also, I looked into MrEd and, if I followed the #if switches 
correctly, the sleep works as follows:

* mzscheme assigns scheme_sleep = MacSleep.

* setup_basic_env: Assigns mzsleep = scheme_sleep, then assigns
scheme_sleep = MrEdSleep.  That is mzsleeep is the scheme_sleep 
given to mred by mzscheme.  

* MrEdSleep: calls MrEdMacSleep with the global mzsleep as the last

* MrEdMacSleep: the last argument is a procedure, mzsleep, which is
called to sleep.

* MacSleep: Uses WaitNextEvent to sleep.

* WNE: Replaces WaitNextEvent in some contexts.

* XCode says this about WaitNextEvent: When running on Mac OS X, a
Carbon application will block for the entire duration of the sleep
parameter if there are no events to be delivered. 

* It is possible that WaitNextEvent on OSX is using a sleep that
interacts badly with setitimer.

* The Darwin man pages for sleep and usleep indicate they
are implemented in using nanosleep and should not interfere with 
the timers.

I did not have time to write a test to isolate the interaction of
WaitNextEvent and setitimer, but it is beginning to look rather 
complicated in any case, though perhaps some signal masking trickery 
could work...

Thanks again for looking at this, and for PLT alltogether!


Posted on the users mailing list.