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.

Hard Disk Sentinel

HDSentinel is an utility that interprets the SMART information of your hard disk drives. Their flagship product is an extensive GUI tool for Win32, but they also have a small command-line application for GNU/Linux.

It was recently uploaded to ArchLinux AUR and I gave it a whirl.

Its output for one of my disks claimed it to be close to failure:

HDD Device  2: /dev/sda
HDD Model ID : ST3160023A
HDD Serial No: 5JS2NX0R
HDD Revision : 3.06
HDD Size     : 152628 MB
Interface    : IDE/ATA
Temperature  : 42 °C
Health       : 13 %
Performance  : 100 %
Power on time: 658 days, 7 hours
Est. lifetime: 19 days

The theory behind HDSentinel seems sound, so I’m looking forward to see whether the prediction will hold.

Using Vim with Common Lisp

The Emacs-based Slime is an excellent IDE for Common Lisp up to the point of inducing people to switch from Vim to Emacs.

Personally I feel that there’s a need for either a full-featured vi written in Common Lisp (no, not GUI-only and written in Python, sorry) or a vi mode for Emacs that is consistent and also full-featured.

Until then you have several possiblities, most of which have been devised pretty recently:

  • Nekthuth uses the Swank/Slime model with a library on the Lisp side and a Python scripted Vim plugin on the editor side. It offers a bunch of good things, but I haven’t tried it, yet.
  • Limp seems to be the current star among Vim/Lisp bridges, with an active community. I’m going to try this soon.
  • Like Slime for Vim is a solution that relies almost solely on GNU Screen. No Hyperspec lookup or function completion without additional work, though.
  • Use some additional hints for a comfortable setup.

These approaches have varying implementation support. You’re always fine with SBCL, but Nekthuth, for example, doesn’t support other implementations.

I’m currently using the plain rlwrap approach but I might take advantage of some other approach soon.

Using Finance::Quote to watch exchange rates

Since I’m often receiving payments in USD I need to keep track of the USD/EUR exchange rates.

I don’t want to run any GUI apps for that though or visit web sites, so I just slightly adapted the Finance::Quote Perl module’s simple example to do what I need:

#!/usr/bin/perl
 
use Finance::Quote;
 
$q = Finance::Quote->new;
$q->timeout(60);
 
print $q->currency("USD","EUR")."\n";

A functional interface for trivial queries like that would be nice in any case. Finance::Quote has one but it’s deprecated; maybe the authors are Java zealots.

The elements of a good drawing

Mark Chong is a freelance drawing artist who semi-regularly posts videos on his blog Longer than Ten-Minute Drawing Techniques.

In the latest video he’s explaining the elements successful drawings. The tutorial is focused on storyboard-based drawing, but the general techniques hold for any drawing.

Like this video? Support Mark by donating a wee bit to him for his rent!

Reflecting on one’s coding self

A surprise incentive to resume blog writing from Aaron Feng, heh.

How old were you when you first started programming?

Ten or eleven.

How did you get started in programming?

Read books about it, peeked at other people’s code, got in front of a computer, started hacking. :)

What was your first language?

BASIC.

What was the first real program you wrote?

A BASIC program calculating the Least Common Multiple of two integers.
On paper.

What languages have you used since you started programming?

BASIC, Turbo Pascal, C, C++, Java, C#, Common Lisp, Scheme, Bourne Shell, Awk, Perl, x86 Assembler, MIPS Assembler, TeX, JavaScript, PHP, SQL.

What was your first professional programming gig?

Depends on what you’d call “professional”.

When I was about 15 years old I wrote a dBase3 to CSV converter in Turbo Pascal for which I received 20 DM (about 10 EUR).

If you knew then what you know now, would you have started programming?

You bet.

If there is one thing you learned along the way that you would tell new developers, what would it be?

Don’t be content with your skills and work. Critically examine your own and others’ results.
Push your limits, push, push, push.

What’s the most fun you’ve ever had … programming?

Me and a friend hacking up a space game prototype with GCC and Allegro at night. I slowly discovered the joys of GNU/Linux and free software at that time.

Writing a boot loader in Assembler.

Letting creative impulses flow into Lisp code with little hindrance.

Who’s next?

Michael Prinzinger
Stephen Compall

I’d also tag Sebastian Heberer but he ain’t got a running blog right now.

Collecting ASDF system dependencies

Here’s a snippet that will recursively collect all dependencies of one or more ASDF systems:

(asdf:oos 'asdf:load-op 'asdf)
(asdf:oos 'asdf:load-op 'metatilities)
 
(defun direct-dependencies (component)
  (cdadr (asdf:component-depends-on 'asdf:load-op
                                    (asdf:find-component nil component))))
 
(defun normalize-system-id (id)
  (intern (symbol-name id) "KEYWORD"))
 
(defun %effective-dependencies (components)
  "Helper function."
  (when components
    (remove-duplicates
      (append components
              (%effective-dependencies
                (mapcar #'normalize-system-id
                        (remove-if #'null
                                   (metatilities:flatten
                                     (mapcar #'direct-dependencies
                                             components))))))
      :test #'eq)))
 
(defun effective-dependencies (components)
  "Find all dependencies needed for the list of COMPONENTS
(which may be an atom, too)."
  (let ((components (metatilities:ensure-list components)))
    (set-difference (%effective-dependencies components) components
                    :key #'normalize-system-id)))
 
;; usage
(effective-dependencies :weblocks)
 
(:LW-COMPAT :CLOSER-MOP :MOPTILITIES :METATILITIES-BASE :TRIVIAL-GRAY-STREAMS
 :ASDF-SYSTEM-CONNECTIONS :METABANG-DYNAMIC-CLASSES :FLEXI-STREAMS :CFFI
 :SB-GROVEL :CL-CONTAINERS :METABANG-BIND :CHUNGA :CL-BASE64 :CL-FAD :CL-PPCRE
 :CL+SSL :MD5 :RFC2388 :SB-BSD-SOCKETS :SB-POSIX :URL-REWRITE :PARENSCRIPT
 :FARE-UTILS :METATILITIES :HUNCHENTOOT :CL-WHO :CL-JSON :PURI :FARE-MATCHER
 :CL-CONT :ITERATE)
« Previous PageNext Page »