Apple C header licenses
Seen in the prelude of the Kernel.framework/Versions/A/Headers/IOKit/hid/*.h
"[...] APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
QUIET ENJOYMENT OR NON-INFRINGEMENT. [...]"
Not fit for quiet enjoyment? Oh, my.
What slows down development...
... Vista bluescreening every time I terminate a hung Python process that has a
lock ("Process has locked pages"). Yep, I can trigger it consistently
Makes.. me.. angry!
Multithreaded goodness for pyglet
I've finally gotten some good results after spending the last few months (on and
off) refactoring the pyglet.media module in pyglet to use multiple threads.
There were two main reasons for attempting this: to make better use of multi-core
machines (pyglet is currently single threaded), and to avoid having to schedule
audio pump in the main event loop (in pyglet 1.0 this was explicit, in 1.1 it's
done on the clock).
The problem with having the audio pump in the main loop is that it requires
application developers to manually tune their programs to keep the audio buffer
full -- and this is obviously very dependent on the hardware and drivers
available. One motivating example was my last PyWeek entry, which had background
music that stalled during long loading times (I managed to get this down to just
the initial loading time, and smooth for the rest of the game, but this was a lot
of effort, and removing the initial pause proved too difficult).
The redesigned media module is still residing in the experimental/mt_media
directory of SVN trunk. Only the OpenAL driver is anywhere near complete. The
DirectSound driver has yet to be ported to the multithreaded API, and the ALSA
driver has been deprecated in favour of a new PulseAudio driver. PulseAudio is
proving far more reliable and capable than the ALSA user-space daemon, and has
been the default audio server in both Ubuntu and Fedora Core for some time. The
PulseAudio driver is mostly complete, but has no 3D capability (Linux users can
still choose to use OpenAL as an alternative).
The audio driver modules are required to pump themselves now. The PulseAudio
driver does this using the built-in PA thread runloop, whereas the OpenAL driver
creates a Python thread that periodically wakes.
Much of the shared code between drivers regarding video frame synchronisation
has been moved into the base classes. This should greatly reduce the amount of
effort required to develop a new audio driver. Audio drivers dispatch events to
the Player object when a new video frame should be displayed. New methods on
pyglet.app make it easy to post events from one thread into the main event loop
safely (these also automatically wake up the main event loop if it's sleeping,
allowing more opportunities for people to integrate multithreaded code into their
The AVbin source driver also now spawns a worker thread for decoding video
frames. Since most of the work in decoding the frame is done outside of Python
(in FFmpeg), this is a great chance for pyglet to do some real multiprocessing.
Quite a lot of work went into ensuring the queue of video frames to be decoded is
kept up-to-date with what's needed on-screen; without an excessive preroll period
or memory usage.
I've done most development on my 900MHz iBook, which is incapable enough that it
can't even play YouTube videos in real time (though pyglet can play them just
fine once downloaded, thanks to FFmpeg). This has forced me to make the
implementation efficient enough to work on old computers; the overhead of the
extra thread processing is significant and required several manual context
switches to get everything playing (almost) as well as the old, single-threaded
On newer computers the performance is fantastic. I did a quick benchmark test
on my 1.8GHz Core 2 Duo Mac Mini. It happily plays 7 SD videos simultaneously
(DivX or Xvid encoding) without sweating, whereas the old code could only play 3
videos. Watching the activity monitor shows that both cores are now being
utilised fully when needed (and run each at around 5% when playing a single
Expect to see this new code in pyglet 1.2. I'll introduce some more of the new
features over the next few weeks. I'll also be talking about pyglet 1.2 at OSDC
2008 in Sydney in December.
Good looking tick mark distribution
Given a min/max range of any magnitude, how do you generate a "nice
looking" distribution of values to cover the range? My need for this was to
generate tick marks on a graph. The function I came up with works quite nicely,
def distribute_nicely(min_val, max_val, min_ticks=3, max_ticks=8):
if max_val - min_val == 0:
mag = 10 ** int(math.log10(max_val - min_val) - .5)
if mag == 0:
mag = 0.1
for multiplier in (10, 5, 2, 1, .5, .2, .1):
interval = multiplier * mag
if min_ticks <= (max_val - min_val) / interval <= max_ticks:
min_val = (min_val // interval) * interval
interval = (max_val - min_val) / max_ticks or max_val - min_val
if interval > 1:
return range(min_val, max_val + interval, interval)
return [i * interval \
for i in range(int(min_val / interval),
int(max_val / interval) + 1)]
>>> distribute_nicely(0, 10)
[0, 2, 4, 6, 8, 10]
>>> distribute_nicely(0, 100)
[0, 20, 40, 60, 80, 100]
>>> distribute_nicely(0, 5)
[0, 1, 2, 3, 4, 5]
>>> distribute_nicely(3, 8)
[3, 4, 5, 6, 7, 8]
>>> distribute_nicely(24, 786)
[0, 200, 400, 600, 800]
>>> distribute_nicely(0.21, 0.86)
[0.2, 0.4, 0.6, 0.8]
>>> distribute_nicely(-8, 8)
[-10, -5, 0, 5, 10]
>>> distribute_nicely(-105, 105)
[-150, -100, -50, 0, 50, 100, 150]
I'd be interested to hear if anyone has an alternative function or improvements
to this one. Or if there's one in the standard library -- I always tend to miss
Clean termination of daemon Python threads
Daemonic threads in Python are threads that will not prevent the interpreter
from exiting (put another way, the interpreter shuts down when all non-daemon
threads exit). When the interpreter shuts down, all variables are set to None,
then each daemon thread is woken up to crash (unexpectedly finding all its
variables, globals and builtins missing).
Here's a nifty pattern that suppresses the ugly exception trace resulting from
these crashes being printed to the terminal:
.... do work ...
This ensures ordinary exceptions are re-raised, but interpreter shutdown related
exceptions are suppressed, as True is evaluated as None. In the off-chance that
some future or alternative Python interpreter doesn't have the same strange
daemon thread shutdown behaviour, the thread will still behave correctly.