posix_mq 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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")