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/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")