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/GNUmakefile CHANGED
@@ -2,7 +2,7 @@
2
2
  all::
3
3
  RUBY = ruby
4
4
  RAKE = rake
5
- GIT_URL = git://git.bogomips.org/ruby_posix_mq.git
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-man
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
- @echo "ChangeLog from $(GIT_URL) ($(log_range))" > $@+
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
- # using rdoc 2.5.x+
80
- doc: .document NEWS ChangeLog
60
+ doc: .document NEWS ChangeLog man html
81
61
  for i in $(man1_rdoc); do > $$i; done
82
- rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
62
+ $(RM) -r doc
63
+ wrongdoc all
83
64
  install -m644 COPYING doc/COPYING
84
- install -m644 $(shell grep '^[A-Z]' .document) doc/
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
- $(RAKE) -s release_changes > $@+
80
+ wrongdoc release_changes > $@+
113
81
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
114
82
  $(release_notes):
115
- GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
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
- .PHONY: .FORCE-GIT-VERSION-FILE doc manifest man test
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
@@ -0,0 +1,6 @@
1
+ === posix_mq 0.6.0 - Rubinius support /
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
+
data/NEWS CHANGED
@@ -1,9 +1,15 @@
1
- === 0.5.1 / 2010-05-09 08:10 UTC
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 / 2010-01-02 11:01 UTC
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 = 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
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
@@ -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")
@@ -10,8 +10,8 @@
10
10
  #endif
11
11
  #include <ruby.h>
12
12
 
13
- #ifndef RB_GC_GUARD
14
- # define RB_GC_GUARD(v) (*(volatile VALUE *)&(v))
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
- #endif
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 RSTRUCT_PTR
62
- # define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
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
- /* hope it's there..., TODO: a better version that works in rbx */
131
- struct timeval rb_time_interval(VALUE);
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 timeval tv, now;
179
+ struct timespec ts, now;
136
180
 
137
181
  if (NIL_P(t))
138
182
  return NULL;
139
183
 
140
- tv = rb_time_interval(t); /* aggregate return :( */
141
- gettimeofday(&now, NULL);
142
- dest->tv_sec = now.tv_sec + tv.tv_sec;
143
- dest->tv_nsec = (now.tv_usec + tv.tv_usec) * 1000;
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 = saved_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
- /* converts the POSIX_MQ::Attr astruct into a struct mq_attr attr */
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
- VALUE *ptr;
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
- if (CLASS_OF(astruct) != cAttr) {
255
- RB_GC_GUARD(astruct) = rb_inspect(astruct);
256
- rb_raise(rb_eArgError, "not a POSIX_MQ::Attr: %s",
257
- RSTRING_PTR(astruct));
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
- ptr = RSTRUCT_PTR(astruct);
307
+ tmp = rb_funcall(astruct, id_maxmsg, 0);
308
+ if (all || !NIL_P(tmp))
309
+ attr->mq_maxmsg = NUM2LONG(tmp);
261
310
 
262
- attr->mq_flags = NUM2LONG(ptr[0]);
311
+ tmp = rb_funcall(astruct, id_msgsize, 0);
312
+ if (all || !NIL_P(tmp))
313
+ attr->mq_msgsize = NUM2LONG(tmp);
263
314
 
264
- if (all || !NIL_P(ptr[1]))
265
- attr->mq_maxmsg = NUM2LONG(ptr[1]);
266
- if (all || !NIL_P(ptr[2]))
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
- RB_GC_GUARD(oflags) = oflags;
363
+ oflags = rb_inspect(oflags);
316
364
  rb_raise(rb_eArgError,
317
365
  "symbol must be :r, :w, or :rw: %s",
318
- RSTRING_PTR(oflags));
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
- attr_from_struct(&x.attr, attr, 1);
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
- RB_GC_GUARD(attr) = rb_inspect(attr);
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
- rb_sys_fail("mq_open");
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
- astruct = rb_struct_alloc_noinit(cAttr);
618
- ptr = RSTRUCT_PTR(astruct);
619
- ptr[0] = LONG2NUM(mq->attr.mq_flags);
620
- ptr[1] = LONG2NUM(mq->attr.mq_maxmsg);
621
- ptr[2] = LONG2NUM(mq->attr.mq_msgsize);
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
- attr_from_struct(&newattr, astruct, 0);
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 (mq_close(mq->des) < 0)
665
- rb_sys_fail("mq_close");
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
- if (mq_notify(mq->des, &not) < 0)
767
- rb_sys_fail("mq_notify");
828
+ my_mq_notify(mq->des, &not);
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
- if (mq_notify(mq->des, notification) < 0)
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"));