2021
August 05: ESP and solar panel Part 2; the results2020
December 26: ESP and solar panel Part 1; the setup August 22: ESP-8266 power issue with ME6206 regulator2019
October 18: How to use alarm syscall in Ruby2018
December 20: Decode Oregon Scientific sensors with RaspberryPi and Arduino2016
October 19: How I recovered a dead hard drive with a freezer September 28: Drawing a ground plane in Kicad June 27: Quick Ruby On Rail memo2015
December 18: Signal handling and Ruby December 14: EventMachine is good but... September 18: My custom ortholinear keyboard February 08: Quick Sinatra boilerplate2014
September 16: Wifi access point on a Raspberry Pi March 24: Linphone and G729 on Opensuse2013
November 11: Ext4 rescue tips November 05: Why this blog is'nt running Wordpress ?The other day I wanted to use the alarm(2) syscall in a ruby project.
This is an old unix syscall very useful to implement using signals. It's not for some kind of timeout, but rather trigger some code after a defined amount of time. With no need of a loop. This is basically an asynchronous timer provided by the linux kernel. So if it's in the kernel, why reimplementing it in userland ?
I couldn't find any references using the alarm syscall in ruby. Very few resources came up with these keywords. All solutions proposed on various forums are using sleep within a thread, like this :
trap "ALRM" do
puts "Alarm received!"
end
def alarm
Thread.new do
sleep 5
Process.kill "ALRM", $$
end
end
But this does not provide the same behavior ! Take this example :
alarm(5)
sleep(4)
alarm(5)
With the above thread implementation, the alarm will be triggered twice, once at 5 sec, and another one at 9 sec. With the real alarm(), the signal would be trigerred only once, at 9 seconds. See man alarm
for more details.
The solution
The syscall alarm(2) is part of the standard libc. There is way in ruby to direclty call some C function from dynamic libraries. Here's a good articles about it : https://aonemd.github.io/blog/making-system-calls-from-ruby
I did some test with Fiddle, unfortunately the documentation is not very abundant but after a bit of fiddling around with that lib, I succeeded to find a working setup.
A direct call to the syscall
function should work but very hardcore, and I could'nt find the syscall_number
for alarm() on my ARM system. You can find it here for x86_64 system though : https://github.com/torvalds/linux/blob/v3.13/arch/x86/syscalls/syscall_64.tbl
But we can call directly the alarm syscall :
require 'fiddle'
libc = Fiddle.dlopen('/lib/arm-linux-gnueabihf/libc.so.6')
alarm = Fiddle::Function.new(libc['alarm'], [Fiddle::TYPE_INT], Fiddle::TYPE_INT)
trap 'ALRM' do
puts "alarm received !"
end
alarm.call(2)
This solution is not ideal, as you need to locate the libc.6.so
file but it does the job. In that example I'm using Rasbian on a Raspberry pi, hence the armhf architecture.
You can locate yours with ldconfig -p | grep libc.so
.