posix_mq 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +7 -0
- data/.gitignore +14 -0
- data/.manifest +24 -0
- data/COPYING +165 -0
- data/ChangeLog +7 -0
- data/Documentation/.gitignore +5 -0
- data/Documentation/GNUmakefile +30 -0
- data/Documentation/posix-mq.rb.1.txt +153 -0
- data/GIT-VERSION-FILE +1 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +179 -0
- data/LICENSE +16 -0
- data/NEWS +4 -0
- data/README +70 -0
- data/Rakefile +159 -0
- data/bin/posix-mq.rb +138 -0
- data/ext/posix_mq/extconf.rb +9 -0
- data/ext/posix_mq/posix_mq.c +813 -0
- data/lib/posix_mq.rb +34 -0
- data/local.mk.sample +70 -0
- data/man/man1/posix-mq.rb.1 +187 -0
- data/posix_mq.gemspec +39 -0
- data/setup.rb +1586 -0
- data/test/test_posix_mq.rb +225 -0
- metadata +88 -0
data/README
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
= posix_mq - POSIX Message Queues for Ruby
|
2
|
+
|
3
|
+
POSIX message queues allow local processes to exchange data in the form
|
4
|
+
of messages. This API is distinct from that provided by System V
|
5
|
+
message queues, but provides similar functionality.
|
6
|
+
|
7
|
+
POSIX message queues may be implemented in the kernel for fast,
|
8
|
+
low-latency communication between processes on the same machine.
|
9
|
+
POSIX message queues are not intended to replace userspace,
|
10
|
+
network-aware message queue implementations.
|
11
|
+
|
12
|
+
== Features
|
13
|
+
|
14
|
+
* Supports message notifications via signals.
|
15
|
+
|
16
|
+
* Supports portable non-blocking operation. Under Linux 2.6.6+ only,
|
17
|
+
POSIX_MQ objects may even be used with event notification mechanisms
|
18
|
+
such as IO.select.
|
19
|
+
|
20
|
+
* Optional timeouts may be applied to send and receive operations.
|
21
|
+
|
22
|
+
* Thread-safe under Ruby 1.9, releases GVL before blocking operations.
|
23
|
+
|
24
|
+
* Documented library API
|
25
|
+
|
26
|
+
* Includes a generic "posix-mq.rb" command-line tool with manpage.
|
27
|
+
|
28
|
+
== Install
|
29
|
+
|
30
|
+
Operating system support (or library emulation) for POSIX message queues
|
31
|
+
is required. Most modern GNU/Linux distributions support this
|
32
|
+
out-of-the-box.
|
33
|
+
|
34
|
+
If you're using a packaged Ruby distribution, make sure you have a C
|
35
|
+
compiler and the matching Ruby development libraries and headers.
|
36
|
+
|
37
|
+
If you plan on using the command-line client, a tarball installation
|
38
|
+
starts up faster and is recommended. Just grab the tarball from:
|
39
|
+
|
40
|
+
http://bogomips.org/ruby_posix_mq/files/
|
41
|
+
Unpack it, and run "ruby setup.rb"
|
42
|
+
|
43
|
+
Otherwise, via RubyGems: gem install posix_mq
|
44
|
+
|
45
|
+
== Development
|
46
|
+
|
47
|
+
You can get the latest source via git from the following locations:
|
48
|
+
|
49
|
+
git://git.bogomips.org/ruby_posix_mq.git
|
50
|
+
git://repo.or.cz/ruby_posix_mq.git (mirror)
|
51
|
+
|
52
|
+
You may browse the code from the web and download the latest snapshot
|
53
|
+
tarballs here:
|
54
|
+
|
55
|
+
* http://git.bogomips.org/cgit/ruby_posix_mq.git (cgit)
|
56
|
+
* http://repo.or.cz/w/ruby_posix_mq.git (gitweb)
|
57
|
+
|
58
|
+
Inline patches (from "git format-patch") to the mailing list are
|
59
|
+
preferred because they allow code review and comments in the reply to
|
60
|
+
the patch.
|
61
|
+
|
62
|
+
We will adhere to mostly the same conventions for patch submissions as
|
63
|
+
git itself. See the Documentation/SubmittingPatches document
|
64
|
+
distributed with git on on patch submission guidelines to follow. Just
|
65
|
+
don't email the git mailing list or maintainer with posix_mq patches.
|
66
|
+
|
67
|
+
== Contact
|
68
|
+
|
69
|
+
All feedback (bug reports, user/development discussion, patches, pull
|
70
|
+
requests) go to the mailing list: mailto:ruby.posix.mq@librelist.com
|
data/Rakefile
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
|
3
|
+
# most tasks are in the GNUmakefile which offers better parallelism
|
4
|
+
|
5
|
+
def tags
|
6
|
+
timefmt = '%Y-%m-%dT%H:%M:%SZ'
|
7
|
+
@tags ||= `git tag -l`.split(/\n/).map do |tag|
|
8
|
+
if %r{\Av[\d\.]+\z} =~ tag
|
9
|
+
header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
|
10
|
+
header = header.split(/\n/)
|
11
|
+
tagger = header.grep(/\Atagger /).first
|
12
|
+
body ||= "initial"
|
13
|
+
{
|
14
|
+
:time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
|
15
|
+
:tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
|
16
|
+
:tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
|
17
|
+
:id => `git rev-parse refs/tags/#{tag}`.chomp!,
|
18
|
+
:tag => tag,
|
19
|
+
:subject => subject,
|
20
|
+
:body => body,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end.compact.sort { |a,b| b[:time] <=> a[:time] }
|
24
|
+
end
|
25
|
+
|
26
|
+
cgit_url = "http://git.bogomips.org/cgit/ruby_posix_mq.git"
|
27
|
+
git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/ruby_posix_mq.git'
|
28
|
+
web_url = "http://bogomips.org/ruby_posix_mq/"
|
29
|
+
|
30
|
+
desc 'prints news as an Atom feed'
|
31
|
+
task :news_atom do
|
32
|
+
require 'nokogiri'
|
33
|
+
new_tags = tags[0,10]
|
34
|
+
puts(Nokogiri::XML::Builder.new do
|
35
|
+
feed :xmlns => "http://www.w3.org/2005/Atom" do
|
36
|
+
id! "#{web_url}NEWS.atom.xml"
|
37
|
+
title "Ruby posix_mq news"
|
38
|
+
subtitle "POSIX Message Queues for Ruby"
|
39
|
+
link! :rel => "alternate", :type => "text/html",
|
40
|
+
:href => "#{web_url}NEWS.html"
|
41
|
+
updated(new_tags.empty? ? "1970-01-01T00:00:00Z" : new_tags.first[:time])
|
42
|
+
new_tags.each do |tag|
|
43
|
+
entry do
|
44
|
+
title tag[:subject]
|
45
|
+
updated tag[:time]
|
46
|
+
published tag[:time]
|
47
|
+
author {
|
48
|
+
name tag[:tagger_name]
|
49
|
+
email tag[:tagger_email]
|
50
|
+
}
|
51
|
+
url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
|
52
|
+
link! :rel => "alternate", :type => "text/html", :href =>url
|
53
|
+
id! url
|
54
|
+
message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
|
55
|
+
content({:type =>:text}, message_only)
|
56
|
+
content(:type =>:xhtml) { pre tag[:body] }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end.to_xml)
|
61
|
+
end
|
62
|
+
|
63
|
+
desc 'prints RDoc-formatted news'
|
64
|
+
task :news_rdoc do
|
65
|
+
tags.each do |tag|
|
66
|
+
time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
|
67
|
+
puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
|
68
|
+
puts ""
|
69
|
+
|
70
|
+
body = tag[:body]
|
71
|
+
puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
|
72
|
+
puts ""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "print release changelog for Rubyforge"
|
77
|
+
task :release_changes do
|
78
|
+
version = ENV['VERSION'] or abort "VERSION= needed"
|
79
|
+
version = "v#{version}"
|
80
|
+
vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
|
81
|
+
prev = vtags[vtags.index(version) - 1]
|
82
|
+
if prev
|
83
|
+
system('git', 'diff', '--stat', prev, version) or abort $?
|
84
|
+
puts ""
|
85
|
+
system('git', 'log', "#{prev}..#{version}") or abort $?
|
86
|
+
else
|
87
|
+
system('git', 'log', version) or abort $?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
desc "print release notes for Rubyforge"
|
92
|
+
task :release_notes do
|
93
|
+
require 'rubygems'
|
94
|
+
|
95
|
+
spec = Gem::Specification.load('posix_mq.gemspec')
|
96
|
+
puts spec.description.strip
|
97
|
+
puts ""
|
98
|
+
puts "* #{spec.homepage}"
|
99
|
+
puts "* #{spec.email}"
|
100
|
+
puts "* #{git_url}"
|
101
|
+
|
102
|
+
_, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
|
103
|
+
print "\nChanges:\n\n"
|
104
|
+
puts body
|
105
|
+
end
|
106
|
+
|
107
|
+
desc "read news article from STDIN and post to rubyforge"
|
108
|
+
task :publish_news do
|
109
|
+
require 'rubyforge'
|
110
|
+
IO.select([STDIN], nil, nil, 1) or abort "E: news must be read from stdin"
|
111
|
+
msg = STDIN.readlines
|
112
|
+
subject = msg.shift
|
113
|
+
blank = msg.shift
|
114
|
+
blank == "\n" or abort "no newline after subject!"
|
115
|
+
subject.strip!
|
116
|
+
body = msg.join("").strip!
|
117
|
+
|
118
|
+
rf = RubyForge.new.configure
|
119
|
+
rf.login
|
120
|
+
rf.post_news('qrp', subject, body)
|
121
|
+
end
|
122
|
+
|
123
|
+
desc "post to RAA"
|
124
|
+
task :raa_update do
|
125
|
+
require 'rubygems'
|
126
|
+
require 'net/http'
|
127
|
+
require 'net/netrc'
|
128
|
+
rc = Net::Netrc.locate('ruby_posix_mq-raa') or abort "~/.netrc not found"
|
129
|
+
password = rc.password
|
130
|
+
|
131
|
+
s = Gem::Specification.load('posix_mq.gemspec')
|
132
|
+
desc = [ s.description.strip ]
|
133
|
+
desc << ""
|
134
|
+
desc << "* #{s.email}"
|
135
|
+
desc << "* #{git_url}"
|
136
|
+
desc << "* #{cgit_url}"
|
137
|
+
desc = desc.join("\n")
|
138
|
+
uri = URI.parse('http://raa.ruby-lang.org/regist.rhtml')
|
139
|
+
form = {
|
140
|
+
:name => s.name,
|
141
|
+
:short_description => s.summary,
|
142
|
+
:version => s.version.to_s,
|
143
|
+
:status => 'experimental',
|
144
|
+
:owner => s.authors.first,
|
145
|
+
:email => s.email,
|
146
|
+
:category_major => 'Library',
|
147
|
+
:category_minor => 'System',
|
148
|
+
:url => s.homepage,
|
149
|
+
:download => 'http://rubyforge.org/frs/?group_id=5626',
|
150
|
+
:license => 'LGPLv3',
|
151
|
+
:description_style => 'Plain',
|
152
|
+
:description => desc,
|
153
|
+
:pass => password,
|
154
|
+
:submit => 'Update',
|
155
|
+
}
|
156
|
+
res = Net::HTTP.post_form(uri, form)
|
157
|
+
p res
|
158
|
+
puts res.body
|
159
|
+
end
|
data/bin/posix-mq.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
Encoding.default_external = Encoding::BINARY if defined?(Encoding)
|
4
|
+
$stderr.sync = $stdout.sync = true
|
5
|
+
|
6
|
+
require 'posix_mq'
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
commands = %w(create attr send receive wait unlink)
|
10
|
+
usage = "Usage: MQUEUE=/name #{File.basename($0)} COMMAND " \
|
11
|
+
"[options] [<arguments>]\n" \
|
12
|
+
"COMMAND may be one of: #{commands.join(', ')}"
|
13
|
+
|
14
|
+
mqueue = ENV["MQUEUE"] or abort usage
|
15
|
+
command = ARGV.shift or abort usage
|
16
|
+
commands.include?(command) or abort usage
|
17
|
+
|
18
|
+
priority = nil
|
19
|
+
timeout = nil
|
20
|
+
mode = 0666
|
21
|
+
oflags = IO::RDONLY
|
22
|
+
mq_attr = nil
|
23
|
+
nonblock = false
|
24
|
+
command = command.to_sym
|
25
|
+
|
26
|
+
ARGV.options do |x|
|
27
|
+
x.banner = usage.split(/\n/).first.gsub(/COMMAND/, command.to_s)
|
28
|
+
x.separator ''
|
29
|
+
|
30
|
+
case command
|
31
|
+
when :create
|
32
|
+
oflags |= IO::CREAT
|
33
|
+
x.on('-x', '--exclusive', "exclusive create") {
|
34
|
+
oflags |= IO::EXCL
|
35
|
+
}
|
36
|
+
x.on('-m', '--mode=MODE', "octal file mode") { |i|
|
37
|
+
mode = i.to_i(8)
|
38
|
+
}
|
39
|
+
x.on('-c', '--maxmsg=COUNT', Integer, "maximum number of messages") { |i|
|
40
|
+
mq_attr ||= POSIX_MQ::Attr.new
|
41
|
+
mq_attr.maxmsg = i
|
42
|
+
}
|
43
|
+
x.on('-s', '--msgsize=BYTES', Integer, "maximum size of message") { |i|
|
44
|
+
mq_attr ||= POSIX_MQ::Attr.new
|
45
|
+
mq_attr.msgsize = i
|
46
|
+
}
|
47
|
+
when :wait
|
48
|
+
x.on('-t', '--timeout=SECONDS', Float, "timeout in seconds") { |f|
|
49
|
+
timeout = f
|
50
|
+
}
|
51
|
+
when :send, :receive
|
52
|
+
conflict = "timeout and nonblock are exclusive"
|
53
|
+
x.on('-t', '--timeout=SECONDS', Float, "timeout in seconds") { |f|
|
54
|
+
abort conflict if nonblock
|
55
|
+
timeout = f
|
56
|
+
}
|
57
|
+
x.on('-n', '--nonblock', "nonblocking operation") {
|
58
|
+
abort conflict if timeout
|
59
|
+
nonblock = true
|
60
|
+
oflags |= IO::NONBLOCK
|
61
|
+
}
|
62
|
+
if command == :send
|
63
|
+
oflags = IO::WRONLY
|
64
|
+
x.on('-p', '--priority=PRIO', Integer, "priority of message") { |i|
|
65
|
+
priority = i
|
66
|
+
}
|
67
|
+
else
|
68
|
+
x.on('-p', '--priority', "output priority of message to stderr") {
|
69
|
+
priority = $stderr
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
x.on('-q', "quiet warnings and errors") { $stderr.reopen("/dev/null", "w") }
|
74
|
+
x.on('-h', '--help', 'Show this help message.') { puts x; exit }
|
75
|
+
x.parse!
|
76
|
+
end
|
77
|
+
|
78
|
+
trap(:INT) { exit 130 }
|
79
|
+
|
80
|
+
unless command == :send || ARGV.empty?
|
81
|
+
abort "#{command} accepts no arguments"
|
82
|
+
end
|
83
|
+
|
84
|
+
begin
|
85
|
+
if command == :create && mq_attr
|
86
|
+
mq_attr.flags = mq_attr.curmsgs = 0
|
87
|
+
mq_attr.msgsize && ! mq_attr.maxmsg and
|
88
|
+
abort "--maxmsg must be set with --msgsize"
|
89
|
+
mq_attr.maxmsg && ! mq_attr.msgsize and
|
90
|
+
abort "--msgsize must be set with --maxmsg"
|
91
|
+
elsif command == :unlink
|
92
|
+
POSIX_MQ.unlink(mqueue)
|
93
|
+
exit
|
94
|
+
end
|
95
|
+
|
96
|
+
mq = POSIX_MQ.open(mqueue, oflags, mode, mq_attr)
|
97
|
+
case command
|
98
|
+
when :create
|
99
|
+
exit
|
100
|
+
when :receive
|
101
|
+
buf, prio = mq.receive("", timeout)
|
102
|
+
$stderr.syswrite("priority=#{prio}\n") if priority
|
103
|
+
$stdout.syswrite(buf)
|
104
|
+
when :send
|
105
|
+
ARGV << $stdin.read if ARGV.empty?
|
106
|
+
ARGV.each { |msg| mq.send(msg, priority, timeout) }
|
107
|
+
when :attr
|
108
|
+
mq_attr = mq.attr
|
109
|
+
$stdout.syswrite(
|
110
|
+
"flags=#{mq_attr.flags}\n" \
|
111
|
+
"maxmsg=#{mq_attr.maxmsg}\n" \
|
112
|
+
"msgsize=#{mq_attr.msgsize}\n" \
|
113
|
+
"curmsgs=#{mq_attr.curmsgs}\n")
|
114
|
+
when :wait
|
115
|
+
trap(:USR1) { exit }
|
116
|
+
|
117
|
+
# we wouldn't get a notification if there were already messages
|
118
|
+
exit if mq.attr.curmsgs > 0
|
119
|
+
mq.notify = :USR1
|
120
|
+
exit if mq.attr.curmsgs > 0 # avoid race condition
|
121
|
+
|
122
|
+
timeout.nil? ? sleep : sleep(timeout)
|
123
|
+
exit 2 # timed out
|
124
|
+
end
|
125
|
+
rescue Errno::EEXIST
|
126
|
+
abort "Queue exists"
|
127
|
+
rescue Errno::ENOENT
|
128
|
+
abort "Queue does not exist"
|
129
|
+
rescue Errno::EMSGSIZE
|
130
|
+
abort "Message too long"
|
131
|
+
rescue Errno::EAGAIN
|
132
|
+
abort(command == :send ? "Queue full" : "No messages available")
|
133
|
+
rescue Errno::ETIMEDOUT
|
134
|
+
warn "Operation timed out"
|
135
|
+
exit 2
|
136
|
+
rescue => e
|
137
|
+
abort e.message
|
138
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
have_header("mqueue.h") or abort "mqueue.h header missing"
|
4
|
+
have_func("rb_str_set_len")
|
5
|
+
have_func("rb_struct_alloc_noinit")
|
6
|
+
have_func('rb_thread_blocking_region')
|
7
|
+
have_library("rt")
|
8
|
+
dir_config("posix_mq")
|
9
|
+
create_makefile("posix_mq_ext")
|