Skip to content

Instantly share code, notes, and snippets.

@peterc
Created April 23, 2017 21:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterc/496da508955b1438b4c83303d012f20c to your computer and use it in GitHub Desktop.
Save peterc/496da508955b1438b4c83303d012f20c to your computer and use it in GitHub Desktop.
A scrappy example of working with SysV message queues in macOS from Ruby using Fiddle.
# A scrappy example library to access the System V message queue
# functionality in macOS. Works on macOS Sierra with Ruby 2.4.
#
# For more info on sysv message queues:
# https://www.softprayog.in/programming/interprocess-communication-using-system-v-message-queues-in-linux
require 'fiddle'
class MsgQ
LIBC = Fiddle.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 = Fiddle::Pointer.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
q = MsgQ.new('/tmp', 'A')
q.send type: 2, msg: "test"
q.send type: 3, msg: "test"
q.send type: 4, msg: "test"
q.send "test"
while m = q.receive(5, 0, MsgQ::IPC_NOWAIT)
p m
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment