posix_mq 0.5.1 → 0.6.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 +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"));
|