posix_mq 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +1 -0
- data/.gitignore +1 -0
- data/.manifest +2 -1
- data/.wrongdoc.yml +7 -0
- data/ChangeLog +501 -71
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +30 -44
- data/LATEST +6 -0
- data/NEWS +14 -7
- data/README +2 -0
- data/Rakefile +1 -103
- data/ext/posix_mq/extconf.rb +1 -1
- data/ext/posix_mq/posix_mq.c +145 -79
- data/lib/posix_mq.rb +2 -2
- data/posix_mq.gemspec +11 -22
- data/test/test_posix_mq.rb +58 -13
- metadata +38 -9
- data/local.mk.sample +0 -70
data/GNUmakefile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
all::
|
3
3
|
RUBY = ruby
|
4
4
|
RAKE = rake
|
5
|
-
|
5
|
+
RSYNC = rsync
|
6
6
|
|
7
7
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
8
8
|
@./GIT-VERSION-GEN
|
@@ -39,10 +39,10 @@ clean:
|
|
39
39
|
-$(MAKE) -C ext/posix_mq clean
|
40
40
|
$(RM) $(setup_rb_files) ext/posix_mq/Makefile
|
41
41
|
|
42
|
-
man:
|
43
|
-
$(MAKE) -C Documentation install
|
42
|
+
man html:
|
43
|
+
$(MAKE) -C Documentation install-$@
|
44
44
|
|
45
|
-
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog
|
45
|
+
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
|
46
46
|
manifest: $(pkg_extra) man
|
47
47
|
$(RM) .manifest
|
48
48
|
$(MAKE) .manifest
|
@@ -54,48 +54,16 @@ manifest: $(pkg_extra) man
|
|
54
54
|
cmp $@+ $@ || mv $@+ $@
|
55
55
|
$(RM) $@+
|
56
56
|
|
57
|
-
NEWS: GIT-VERSION-FILE
|
58
|
-
$(RAKE) -s news_rdoc > $@+
|
59
|
-
mv $@+ $@
|
60
|
-
|
61
|
-
SINCE = 0.4.0
|
62
|
-
ChangeLog: LOG_VERSION = \
|
63
|
-
$(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
|
64
|
-
echo $(GIT_VERSION) || git describe)
|
65
|
-
ifneq ($(SINCE),)
|
66
|
-
ChangeLog: log_range = v$(SINCE)..$(LOG_VERSION)
|
67
|
-
endif
|
68
57
|
ChangeLog: GIT-VERSION-FILE
|
69
|
-
|
70
|
-
@echo >> $@+
|
71
|
-
git log $(log_range) | sed -e 's/^/ /' >> $@+
|
72
|
-
mv $@+ $@
|
73
|
-
|
74
|
-
news_atom := http://bogomips.org/ruby_posix_mq/NEWS.atom.xml
|
75
|
-
cgit_atom := http://git.bogomips.org/cgit/ruby_posix_mq.git/atom/?h=master
|
76
|
-
atom = <link rel="alternate" title="Atom feed" href="$(1)" \
|
77
|
-
type="application/atom+xml"/>
|
58
|
+
wrongdoc prepare
|
78
59
|
|
79
|
-
|
80
|
-
doc: .document NEWS ChangeLog
|
60
|
+
doc: .document NEWS ChangeLog man html
|
81
61
|
for i in $(man1_rdoc); do > $$i; done
|
82
|
-
|
62
|
+
$(RM) -r doc
|
63
|
+
wrongdoc all
|
83
64
|
install -m644 COPYING doc/COPYING
|
84
|
-
install -m644 $(shell grep '^[A-Z]' .document)
|
85
|
-
$(MAKE) -C Documentation install-html install-man
|
65
|
+
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
86
66
|
install -m644 $(man1_paths) doc/
|
87
|
-
cd doc && for i in $(base_bins); do \
|
88
|
-
html=$$(echo $$i | sed 's/\.rb/_rb/')_1.html; \
|
89
|
-
sed -e '/"documentation">/r man1/'$$i'.1.html' \
|
90
|
-
< $$html > tmp && mv tmp $$html; done
|
91
|
-
$(RUBY) -i -p -e \
|
92
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
|
93
|
-
doc/ChangeLog.html
|
94
|
-
$(RUBY) -i -p -e \
|
95
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
|
96
|
-
doc/NEWS.html doc/README.html
|
97
|
-
$(RAKE) -s news_atom > doc/NEWS.atom.xml
|
98
|
-
cd doc && ln README.html tmp && mv tmp index.html
|
99
67
|
$(RM) $(man1_rdoc)
|
100
68
|
|
101
69
|
ifneq ($(VERSION),)
|
@@ -109,10 +77,10 @@ release_changes := release_changes-$(VERSION)
|
|
109
77
|
release-notes: $(release_notes)
|
110
78
|
release-changes: $(release_changes)
|
111
79
|
$(release_changes):
|
112
|
-
|
80
|
+
wrongdoc release_changes > $@+
|
113
81
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
114
82
|
$(release_notes):
|
115
|
-
|
83
|
+
wrongdoc release_notes > $@+
|
116
84
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
117
85
|
|
118
86
|
# ensures we're actually on the tagged $(VERSION), only used for release
|
@@ -177,4 +145,22 @@ test: test-unit
|
|
177
145
|
test-unit: build
|
178
146
|
$(RUBY) -I lib:ext/posix_mq test/test_posix_mq.rb
|
179
147
|
|
180
|
-
|
148
|
+
# publishes docs to http://bogomips.org/ruby_posix_mq/
|
149
|
+
publish_doc:
|
150
|
+
-git set-file-times
|
151
|
+
$(RM) -r doc
|
152
|
+
$(MAKE) doc
|
153
|
+
find doc/images -type f | \
|
154
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:03' doc/rdoc.css
|
155
|
+
$(MAKE) doc_gz
|
156
|
+
$(RSYNC) -av doc/ bogomips.org:/srv/bogomips/ruby_posix_mq/
|
157
|
+
git ls-files | xargs touch
|
158
|
+
|
159
|
+
# Create gzip variants of the same timestamp as the original so nginx
|
160
|
+
# "gzip_static on" can serve the gzipped versions directly.
|
161
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
162
|
+
doc_gz:
|
163
|
+
for i in $(docs); do \
|
164
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
165
|
+
|
166
|
+
.PHONY: .FORCE-GIT-VERSION-FILE doc manifest man test html
|
data/LATEST
ADDED
data/NEWS
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
=== 0.
|
1
|
+
=== posix_mq 0.6.0 - Rubinius support / 2010-12-25 08:28 UTC
|
2
|
+
|
3
|
+
Rubinius 1.2 as well as Ruby 1.9. Ruby 1.8 works except it will
|
4
|
+
block the entire interpreter for blocking operations. Spurious
|
5
|
+
errors during GC for POSIX_MQ#to_io users are now avoided.
|
6
|
+
|
7
|
+
=== posix_mq 0.5.1 / 2010-05-09 08:10 UTC
|
2
8
|
|
3
9
|
Fix POSIX_MQ#notify(&block) usage, this regression was
|
4
10
|
introduced in 0.4.0 and our tests for it were broken, as well.
|
5
11
|
|
6
|
-
=== 0.5.0 / 2010-05-05 02:54 UTC
|
12
|
+
=== posix_mq 0.5.0 / 2010-05-05 02:54 UTC
|
7
13
|
|
8
14
|
Uncommonly raised exceptions due to programmer error are now
|
9
15
|
raised more safely with respect to the MRI garbage collector.
|
@@ -15,7 +21,7 @@
|
|
15
21
|
|
16
22
|
Minor cleanups and documentation now uses RDoc 2.5.x
|
17
23
|
|
18
|
-
=== 0.4.0 / 2010-03-13 09:44 UTC
|
24
|
+
=== posix_mq 0.4.0 / 2010-03-13 09:44 UTC
|
19
25
|
|
20
26
|
Small bugfixes and small API changes to avoid potential
|
21
27
|
issues/misuse are the focus of this release.
|
@@ -38,7 +44,7 @@
|
|
38
44
|
* remove non-portable #warning CPP directive
|
39
45
|
* ensure POSIX_MQ#name is clobber-proof
|
40
46
|
|
41
|
-
=== 0.3.1 / 2010-02-13 12:05 UTC
|
47
|
+
=== posix_mq 0.3.1 / 2010-02-13 12:05 UTC
|
42
48
|
|
43
49
|
This fixes a misuse of the Ruby API leading to memory leaks in
|
44
50
|
cases where message queues are continually opened and closed
|
@@ -49,7 +55,7 @@
|
|
49
55
|
multi-thread/multi-process-safe in every way imaginable and also
|
50
56
|
capable of non-blocking operation.
|
51
57
|
|
52
|
-
=== 0.3.0 / 2010-01-09 23:11 UTC
|
58
|
+
=== posix_mq 0.3.0 / 2010-01-09 23:11 UTC
|
53
59
|
|
54
60
|
This release adds a few new API methods, fixes MRI 1.8.6
|
55
61
|
support. We should now have full feature parity with
|
@@ -71,7 +77,7 @@
|
|
71
77
|
Linux, FreeBSD and possibly any other platforms where POSIX
|
72
78
|
message queues are implemented with a file descriptor.
|
73
79
|
|
74
|
-
=== 0.2.0 / 2010-01-03 05:52 UTC
|
80
|
+
=== posix_mq 0.2.0 / 2010-01-03 05:52 UTC
|
75
81
|
|
76
82
|
This release fixes notification (un)registration and should be
|
77
83
|
fully-supported on modern FreeBSD (7.2+) releases.
|
@@ -81,7 +87,8 @@
|
|
81
87
|
functionality. Under FreeBSD, using IO.select on POSIX_MQ
|
82
88
|
objects is now possible as it has always been under Linux.
|
83
89
|
|
84
|
-
=== 0.1.0
|
90
|
+
=== posix_mq 0.1.0 - initial release
|
91
|
+
/ 2010-01-02 11:01 UTC
|
85
92
|
|
86
93
|
initial
|
87
94
|
|
data/README
CHANGED
@@ -26,6 +26,8 @@ network-aware message queue implementations.
|
|
26
26
|
* Thread-safe blocking operations under Ruby 1.9, releases GVL
|
27
27
|
before blocking operations.
|
28
28
|
|
29
|
+
* Works under Ruby 1.8, Ruby 1.9 and Rubinius 1.2
|
30
|
+
|
29
31
|
* Documented library API
|
30
32
|
|
31
33
|
* Includes a generic "posix-mq-rb" command-line tool with manpage.
|
data/Rakefile
CHANGED
@@ -1,108 +1,6 @@
|
|
1
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
2
|
cgit_url = "http://git.bogomips.org/cgit/ruby_posix_mq.git"
|
27
|
-
git_url =
|
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
|
3
|
+
git_url = 'git://git.bogomips.org/ruby_posix_mq.git'
|
106
4
|
|
107
5
|
desc "read news article from STDIN and post to rubyforge"
|
108
6
|
task :publish_news do
|
data/ext/posix_mq/extconf.rb
CHANGED
@@ -6,8 +6,8 @@ have_header("mqueue.h") or abort "mqueue.h header missing"
|
|
6
6
|
have_func("__mq_oshandle")
|
7
7
|
have_header("pthread.h")
|
8
8
|
have_func("rb_str_set_len")
|
9
|
-
have_func("rb_struct_alloc_noinit")
|
10
9
|
have_func('rb_thread_blocking_region')
|
10
|
+
have_library("m")
|
11
11
|
have_library("rt")
|
12
12
|
have_library("pthread")
|
13
13
|
dir_config("posix_mq")
|
data/ext/posix_mq/posix_mq.c
CHANGED
@@ -10,8 +10,8 @@
|
|
10
10
|
#endif
|
11
11
|
#include <ruby.h>
|
12
12
|
|
13
|
-
#ifndef
|
14
|
-
# define
|
13
|
+
#ifndef NUM2TIMET
|
14
|
+
# define NUM2TIMET NUM2INT
|
15
15
|
#endif
|
16
16
|
|
17
17
|
#include <time.h>
|
@@ -21,6 +21,8 @@
|
|
21
21
|
#include <errno.h>
|
22
22
|
#include <assert.h>
|
23
23
|
#include <unistd.h>
|
24
|
+
#include <float.h>
|
25
|
+
#include <math.h>
|
24
26
|
|
25
27
|
#if defined(__linux__)
|
26
28
|
# define MQD_TO_FD(mqd) (int)(mqd)
|
@@ -29,11 +31,8 @@
|
|
29
31
|
#else
|
30
32
|
# define MQ_IO_MARK(mq) ((void)(0))
|
31
33
|
# define MQ_IO_SET(mq,val) ((void)(0))
|
32
|
-
#
|
33
|
-
|
34
|
-
#ifdef MQD_TO_FD
|
35
|
-
# define MQ_IO_MARK(mq) rb_gc_mark((mq)->io)
|
36
|
-
# define MQ_IO_SET(mq,val) do { (mq)->io = (val); } while (0)
|
34
|
+
# define MQ_IO_CLOSE(mq) ((void)(0))
|
35
|
+
# define MQ_IO_NILP(mq) ((void)(1))
|
37
36
|
#endif
|
38
37
|
|
39
38
|
struct posix_mq {
|
@@ -46,8 +45,26 @@ struct posix_mq {
|
|
46
45
|
#endif
|
47
46
|
};
|
48
47
|
|
48
|
+
#ifdef MQD_TO_FD
|
49
|
+
# define MQ_IO_MARK(mq) rb_gc_mark((mq)->io)
|
50
|
+
# define MQ_IO_SET(mq,val) do { (mq)->io = (val); } while (0)
|
51
|
+
# define MQ_IO_NIL_P(mq) NIL_P((mq)->io)
|
52
|
+
static int MQ_IO_CLOSE(struct posix_mq *mq)
|
53
|
+
{
|
54
|
+
if (NIL_P(mq->io))
|
55
|
+
return 0;
|
56
|
+
|
57
|
+
/* not safe during GC */
|
58
|
+
rb_io_close(mq->io);
|
59
|
+
mq->io = Qnil;
|
60
|
+
|
61
|
+
return 1;
|
62
|
+
}
|
63
|
+
#endif
|
64
|
+
|
49
65
|
static VALUE cPOSIX_MQ, cAttr;
|
50
|
-
static ID id_new, id_kill, id_fileno;
|
66
|
+
static ID id_new, id_kill, id_fileno, id_mul, id_divmod;
|
67
|
+
static ID id_flags, id_maxmsg, id_msgsize, id_curmsgs;
|
51
68
|
static ID sym_r, sym_w, sym_rw;
|
52
69
|
static const mqd_t MQD_INVALID = (mqd_t)-1;
|
53
70
|
|
@@ -58,34 +75,22 @@ static const mqd_t MQD_INVALID = (mqd_t)-1;
|
|
58
75
|
#ifndef RSTRING_LEN
|
59
76
|
# define RSTRING_LEN(s) (RSTRING(s)->len)
|
60
77
|
#endif
|
61
|
-
#ifndef
|
62
|
-
# define
|
63
|
-
#endif
|
64
|
-
#ifndef RSTRUCT_LEN
|
65
|
-
# define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
|
78
|
+
#ifndef RFLOAT_VALUE
|
79
|
+
# define RFLOAT_VALUE(f) (RFLOAT(f)->value)
|
66
80
|
#endif
|
67
81
|
|
68
82
|
#ifndef HAVE_RB_STR_SET_LEN
|
69
|
-
# ifdef RUBINIUS
|
70
|
-
# define rb_str_set_len(str,len) rb_str_resize(str,len)
|
71
|
-
# else /* 1.8.6 optimized version */
|
72
83
|
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
84
|
+
# ifdef RUBINIUS
|
85
|
+
# error upgrade Rubinius, rb_str_set_len should be available
|
86
|
+
# endif
|
73
87
|
static void rb_18_str_set_len(VALUE str, long len)
|
74
88
|
{
|
75
89
|
RSTRING(str)->len = len;
|
76
90
|
RSTRING(str)->ptr[len] = '\0';
|
77
91
|
}
|
78
|
-
# define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
79
|
-
# endif /* ! RUBINIUS */
|
80
92
|
#endif /* !defined(HAVE_RB_STR_SET_LEN) */
|
81
93
|
|
82
|
-
#ifndef HAVE_RB_STRUCT_ALLOC_NOINIT
|
83
|
-
static VALUE rb_struct_alloc_noinit(VALUE class)
|
84
|
-
{
|
85
|
-
return rb_funcall(class, id_new, 0, 0);
|
86
|
-
}
|
87
|
-
#endif /* !defined(HAVE_RB_STRUCT_ALLOC_NOINIT) */
|
88
|
-
|
89
94
|
/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
|
90
95
|
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
91
96
|
# include <rubysig.h>
|
@@ -127,24 +132,63 @@ struct rw_args {
|
|
127
132
|
struct timespec *timeout;
|
128
133
|
};
|
129
134
|
|
130
|
-
|
131
|
-
|
135
|
+
static void num2timespec(struct timespec *ts, VALUE t)
|
136
|
+
{
|
137
|
+
switch (TYPE(t)) {
|
138
|
+
case T_FIXNUM:
|
139
|
+
case T_BIGNUM:
|
140
|
+
ts->tv_sec = NUM2TIMET(t);
|
141
|
+
ts->tv_nsec = 0;
|
142
|
+
break;
|
143
|
+
case T_FLOAT: {
|
144
|
+
double f, d;
|
145
|
+
double val = RFLOAT_VALUE(t);
|
146
|
+
|
147
|
+
d = modf(val, &f);
|
148
|
+
if (d >= 0) {
|
149
|
+
ts->tv_nsec = (long)(d * 1e9 + 0.5);
|
150
|
+
} else {
|
151
|
+
ts->tv_nsec = (long)(-d * 1e9 + 0.5);
|
152
|
+
if (ts->tv_nsec > 0) {
|
153
|
+
ts->tv_nsec = 1000000000 - ts->tv_nsec;
|
154
|
+
f -= 1;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
ts->tv_sec = (time_t)f;
|
158
|
+
if (f != ts->tv_sec)
|
159
|
+
rb_raise(rb_eRangeError, "%f out of range", val);
|
160
|
+
ts->tv_sec = (time_t)f;
|
161
|
+
}
|
162
|
+
break;
|
163
|
+
default: {
|
164
|
+
VALUE f;
|
165
|
+
VALUE ary = rb_funcall(t, id_divmod, 1, INT2FIX(1));
|
166
|
+
|
167
|
+
Check_Type(ary, T_ARRAY);
|
168
|
+
|
169
|
+
ts->tv_sec = NUM2TIMET(rb_ary_entry(ary, 0));
|
170
|
+
f = rb_ary_entry(ary, 1);
|
171
|
+
f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
|
172
|
+
ts->tv_nsec = NUM2LONG(f);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
132
176
|
|
133
177
|
static struct timespec *convert_timeout(struct timespec *dest, VALUE t)
|
134
178
|
{
|
135
|
-
struct
|
179
|
+
struct timespec ts, now;
|
136
180
|
|
137
181
|
if (NIL_P(t))
|
138
182
|
return NULL;
|
139
183
|
|
140
|
-
|
141
|
-
|
142
|
-
dest->tv_sec = now.tv_sec +
|
143
|
-
dest->tv_nsec =
|
184
|
+
num2timespec(&ts, t);
|
185
|
+
clock_gettime(CLOCK_REALTIME, &now);
|
186
|
+
dest->tv_sec = now.tv_sec + ts.tv_sec;
|
187
|
+
dest->tv_nsec = now.tv_nsec + ts.tv_nsec;
|
144
188
|
|
145
189
|
if (dest->tv_nsec > 1000000000) {
|
146
190
|
dest->tv_nsec -= 1000000000;
|
147
|
-
dest->tv_sec
|
191
|
+
++dest->tv_sec;
|
148
192
|
}
|
149
193
|
|
150
194
|
return dest;
|
@@ -205,12 +249,10 @@ static void _free(void *ptr)
|
|
205
249
|
{
|
206
250
|
struct posix_mq *mq = ptr;
|
207
251
|
|
208
|
-
if (mq->des != MQD_INVALID) {
|
252
|
+
if (mq->des != MQD_INVALID && MQ_IO_NIL_P(mq)) {
|
209
253
|
/* we ignore errors when gc-ing */
|
210
|
-
int saved_errno = errno;
|
211
|
-
|
212
254
|
mq_close(mq->des);
|
213
|
-
errno =
|
255
|
+
errno = 0;
|
214
256
|
}
|
215
257
|
xfree(ptr);
|
216
258
|
}
|
@@ -246,27 +288,33 @@ static struct posix_mq *get(VALUE self, int need_valid)
|
|
246
288
|
return mq;
|
247
289
|
}
|
248
290
|
|
249
|
-
|
250
|
-
static void attr_from_struct(struct mq_attr *attr, VALUE astruct, int all)
|
291
|
+
static void check_struct_type(VALUE astruct)
|
251
292
|
{
|
252
|
-
|
293
|
+
if (CLASS_OF(astruct) == cAttr)
|
294
|
+
return;
|
295
|
+
astruct = rb_inspect(astruct);
|
296
|
+
rb_raise(rb_eTypeError, "not a POSIX_MQ::Attr: %s",
|
297
|
+
StringValuePtr(astruct));
|
298
|
+
}
|
253
299
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
300
|
+
static void rstruct2mqattr(struct mq_attr *attr, VALUE astruct, int all)
|
301
|
+
{
|
302
|
+
VALUE tmp;
|
303
|
+
|
304
|
+
check_struct_type(astruct);
|
305
|
+
attr->mq_flags = NUM2LONG(rb_funcall(astruct, id_flags, 0));
|
259
306
|
|
260
|
-
|
307
|
+
tmp = rb_funcall(astruct, id_maxmsg, 0);
|
308
|
+
if (all || !NIL_P(tmp))
|
309
|
+
attr->mq_maxmsg = NUM2LONG(tmp);
|
261
310
|
|
262
|
-
|
311
|
+
tmp = rb_funcall(astruct, id_msgsize, 0);
|
312
|
+
if (all || !NIL_P(tmp))
|
313
|
+
attr->mq_msgsize = NUM2LONG(tmp);
|
263
314
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
attr->mq_msgsize = NUM2LONG(ptr[2]);
|
268
|
-
if (!NIL_P(ptr[3]))
|
269
|
-
attr->mq_curmsgs = NUM2LONG(ptr[3]);
|
315
|
+
tmp = rb_funcall(astruct, id_curmsgs, 0);
|
316
|
+
if (!NIL_P(tmp))
|
317
|
+
attr->mq_curmsgs = NUM2LONG(tmp);
|
270
318
|
}
|
271
319
|
|
272
320
|
/*
|
@@ -312,10 +360,10 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
312
360
|
else if (oflags == sym_rw)
|
313
361
|
x.oflags = O_CREAT|O_RDWR;
|
314
362
|
else {
|
315
|
-
|
363
|
+
oflags = rb_inspect(oflags);
|
316
364
|
rb_raise(rb_eArgError,
|
317
365
|
"symbol must be :r, :w, or :rw: %s",
|
318
|
-
|
366
|
+
StringValuePtr(oflags));
|
319
367
|
}
|
320
368
|
break;
|
321
369
|
case T_BIGNUM:
|
@@ -347,7 +395,7 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
347
395
|
switch (TYPE(attr)) {
|
348
396
|
case T_STRUCT:
|
349
397
|
x.argc = 4;
|
350
|
-
|
398
|
+
rstruct2mqattr(&x.attr, attr, 1);
|
351
399
|
|
352
400
|
/* principle of least surprise */
|
353
401
|
if (x.attr.mq_flags & O_NONBLOCK)
|
@@ -356,14 +404,18 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
356
404
|
case T_NIL:
|
357
405
|
break;
|
358
406
|
default:
|
359
|
-
|
360
|
-
rb_raise(rb_eArgError, "attr must be a POSIX_MQ::Attr: %s",
|
361
|
-
RSTRING_PTR(attr));
|
407
|
+
check_struct_type(attr);
|
362
408
|
}
|
363
409
|
|
364
410
|
mq->des = (mqd_t)xopen(&x);
|
365
|
-
if (mq->des == MQD_INVALID)
|
366
|
-
|
411
|
+
if (mq->des == MQD_INVALID) {
|
412
|
+
if (errno == ENOMEM || errno == EMFILE || errno == ENFILE) {
|
413
|
+
rb_gc();
|
414
|
+
mq->des = (mqd_t)xopen(&x);
|
415
|
+
}
|
416
|
+
if (mq->des == MQD_INVALID)
|
417
|
+
rb_sys_fail("mq_open");
|
418
|
+
}
|
367
419
|
|
368
420
|
mq->name = rb_str_dup(name);
|
369
421
|
if (x.oflags & O_NONBLOCK)
|
@@ -609,19 +661,15 @@ static VALUE getattr(VALUE self)
|
|
609
661
|
{
|
610
662
|
struct posix_mq *mq = get(self, 1);
|
611
663
|
VALUE astruct;
|
612
|
-
VALUE *ptr;
|
613
664
|
|
614
665
|
if (mq_getattr(mq->des, &mq->attr) < 0)
|
615
666
|
rb_sys_fail("mq_getattr");
|
616
667
|
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
ptr[3] = LONG2NUM(mq->attr.mq_curmsgs);
|
623
|
-
|
624
|
-
return astruct;
|
668
|
+
return rb_funcall(cAttr, id_new, 4,
|
669
|
+
LONG2NUM(mq->attr.mq_flags),
|
670
|
+
LONG2NUM(mq->attr.mq_maxmsg),
|
671
|
+
LONG2NUM(mq->attr.mq_msgsize),
|
672
|
+
LONG2NUM(mq->attr.mq_curmsgs));
|
625
673
|
}
|
626
674
|
|
627
675
|
/*
|
@@ -639,7 +687,7 @@ static VALUE setattr(VALUE self, VALUE astruct)
|
|
639
687
|
struct posix_mq *mq = get(self, 1);
|
640
688
|
struct mq_attr newattr;
|
641
689
|
|
642
|
-
|
690
|
+
rstruct2mqattr(&newattr, astruct, 0);
|
643
691
|
|
644
692
|
if (mq_setattr(mq->des, &newattr, NULL) < 0)
|
645
693
|
rb_sys_fail("mq_setattr");
|
@@ -661,11 +709,11 @@ static VALUE _close(VALUE self)
|
|
661
709
|
{
|
662
710
|
struct posix_mq *mq = get(self, 1);
|
663
711
|
|
664
|
-
if (
|
665
|
-
|
666
|
-
|
712
|
+
if (! MQ_IO_CLOSE(mq)) {
|
713
|
+
if (mq_close(mq->des) == -1)
|
714
|
+
rb_sys_fail("mq_close");
|
715
|
+
}
|
667
716
|
mq->des = MQD_INVALID;
|
668
|
-
MQ_IO_SET(mq, Qnil);
|
669
717
|
|
670
718
|
return Qnil;
|
671
719
|
}
|
@@ -736,6 +784,20 @@ static void thread_notify_fd(union sigval sv)
|
|
736
784
|
while ((write(fd, "", 1) < 0) && (errno == EINTR || errno == EAGAIN));
|
737
785
|
}
|
738
786
|
|
787
|
+
static void my_mq_notify(mqd_t des, struct sigevent *not)
|
788
|
+
{
|
789
|
+
mqd_t rv = mq_notify(des, not);
|
790
|
+
|
791
|
+
if (rv == MQD_INVALID) {
|
792
|
+
if (errno == ENOMEM) {
|
793
|
+
rb_gc();
|
794
|
+
rv = mq_notify(des, not);
|
795
|
+
}
|
796
|
+
if (rv == MQD_INVALID)
|
797
|
+
rb_sys_fail("mq_notify");
|
798
|
+
}
|
799
|
+
}
|
800
|
+
|
739
801
|
/* :nodoc: */
|
740
802
|
static VALUE setnotify_exec(VALUE self, VALUE io, VALUE thr)
|
741
803
|
{
|
@@ -763,8 +825,7 @@ static VALUE setnotify_exec(VALUE self, VALUE io, VALUE thr)
|
|
763
825
|
rb_funcall(mq->thread, id_kill, 0, 0);
|
764
826
|
mq->thread = thr;
|
765
827
|
|
766
|
-
|
767
|
-
rb_sys_fail("mq_notify");
|
828
|
+
my_mq_notify(mq->des, ¬);
|
768
829
|
|
769
830
|
return thr;
|
770
831
|
}
|
@@ -834,8 +895,7 @@ static VALUE setnotify(VALUE self, VALUE arg)
|
|
834
895
|
rb_raise(rb_eArgError, "must be a signal or nil");
|
835
896
|
}
|
836
897
|
|
837
|
-
|
838
|
-
rb_sys_fail("mq_notify");
|
898
|
+
my_mq_notify(mq->des, notification);
|
839
899
|
|
840
900
|
return rv;
|
841
901
|
}
|
@@ -931,6 +991,12 @@ void Init_posix_mq_ext(void)
|
|
931
991
|
id_new = rb_intern("new");
|
932
992
|
id_kill = rb_intern("kill");
|
933
993
|
id_fileno = rb_intern("fileno");
|
994
|
+
id_mul = rb_intern("*");
|
995
|
+
id_divmod = rb_intern("divmod");
|
996
|
+
id_flags = rb_intern("flags");
|
997
|
+
id_maxmsg = rb_intern("maxmsg");
|
998
|
+
id_msgsize = rb_intern("msgsize");
|
999
|
+
id_curmsgs = rb_intern("curmsgs");
|
934
1000
|
sym_r = ID2SYM(rb_intern("r"));
|
935
1001
|
sym_w = ID2SYM(rb_intern("w"));
|
936
1002
|
sym_rw = ID2SYM(rb_intern("rw"));
|