Created
May 3, 2012 02:52
-
-
Save peterc/2582673 to your computer and use it in GitHub Desktop.
Sys V message queues in Ruby on OS X (take one)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Lightweight library to access the System V message queue functionality on Mac OS X (32 and 64 bit) | |
# Still quite scrappy and needs to be packaged up properly but.. it works! | |
require 'fiddle' | |
class MsgQ | |
LIBC = DL.dlopen('libc.dylib') | |
IPC_CREAT = 001000 | |
IPC_EXCL = 002000 | |
IPC_NOWAIT = 004000 | |
IPC_R = 000400 | |
IPC_W = 000200 | |
IPC_M = 010000 | |
SIZEOF_LONG = [0].pack('L_').size | |
def initialize(path, id) | |
@id = self.class.get(path, id) | |
end | |
def self.ftok(path, id) | |
id = id.class == String ? id.ord : id.to_i | |
Fiddle::Function.new(LIBC['ftok'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT], Fiddle::TYPE_INT).call(path, id) | |
end | |
def self.get(path, id, msgflag = IPC_CREAT | IPC_R | IPC_W | IPC_M ) | |
Fiddle::Function.new(LIBC['msgget'], [Fiddle::TYPE_INT, Fiddle::TYPE_INT], Fiddle::TYPE_INT) | |
.call(ftok(path, id), msgflag) | |
end | |
def send(msg = {}, flags = 0) | |
msg = { msg: msg } if msg.is_a? String | |
msg = { type: 1, msg: '' }.merge(msg) | |
r = Fiddle::Function.new(LIBC['msgsnd'], [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_INT], Fiddle::TYPE_INT) | |
.call(@id, [msg[:type]].pack('Q') + msg[:msg], msg[:msg].length + 1, flags) | |
r == -1 ? false : r | |
end | |
def receive(size, type, flags) | |
ptr = DL::CPtr.malloc(size + SIZEOF_LONG) | |
r = Fiddle::Function.new(LIBC['msgrcv'], [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_INT, Fiddle::TYPE_INT], Fiddle::TYPE_INT) | |
.call(@id, ptr.to_i, size, type, flags) | |
msg_type = ptr[0, SIZEOF_LONG].unpack('Q')[0] | |
msg = (ptr + SIZEOF_LONG).to_s | |
ptr.free | |
r == -1 ? false : { type: msg_type, msg: msg } | |
end | |
end | |
### | |
if __FILE__ == $0 | |
queue = MsgQ.new('/tmp', 'A') | |
queue.send type: 2, msg: "test" | |
queue.send type: 3, msg: "test" | |
queue.send type: 4, msg: "test" | |
queue.send "test" | |
while m = queue.receive(5, 0, MsgQ::IPC_NOWAIT) | |
p m | |
end | |
end |
A corrected version to work on ruby 2.6.3
https://gist.github.com/unplugandplay/a66068239f621790c87e0e017b064a92
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Reasonably straightforward. I had to do quite a bit of "spelunking" to work out various DL trivialities and issues though. I'm still semi-stuck on one - how to get access to "errno"! However, it seems FFI.errno will do the trick, but introduces another dependency. Man, DL documentation is SO hard to come by.. you end up having to read weird Japanese forums.
I've seen the POSIX mq stuff but.. it's entirely a no-go on OS X. Unless things have changed recently, last I read was OS X has zero support for it and only does SysV (and even then, it's not that good..)
I hope to write up this spelunking for an article on Ruby Inside. I did learn a bit of stuff and as DL/Fiddle documentation is so short.. :-)