posix_mq 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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")
|