sendfile 1.0.0 → 1.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.
@@ -43,6 +43,7 @@
43
43
  #include <unistd.h>
44
44
  #include <fcntl.h>
45
45
  #include "config.h"
46
+ static VALUE sym_wait_writable;
46
47
 
47
48
  #ifndef HAVE_RB_THREAD_BLOCKING_REGION
48
49
  /*
@@ -185,7 +186,7 @@ static off_t sendfile_full(struct sendfile_args *args)
185
186
  return all - args->count;
186
187
  }
187
188
 
188
- static off_t sendfile_nonblock(struct sendfile_args *args)
189
+ static VALUE sendfile_nonblock(struct sendfile_args *args, int try)
189
190
  {
190
191
  ssize_t rv;
191
192
  off_t before = args->count;
@@ -201,12 +202,18 @@ static off_t sendfile_nonblock(struct sendfile_args *args)
201
202
 
202
203
  rv = (ssize_t)rb_thread_blocking_region(nogvl_sendfile, args,
203
204
  RUBY_UBF_IO, NULL);
204
- if (rv < 0)
205
+ if (rv < 0) {
206
+ if (try && errno == EAGAIN)
207
+ return sym_wait_writable;
205
208
  rb_sys_fail("sendfile");
206
- if (args->eof)
209
+ }
210
+ if (args->eof) {
211
+ if (try)
212
+ return Qnil;
207
213
  rb_eof_error();
214
+ }
208
215
 
209
- return before - args->count;
216
+ return OFFT2NUM(before - args->count);
210
217
  }
211
218
 
212
219
  static void convert_args(int argc, VALUE *argv, VALUE self,
@@ -287,7 +294,40 @@ static VALUE rb_io_sendfile_nonblock(int argc, VALUE *argv, VALUE self)
287
294
 
288
295
  convert_args(argc, argv, self, &args);
289
296
 
290
- return OFFT2NUM(sendfile_nonblock(&args));
297
+ return sendfile_nonblock(&args, 0);
298
+ }
299
+
300
+ /* call-seq:
301
+ * writeIO.trysendfile(readIO, offset=0, count=nil) => integer, nil, or
302
+ * :wait_writable
303
+ *
304
+ * Transfers count bytes starting at offset from readIO directly to writeIO
305
+ * without copying (i.e. invoking the kernel to do it for you).
306
+ *
307
+ * Unlike IO#sendfile, this will set the O_NONBLOCK flag on writeIO
308
+ * before calling sendfile(2) and will return :wait_writable instead
309
+ * of blocking. This method is intended for use with non-blocking
310
+ * event frameworks, including those that rely on Fibers.
311
+ *
312
+ * If offset is omitted, transfer starts at the beginning of the file.
313
+ *
314
+ * If count is omitted, the full length of the file will be sent.
315
+ *
316
+ * Returns the number of bytes sent on success, nil on EOF, and
317
+ * :wait_writable on EAGAIN. Will throw system error exception on error.
318
+ * (check man sendfile(2) on your platform for
319
+ * information on what errors could result and how to handle them)
320
+ *
321
+ * This method is a faster alternative to sendfile_nonblock as it does
322
+ * not raise exceptions on common EAGAIN errors.
323
+ */
324
+ static VALUE rb_io_trysendfile(int argc, VALUE *argv, VALUE self)
325
+ {
326
+ struct sendfile_args args;
327
+
328
+ convert_args(argc, argv, self, &args);
329
+
330
+ return sendfile_nonblock(&args, 1);
291
331
  }
292
332
 
293
333
  /* Interface to the UNIX sendfile(2) system call. Should work on FreeBSD,
@@ -295,8 +335,10 @@ static VALUE rb_io_sendfile_nonblock(int argc, VALUE *argv, VALUE self)
295
335
  */
296
336
  void Init_sendfile(void)
297
337
  {
338
+ sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
298
339
  rb_define_method(rb_cIO, "sendfile", rb_io_sendfile, -1);
299
340
  rb_define_method(rb_cIO, "sendfile_nonblock",
300
341
  rb_io_sendfile_nonblock, -1);
342
+ rb_define_method(rb_cIO, "trysendfile", rb_io_trysendfile, -1);
301
343
  }
302
344
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  spec = Gem::Specification.new do |gs|
4
4
  gs.name = 'sendfile'
5
- gs.version = '1.0.0'
5
+ gs.version = '1.1.0'
6
6
  gs.summary = 'Ruby interface to sendfile(2) system call'
7
7
  gs.description = <<-EOF
8
8
  Allows Ruby programs to access sendfile(2) functionality on
@@ -185,6 +185,26 @@ class TestSendfile < Test::Unit::TestCase
185
185
  assert_equal nr_read, nr_sent
186
186
  end
187
187
 
188
+ def test_trysendfile
189
+ c, s = UNIXSocket.pair
190
+ nr_sent = 0
191
+ assert_nothing_raised do
192
+ case rv = c.trysendfile(@small)
193
+ when :wait_writable
194
+ break
195
+ when Integer
196
+ nr_sent += rv
197
+ else
198
+ raise "Unexpected return: #{rv.inspect}"
199
+ end while true
200
+ end
201
+ assert nr_sent > 0, "nr_sent: #{nr_sent} <= 0"
202
+ c.close
203
+ nr_read = s.read.size
204
+ s.close
205
+ assert_equal nr_read, nr_sent
206
+ end
207
+
188
208
  def test_tempfile
189
209
  tmp = Tempfile.new ''
190
210
  tmp.write @small_data
@@ -223,5 +243,12 @@ class TestSendfile < Test::Unit::TestCase
223
243
  end
224
244
  s.close
225
245
  end
246
+
247
+ def test_trysendfile_eof
248
+ s = TCPSocket.new @host, @port
249
+ off = @small_data.size
250
+ assert_nil s.trysendfile(@small, off, 1)
251
+ s.close
252
+ end
226
253
  end # class TestSendfile
227
254
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sendfile
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 0
10
- version: 1.0.0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Toby DiPasquale
@@ -15,7 +15,7 @@ autorequire: sendfile
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-26 00:00:00 -04:00
18
+ date: 2011-03-05 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies: []
21
21