Weird release policies in PEAR land

I’m not very fond of PHP, but it’s hard to dodge it.

Fortunately the PEAR project has a set of excellent (well, as close to excellency as PHP lets you get…) libraries for all sorts of purposes.

The only thing with them is that they have problems managing their releases. The main site of the popular HTML Quickform library sports a fat warning sign, claiming that this package had been superseded by the aptly named HTML QuickForm 2 package.

That’s funny, because most if not all other packages depending on QuickForm are still built for the old version. Even more funny is what a vanilla install of the PEAR package tool will throws at anyone attempting to install QuickForm2:

% sudo pear install HTML_QuickForm2
Failed to download pear/HTML_QuickForm2 within preferred state "stable", latest release is version 0.2.0, stability "alpha", use "channel://pear.php.net/HTML_QuickForm2-0.2.0" to install
Cannot initialize 'channel://pear.php.net/HTML_QuickForm2', invalid or missing package file
Package "channel://pear.php.net/HTML_QuickForm2" is not valid
install failed

Now take into account that this situation has been in place for at least one year. Not really a role model for a sane software development release process.

Evidence B: Structures_Datagrid and a bunch of other packages are also marked “beta” but have been used by the majority (I daresay) of developers without any problems over the course of the last dekamonths.

What gives, PEAR?

Partial MP3 decoder in Haskell

Here’s a partially conforming MP3 decoder in Haskell.

It looks pretty clean even to me, not being a Haskell programmer.

Who’s up for it in Common Lisp? :)

JES, a KISS mail server

JES is a tiny Java mail server.

Very useful for testing local mail emitting routines.

Usage: download, extract, quickly edit the configuration files and execute bin/mail.sh.

Thanks, Eric!

Threads in SBCL

Working with threads in SBCL isn't obvious in some respects. I'd like to use this post to collect some hints for people starting out with multi-threaded programming in SBCL. Prerequisite: SBCL compiled with threads (still not the default). Check with (not (null (member :sb-thread *features*))).

Usage

All thread stuff lies in the SB-THREAD package, so you need to import it when you don't want to do prefixing:
(use-package :sb-thread)

Creating a thread

(make-thread (lambda () ...) :name "optional name")
Spawns a new thread executing the lambda and return it. The thread will silently terminate when the lambda returns. You can wait for its completion using JOIN-THREAD.

Listing threads

(list-all-threads)
'nuff said.

Debugging threads

Use RELEASE-FOREGROUND to switch between multiple threads waiting for input:
CL-USER(15): (make-thread (lambda () (break)))
 
debugger invoked on a SIMPLE-CONDITION in thread #< thread RUNNING {AA9E831}>:
  break
 
#< thread RUNNING {AA9E831}>
CL-USER(16): (release-foreground)
 
Resuming thread #< thread RUNNING {A93CD49}>
 
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
 
restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE        ] Return from BREAK.
  1: [TERMINATE-THREAD] Terminate this thread (#< thread RUNNING {A93CD49}>)
 
(BREAK "break")3
0] (release-foreground)
Resuming thread #< thread "initial thread" RUNNING {A6DD551}>
CL-USER(17):

Cleaning up

Perhaps this is obvious to someone familiar with the stack semantics of threading:
CL-USER(25): (make-thread (lambda () (unwind-protect (break) (format t "cleanup~%"))))
 
#<thread RUNNING {AB89DB9}>
CL-USER(26):
debugger invoked on a SIMPLE-CONDITION in thread #< thread RUNNING {AB89DB9}>:
  break
(release-foreground)
Resuming thread #< thread RUNNING {AB89DB9}>
 
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
 
restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE        ] Return from BREAK.
  1: [TERMINATE-THREAD] Terminate this thread (#< thread RUNNING {AB89DB9}>)
 
(BREAK "break")
0]
1
Resuming thread #< thread "initial thread" RUNNING {A6DD551}>
1
CL-USER(27): cleanup
</thread>

Miscellaneous notes

Hash tables

Somewhere in time SBCL dropped locking for hash tables to give the user the freedom to implement the level of locking they need. So you need to protect your hash tables for concurrent access or else.

Thread model

There are two fundamental models for a thread framework: rely on the native OS facilities for threading or implement some sort of concurrency scheduling yourself. Allegro uses the latter method while SBCL and ECL use native threading.

HID remotes and LIRC

Nowadays USB HID remotes that act like a keyboard and mouse in one device seem to be popular.

At least I unknowingly got me one and then had problems getting it to run with LIRC.

Fortunately Chris Grove figured out how to make this work, after three weeks of fiddling.

Here’s the recipe.

These remotes register themselves as two HID devices, a keyboard and a mouse. Some keys it sends as keyboard, some as mouse. So first you need to find out which devices it will use:

cat /proc/bus/input/devices

Try to identify the devices and note down the event node name on the line where it says “Handlers”:

[...]
N: Name="HID 05a4:9881"
[...]
H: Handlers=kbd event7
[...]
N: Name="HID 05a4:9881"
[...]
H: Handlers=kbd mouse2 event8
[...]

So mine is at /dev/input/event7 and /dev/input/event8.

Now we need to run an lircd instance for both of them using the dev/input devices and link them. Here’s a script that does this:

#!/bin/sh
 
sudo lircd -Hdev/input -d/dev/input/event7 -o/dev/lircd1 \
  --pidfile=/var/run/lircd1.pid --listen
 
sudo lircd -Hdev/input -d/dev/input/event8 -o/dev/lircd \
  --pidfile=/var/run/lircd.pid --connect=localhost:8765

Done! Everything should work now.

Vim: Substitute in all buffers

To replace all instances of FOO with BAR in one file, you’d do:

:%s/FOO/BAR/g|:up

The pipe | lets you separate multiple commands and :up is like :w but only writes changed buffers.

Now for all open files:

:bufdo :%s/FOO/BAR/g|:up

Roughly translates to: for all open buffers, substitute FOO with BAR and write the changes.