06
Sep 10

Some thoughts (and code) around GObject-Introspection

There is one single thing that is, in my opinion, generating a fair amount of hype and reinvigorated interest in the GNOME platform: GObject-Introspection (or “GI” to save some typing :P ). In short, it works like this:

  • Library developers add annotations to the documentation comments of functions.
  • The GI support tools generate XML and compiled API metadata.
  • You have a library to use that metadata at runtime.

The last thing is very interesting, especially the runtime usage of metadata… because it enables dynamic language bindings. This means that developers no longer have to build e.g. the Python bindings for themselves but just annotating the source code! (Side note, they already exist as PyGI.) A direct implication of this is that there is a single “glue module” for your favourite language, and that all GI-capable libraries are available without having to build any code. To make it clear, let me put it this way:

Holy introspection, Batman!

Definitely GI is somewhat that makes the platform even more awesome than before, because it will allow for having support for more languages to be used to write GNOME applications, and also bindings will not lag behind the libraries.

Being so awesome, I wanted to try it out. It has been some time since I do not use Lua, so I thought it would be interesting to write a GI glue code for Lua, provided that writing extensions using its C API is dead simple. This way LuiGI was born and I invested about a total of eight hours to write ~1300 lines of code which allow for using some GI-aware libraries. The mandatory screenshot:

LuiGI Screenshot

The above application window was created entirely from Lua, with LuiGI using libgirepository to dynamically find functions, classes and methods at runtime, using the following script (I especially like how the Lua syntactic sugar for function calls on tables makes setting properties at instantiation time look):

local Gtk = require ("gi").Gtk
Gtk.init (0, nil)
 
window  = Gtk.Window    { title = "Toolbared window",
                          default_width  = 400,
                          default_height = 300,
                          allow_shrink   = false }
sbar    = Gtk.Statusbar { has_resize_grip = true }
toolbar = Gtk.Toolbar   { tooltips = true }
vbox    = Gtk.VBox      {}
 
sbar_ctx = sbar:get_context_id ("default")
sbar:push (sbar_ctx, "Look ma, this was set from Lua!")
 
toolbar:insert (Gtk.ToolButton { stock_id = "gtk-quit"  }, -1)
toolbar:insert (Gtk.ToolButton { stock_id = "gtk-about" }, -1)
 
vbox:pack_start (toolbar, false, false, 0)
vbox:pack_start (Gtk.Label { label = "Empty area" }, true, true, 0)
vbox:pack_end   (sbar, false, false, 0)
 
window:add (vbox)
window:show_all ()
 
Gtk.main ()

Note that there is no event handling at all in the above code. The reason is that I have not yet implemented support for using Lua functions as callbacks ;-)

What I think about GI after getting my hands dirty —by writing a bind, no less— is that the Batman image above is perfectly well-grounded. The code needed to glue GI support into some language is not trivial, but I still think the API is quite convenient provided that it deals with a rather complicated issue without breaking any existing GObject-based code. The part I have found harder so far is handling conversion of values between the Lua and C worlds.

Today I was hacking a bit more on LuiGI, and dropped by the #introspection IRC channel, precisely to ask a couple of questions about how to get some information for type conversion, and the kind people there made me note about LGI, which is also a dynamic GI binding for Lua. I have not been able of testing it because it needs a bleeding edge libgirepository, but looking at its code I can tell that it is more complete than my own, so I will be probably contributing to it instead of duplicating efforts.

Some final words: I am truly convinced that GI does not only looks good, but it is actually very good. I foresee that this gust of fresh wind will bring more awesomeness to GNOME :-D


27
Aug 10

DMon: Process monitoring with style

Have you ever wanted to run a lengthy process making sure that it will be restarted on failure? Did you need at some point to daemonize a “normal” program? Well, maybe you already knew about daemontools, runit, freedt, Supervisor, upstart or —recently— systemd. They already do a good job respawning processes, but there are three single things that neither of them are capable of doing:

  • Running a single command and exiting when it exits successfully.
  • Running commands interactively, without daemonizing nor detaching from the terminal.
  • Temporarily suspending execution when the system load goes over a configurable value, and resuming execution automatically as soon as the load drops below another configurable value.

If you ever needed at least one of those features, then DMon is probably what you want. If unsure, read the examples below — you might find some inspiration for use-cases!

The Story

Years ago I discovered Daniel J. Bernstein’s qmail, and with it came the rest of the “DJB-ware” software stack: djbdns, ucspi, daemontools… and their philosophy!)

Some weeks ago I coded vfand, a small “non-daemon” to control the speed of the fan in my Vaio laptop because it was overheating. I am lazy, so I deliberately left out daemonization and suggested launching it from init(8) — because I knew that DJB’s tools leave daemonization and logging to other tools which just do one thing well.

Days back I had to make a huge data copy in a mission-critical mail server, and used the mighty rsync tool because I wanted the copy to be interruptible so I could stop it when the system load was getting high and then resuming the data copy. I did that manually (Ctrl-Z, wait, fg, repeat), and I do not like performing automatable tasks. Fortunately I seldom do this kind of tasks.

Do you recognize the pattern? DMon is a subproduct of what I have been doing lately, applying the knowledge about daemontools I already had.

How does it work? — Modus operandi

In short it works àla daemontools without control sockets and without using script files for launching processes. All options are specified in the command line, as long as the commands to be run. Like this:

dmon [options] command [command-options] \
     [-- log-command [log-command-options]

As an example, consider the following command line:

dmon cron -f -- dlog /var/log/cron.log

This is what DMon wil do:

  1. Daemonize itself.
  2. Create a pipe(2), which will be used to connect the output of the given command to the input of the log-command.
  3. Spawn both the command and the log-command.
  4. Silently wait. If some child is terminated, it will be respawned.

That is pretty close to what the supervise program included in daemontools does, so it have already all the advantages of it, plus without needing stuff in the file system. Passing options to dmon will trigger some of the extra features provided:

  • Passing -n makes it run in the foreground. This is very useful in conjunction with -1: with tha latter the processes will be only respawned if their exit status is non-zero.
  • If you want to log messages from standard error, use -e and both standard output and standard error will be piped to the logging command.
  • For faulty programs which could get somewhat “locked” and sometimes take too much time to run, you may pass a maximum running time with -t. When the timeout is reached the program will be forcibly killed and then started again.
  • Finally, for pausing the program over a given value of system load, use -L. After pausing execution (by means of the SIGSTOP signal), it will be resumed when the system load falls below the value given with -l (by sending SIGCONT). The signals used are the standard ones used for this duty e.g. by the shell, so almost every well-behaved program will work without modifications.

The DMon package already includes a couple tools ready to be used as logging command: dlog will append lines to a log file, optionally adding a timestamp to them, and dsyslog will send lines to the system log. You can use any logging tool which works with daemontools, like multilog (part of it) or my own rotlog ;-)

DMon use-cases & Examples

Running rsync in a terminal (without detaching), pausing the copy when the system load is above 4.0, retrying until the copy succeeds:

dmon -n -1 -L 4.0 rsync -az /path/to/srcdir /path/to/destdir

Launching vfand as a daemon, logging errors to the local syslog, and saving the PID of the process (the second line terminates dmon, vfand and dsyslog in a single shot):

dmon -e -p /var/run/vfand.pid vfand -- dsyslog vfand
kill $(cat /var/run/vfand.pid)

Starting the MediaTomb UPnP server as a user mediatomb (i.e. at bootup), saving auto-rotated logs with rotlog running as user log:

dmon -e -u mediatomb -g mediatomb -U log -G log \
     mediatomb --interface eth0 --home /mnt/mediafiles \
     -- rotlog -c /var/log/mediatomb/

Final Words

It was fun for me to hack in DMon because C is a language I learnt to love, and using it from time to time is nice to not lose contact with it. Also, I had a clear idea of what I wanted to do for solving a particular problem, which is great for keeping focus.

Albeit DMon is already in its third release (namely version 0.3) and I have been using it since its first inceptions, it may contain bugs as any other piece of software. Do not hesitate to drop me a line with your complaints and suggestions — or even better: get yourself a clone of the Git repository and use its send-email awesomeness!

Have a lot of fun… :-D


09
Aug 10

Three reasons why I can live without Flash plugin

Ahh, Flash: the non-accessible, proprietary, widely used, hated and loved browser plugin. I have been using 64-bit GNU/Linux distributions for almost five years, with varying degrees of satisfaction regarding Flash content. In the beginning, there was no Flash at all, and that was good. Then came nspluginwrapper, which I decided not to use because I won’t install duplicated 32-bit libraries in my system. Finally, at some point Adobe released a 64-bit alpha release of the thing. It worked but sometimes it decided it was a good moment to crash. Lately Adobe ceased to distribute it, arguing it “had security flaws” and that “they are working in improved 64-bit support”. Whatever that wording could mean, the fact is that now it is easier than before to stay away from having the Flash plugin installed. My (personal) selection reasons is:

  • HTML5. Most video sites (that’s for what Flash is used, isn’t it?) have now some degree of HTML5 support, including the “big ones”: YouTube, DailyMotion, Vimeo… Just get yourself a modern browser and you’re ready to go.
  • Speed. Flash is slooow. In. Every. Platform. I. Tried. Even using the PlayStation 3, which has plenty of raw power, the browser is sluggish in sites with Flash content.
  • youtube-dl. This is a script which will happily download videos from some video sites, by the way including YouTube. This is the ultimate reason why one can happily live without Flash.

The nicest feature of youtube-dl is the --get-url flag. You can directly stream a video with e.g. mplayer using a small script like this one:

#! /bin/sh
exec mplayer "$(youtube-dl --get-url "$1")"

Nice, isn’t it? ;-)


27
Jul 10

vfand: A daemon to control fan speed in Vaio laptops

Today I got tired of getting frequent lock-ups in my laptop, a Vaio TZ11MN/N which has been serving me just fine the during the past three years. I decided to investigate a bit because the machine was quite hot, and after some digging I found that the fan speed was being kept below 45, by reading from /sys. For example:

cat /sys/devices/platform/sony-laptop/fanspeed
44

Then I noticed that writing to the file would also work, but the embedded controller would insist in lowering the speed, so I ran the following loop from the shell:

while sleep 5 ; do
   echo 200 > /sys/devices/platform/sony-laptop/fanspeed
done

That snip caused the fan to stay running at a higher speed, and the laptop temperature started to fall slowly. Then I tried fancontrol, without luck: the fans in my TZ11 cannot be controlled with it. Then I decided to write my own, and vfand was born.

Even when some temperature sensors are there (e.g. the one in the CPU die), I found no easy way of determining the overall temperature of the machine using entries from /sys. Next was to determine which driver is in charge of the fan entry under /sys, to check whether it can do something else. The fan entry is managed by the sonypi driver, which actually does support opening /dev/sonypi and getting the temperature using an ioctl called SONYPI_IOCGTEMP. It looked fine, so I implemented my little daemon in terms of ioctl on that device, so it should would with all Vaio laptops supported by the driver.

The speed control algorithm is quite simple at the moment, but it works fine for me:

  • When the temperature is less than a user-configurable value (35º C by default), the fan speed is set to the minimum possible value.
  • When the temperature is above a user-configurable value (55 ºC by default), the fan speed is set to the maximum possible value.
  • If the temperature is in between the configurable values, then a linear formula is used to calculate the speed. As the temperature raises, the fan speed will be raised, too (and vice versa).

The daemon is naïve, so it will log errors to the standard error stream, and it will not detach itself from the controlling terminal. An option is running it from /etc/rc.local until I add an init script which uses start-stop-daemon (or something else) to launch it.

Another option, which is a bit bizarre but will ensure that it is always running even if it does, is doing:

echo 'vf:2345:respawn:/usr/bin/vfand' >> /etc/inittab
telinit q

Last, but not least, I have already uploaded a simple, working package to our APT repository.

I hope this is useful for some other Vaio user out there ;-)


26
Jul 10

Escaping manual package installation woes: Enter our APT repository

Lately I have been packaging stuff as ready-to-use .deb packages. But providing just a bunch of links to them and forcing people to use arcane tools like dpkg -i to install software is not very user-friendly… and it is definitely not sysadmin-friendly either. Due to those reasons, we decided to roll our own APT repository. This means that from now on I will stop posting links here, and that you get a convenient way of installing packages em automatically getting updates.

For the moment there is not a lot of packages are in the APT repository, because some of the packages’ control files were not in a very good shape and I need to tweak them a bit before reprepro will happily agree to add them in the repository. The good news is that I am adding some ARM EABI packages ready to use with the GuruPlug.

Instructions for using the repository can be found at apt.igalia.com, as well as the repository PGP key (E438FFC5), which is signed with my own (E4C9123B).

Have a lot of fun… ;-)


16
Jul 10

Debugging Python unit tests

I have been doing quite some Python hacking lately, especially unit testing, and I have found some “funny” bugs in a piece of code. I wanted to do some step-by-step debugging, but I did not want to manually invoke the debugger with the same environment as the unit tests, because the preparation needed for test cases is not trivial.

Then I decided to re-read the Pdb documentation, and found a super-handy feature: the set_trace() function. I short, you can insert the following snippet in almost any piece of code:

import pdb
pdb.set_trace()

…and when the execution flow call set_trace(), the debugger will take over the terminal and display the familiar (Pdb) prompt, being the environment that of the scope where set_trace() was called.

This was today’s Python handy tip :D


28
Jun 10

Recipe: Convert FLAC files to MP3

This is another recipe-alike, self-reminder post. This one converts all FLAC files in a directory to MP3, which I do hardly now (because I have OGG-Vorbis support almost everywhere :D ), but is still useful for some hardware players. Also, note that this properly saves ID3 tags and song length information (it took me some time to find about xingmux, which is in gst-plugins-ugly):

for i in *.flac ; do
  gst-launch-0.10 filesrc location="${i}" \
    ! flacdec ! audioconvert ! lame vbr=4 birate=224 \
    ! xingmux ! id3mux ! filesink location="${i%.flac}.mp3"
done

Copy, paste, and you are done! ;)


21
Jun 10

And even more packages

Most of the time, people involved in the Free Software community what does with packages is using prebuilt packages, and a small amount of people are who actually prepare packages. For one reason or another, I end up building some Debian packages from time to time. Most of the time the motivations are:

  • Having some build-time option enabled (fine-tuning build options via USE-flags is one of the reasons why I love Gentoo :-D ).
  • A new version we want is out but there is no package in Debian stable, nor in backports. Or maybe it is some experimental application we want to use.
  • Add patches in packages which are not yet officially merged, either in Debian or in the upstream project.

In the spirit of giving something back to the community, and because they may be useful to other persons, I like sharing the result of my work, so here we go with a new batch of .deb packages (which most likely will work in Ubuntu as well):

What Distribution Packages
OpenERP client 6.0 alpha 20100617 lenny openerp-client_6.0-alpha20100617_all.deb
DSpam 3.9.0 lenny dspam_3.9.0-4_i386.deb
dspam-doc_3.9.0-4_all.deb
dspam-webfrontend_3.9.0-4_all.deb
libdspam7_3.9.0-4_i386.deb
libdspam7-drv-sqlite3_3.9.0-4_i386.deb
libdspam7-drv-pgsql_3.9.0-4_i386.deb
libdspam7-drv-mysql_3.9.0-4_i386.deb
libdspam7-dev_3.9.0-4_i386.deb
Nginx 0.8.41 lenny / squeeze nginx_0.8.41-0_amd64.deb
nginx_0.8.41-0_armel.deb
rotlog 0.2 lenny / squeeze rotlog_0.2-1_armel.deb

One note regarding the Nginx package: it is supercharged with the versions of the following third-party modules:

The ARM packages are the ones I am using in my GuruPlug, and were built in the plug itself, so I am quite sure they will work in almost any ARM Debian box which uses EABI, including the venerable SheevaPlug and NSLU2 devices.

Have a lot of fun… ;-)


31
May 10

Do a bus-trip with OpenAMQ

So you want to do some messaging using AMQP, you have a Debian system (or based on it), and you want to try out OpenAMQ… it’s your lucky day!

I have just built some .deb packages for the OpenAMQ, using some packaging support files I found, plus some patches I throwed in to bring it up to date. Just pick the package of version 1.2c4 for the distribution of your choice:

As always, I am just providing those packages here for your convenience. They work fine for me, but you are on your own using them.

By the way, you may also want to try other options like RabbitMQ (package rabbitmq and/or 0MQ (package zeromq-bin, I did not have luck with this one, though).

And now it is time to start using the just installed message queueing service :-D


19
May 10

Recipe: Convert FLAC files to OGG Vorbis

As with previous “recipe” posts, this one is for me to remember in the future how to convert all FLAC files in a directory to OGG-Vorbis easily. The main motivation between this is making some lighter files to drop them in a Nokia N900 (at last, I have a device that can play them!) and save some disk space.

The recipe uses GStreamer’s gst-launch command:

for i in *.flac ; do
  gst-launch-0.10 filesrc location="${i}" \
    ! flacdec ! audioconvert ! vorbisenc quality=0.5 \
    ! oggmux ! filesink location="${i%.flac}.ogg"
done

So, just copy-and-paste the recipe above as needed :-D