cool.io 1.9.0 → 1.9.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e56b06dac89092ba3fb69d7705788b4aecb51a205075b47afa6b8ff946f8bfa6
4
- data.tar.gz: d9ff9ac907b8eb86d3158d893acdcc0f64c58985ae2ccfeeafbcc9c2a5e366a4
3
+ metadata.gz: 3da0843b8a62fd01aab297ce31f885a5856b4326bef2fb3c90d363f9576fe9a3
4
+ data.tar.gz: d073dd104500ccc2c1b62411c8f02c083df004353f9d2798ccf8ae41166effbd
5
5
  SHA512:
6
- metadata.gz: b9d3c85e07f9f439c86be0572d4c455a429fbb2b8fd5b1cbdb87cd0fdca1c629060515074751eecb92357b365edf05c8b0cc79ce63ca4d6188e4eeca903cf95e
7
- data.tar.gz: 942c188b705d59f6aa0c9d028d87b17722f9cba55c317cfb1be8f7548562c68e1467c8ec5664297cbb575fd1f6997875311d1a35d76efb772c4f50c87c20aa94
6
+ metadata.gz: b3f2fab2151abdbd3e0762aa04675cab8b4d196990227bf5d068f12360a62c87e669480f50e70b47b289a9c0f29deeddb28836590422faafe5d0a5ecaf6173fb
7
+ data.tar.gz: 233ea14784f4390b6b1f1b8fb131d5b1d20d14d0b78f9f1fd3b39f89bd25d34be505267d23d1b5647be2febcd5216e33a459c0e135ee49737334a06a0626bb47
@@ -5,9 +5,6 @@ on: [push, pull_request]
5
5
  permissions:
6
6
  contents: read
7
7
 
8
- env:
9
- CONSOLE_OUTPUT: XTerm
10
-
11
8
  jobs:
12
9
  test:
13
10
  name: ${{matrix.ruby}} on ${{matrix.os}}
@@ -20,35 +17,27 @@ jobs:
20
17
  os:
21
18
  - ubuntu
22
19
  - macos
23
- - windows
24
20
 
25
21
  ruby:
26
- - "3.0"
27
- - "3.1"
28
22
  - "3.2"
29
23
  - "3.3"
30
- - "head"
24
+ - "3.4"
25
+ - "4.0"
31
26
 
32
27
  experimental: [false]
33
28
 
34
- # include:
35
- # - os: ubuntu
36
- # ruby: truffleruby
37
- # experimental: true
38
- # - os: ubuntu
39
- # ruby: jruby
40
- # experimental: true
41
- # - os: ubuntu
42
- # ruby: head
43
- # experimental: true
29
+ include:
30
+ - os: ubuntu
31
+ ruby: head
32
+ experimental: true
44
33
 
45
34
  steps:
46
- - uses: actions/checkout@v3
35
+ - uses: actions/checkout@v6
47
36
  - uses: ruby/setup-ruby@v1
48
37
  with:
49
38
  ruby-version: ${{matrix.ruby}}
50
39
  bundler-cache: true
51
40
 
52
41
  - name: Run tests
53
- timeout-minutes: 2
42
+ timeout-minutes: 10
54
43
  run: bundle exec rake
@@ -0,0 +1,44 @@
1
+ name: Memcheck
2
+
3
+ on: [push, pull_request]
4
+
5
+ permissions:
6
+ contents: read
7
+
8
+ jobs:
9
+ test:
10
+ name: ${{matrix.ruby}} on ${{matrix.os}}
11
+ runs-on: ${{matrix.os}}-latest
12
+ continue-on-error: ${{matrix.experimental}}
13
+
14
+ strategy:
15
+ matrix:
16
+ os:
17
+ - ubuntu
18
+
19
+ ruby:
20
+ - "3.2"
21
+ - "3.3"
22
+ - "3.4"
23
+ - "4.0"
24
+
25
+ experimental: [false]
26
+
27
+ include:
28
+ - os: ubuntu
29
+ ruby: head
30
+ experimental: true
31
+
32
+ steps:
33
+ - uses: actions/checkout@v6
34
+ - uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{matrix.ruby}}
37
+ bundler-cache: true
38
+ - name: Install Valgrind
39
+ run: |
40
+ sudo apt-get update
41
+ sudo apt-get install -y valgrind
42
+ - name: Run tests
43
+ timeout-minutes: 10
44
+ run: bundle exec rake spec:valgrind
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  require 'rake/extensiontask'
24
24
 
25
- spec = eval(File.read("cool.io.gemspec"))
25
+ spec = Gem::Specification.load("cool.io.gemspec")
26
26
 
27
27
  def configure_cross_compilation(ext)
28
28
  unless RUBY_PLATFORM =~ /mswin|mingw/
@@ -48,24 +48,11 @@ namespace :build do
48
48
  end
49
49
  end
50
50
 
51
- # adapted from http://flavoriffic.blogspot.com/2009/06/easily-valgrind-gdb-your-ruby-c.html
52
- def specs_command
53
- require "find"
54
- files = []
55
- Find.find("spec") do |f|
56
- files << f if File.basename(f) =~ /.*spec.*\.rb$/
57
- end
58
- cmdline = "#{RUBY} -I.:lib:ext:spec \
59
- -e '%w[#{files.join(' ')}].each { |f| require f }'"
60
- end
61
-
62
- namespace :spec do
63
- desc "run specs with valgrind"
64
- task :valgrind => :compile do
65
- system "valgrind --num-callers=15 \
66
- --partial-loads-ok=yes --undef-value-errors=no \
67
- --tool=memcheck --leak-check=yes --track-fds=yes \
68
- --show-reachable=yes #{specs_command}"
51
+ if RUBY_PLATFORM.include?('linux')
52
+ require 'ruby_memcheck'
53
+ require 'ruby_memcheck/rspec/rake_task'
54
+ namespace :spec do
55
+ RubyMemcheck::RSpec::RakeTask.new(valgrind: :compile)
69
56
  end
70
57
  end
71
58
 
data/cool.io.gemspec CHANGED
@@ -1,6 +1,4 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "cool.io/version"
1
+ require_relative "lib/cool.io/version"
4
2
 
5
3
  Gem::Specification.new do |s|
6
4
  s.name = "cool.io"
data/ext/cool.io/buffer.c CHANGED
@@ -28,17 +28,22 @@
28
28
 
29
29
  /* Default number of bytes in each node's buffer. Should be >= MTU */
30
30
  #define DEFAULT_NODE_SIZE 16384
31
- static unsigned default_node_size = DEFAULT_NODE_SIZE;
31
+ static size_t default_node_size = DEFAULT_NODE_SIZE;
32
32
 
33
+ /*
34
+ * Byte counts are kept in size_t so the accounting cannot wrap while the
35
+ * buffer itself still holds the data. node_size is capped at MAX_BUFFER_SIZE,
36
+ * but size grows with whatever the buffer is asked to hold.
37
+ */
33
38
  struct buffer {
34
- unsigned size, node_size;
39
+ size_t size, node_size;
35
40
  struct buffer_node *head, *tail;
36
41
  struct buffer_node *pool_head, *pool_tail;
37
42
 
38
43
  };
39
44
 
40
45
  struct buffer_node {
41
- unsigned start, end;
46
+ size_t start, end;
42
47
  struct buffer_node *next;
43
48
  unsigned char data[0];
44
49
  };
@@ -47,8 +52,8 @@ static VALUE mCoolio = Qnil;
47
52
  static VALUE cCoolio_Buffer = Qnil;
48
53
 
49
54
  static VALUE Coolio_Buffer_allocate(VALUE klass);
50
- static void Coolio_Buffer_mark(struct buffer *);
51
- static void Coolio_Buffer_free(struct buffer *);
55
+ static void Coolio_Buffer_mark(void *);
56
+ static void Coolio_Buffer_free(void *);
52
57
 
53
58
  static VALUE Coolio_Buffer_default_node_size(VALUE klass);
54
59
  static VALUE Coolio_Buffer_set_default_node_size(VALUE klass, VALUE size);
@@ -64,17 +69,17 @@ static VALUE Coolio_Buffer_to_str(VALUE self);
64
69
  static VALUE Coolio_Buffer_read_from(VALUE self, VALUE io);
65
70
  static VALUE Coolio_Buffer_write_to(VALUE self, VALUE io);
66
71
 
67
- static struct buffer *buffer_new(void);
72
+ static struct buffer *buffer_init(struct buffer *);
68
73
  static void buffer_clear(struct buffer * buf);
69
74
  static void buffer_free(struct buffer * buf);
70
75
  static void buffer_free_pool(struct buffer * buf);
71
- static void buffer_prepend(struct buffer * buf, char *str, unsigned len);
72
- static void buffer_append(struct buffer * buf, char *str, unsigned len);
73
- static void buffer_read(struct buffer * buf, char *str, unsigned len);
76
+ static void buffer_prepend(struct buffer * buf, char *str, size_t len);
77
+ static void buffer_append(struct buffer * buf, char *str, size_t len);
78
+ static void buffer_read(struct buffer * buf, char *str, size_t len);
74
79
  static int buffer_read_frame(struct buffer * buf, VALUE str, char frame_mark);
75
- static void buffer_copy(struct buffer * buf, char *str, unsigned len);
76
- static int buffer_read_from(struct buffer * buf, int fd);
77
- static int buffer_write_to(struct buffer * buf, int fd);
80
+ static void buffer_copy(struct buffer * buf, char *str, size_t len);
81
+ static ssize_t buffer_read_from(struct buffer * buf, int fd);
82
+ static ssize_t buffer_write_to(struct buffer * buf, int fd);
78
83
 
79
84
  /*
80
85
  * High-performance I/O buffer intended for use in non-blocking programs
@@ -86,8 +91,6 @@ static int buffer_write_to(struct buffer * buf, int fd);
86
91
  void
87
92
  Init_coolio_buffer()
88
93
  {
89
- VALUE cCoolio_IO;
90
-
91
94
  mCoolio = rb_define_module("Coolio");
92
95
  cCoolio_Buffer = rb_define_class_under(mCoolio, "Buffer", rb_cObject);
93
96
  rb_define_alloc_func(cCoolio_Buffer, Coolio_Buffer_allocate);
@@ -114,42 +117,54 @@ Init_coolio_buffer()
114
117
  rb_define_const(cCoolio_Buffer, "MAX_SIZE", INT2NUM(MAX_BUFFER_SIZE));
115
118
  }
116
119
 
120
+ static const rb_data_type_t Coolio_Buffer_type = {
121
+ "Coolio::Buffer",
122
+ {
123
+ Coolio_Buffer_mark,
124
+ Coolio_Buffer_free,
125
+ }
126
+ };
127
+
117
128
  static VALUE
118
129
  Coolio_Buffer_allocate(VALUE klass)
119
130
  {
120
- return Data_Wrap_Struct(klass, Coolio_Buffer_mark, Coolio_Buffer_free, buffer_new());
131
+ struct buffer *buf;
132
+ VALUE buffer = TypedData_Make_Struct(klass, struct buffer, &Coolio_Buffer_type, buf);
133
+
134
+ buffer_init(buf);
135
+ return buffer;
121
136
  }
122
137
 
123
138
  static void
124
- Coolio_Buffer_mark(struct buffer * buf)
139
+ Coolio_Buffer_mark(void *buf)
125
140
  {
126
141
  /* Naively discard the memory pool whenever Ruby garbage collects */
127
142
  buffer_free_pool(buf);
128
143
  }
129
144
 
130
145
  static void
131
- Coolio_Buffer_free(struct buffer * buf)
146
+ Coolio_Buffer_free(void * buf)
132
147
  {
133
148
  buffer_free(buf);
134
149
  }
135
150
 
136
151
  /**
137
152
  * call-seq:
138
- * Coolio::Buffer.default_node_size -> 4096
153
+ * Coolio::Buffer.default_node_size -> 16384
139
154
  *
140
155
  * Retrieves the current value of the default node size.
141
156
  */
142
157
  static VALUE
143
158
  Coolio_Buffer_default_node_size(VALUE klass)
144
159
  {
145
- return UINT2NUM(default_node_size);
160
+ return SIZET2NUM(default_node_size);
146
161
  }
147
162
 
148
163
  /*
149
164
  * safely converts node sizes from Ruby numerics to C and raising
150
165
  * ArgumentError or RangeError on invalid sizes
151
166
  */
152
- static unsigned
167
+ static size_t
153
168
  convert_node_size(VALUE size)
154
169
  {
155
170
  if (
@@ -158,7 +173,7 @@ convert_node_size(VALUE size)
158
173
  )
159
174
  rb_raise(rb_eArgError, "invalid buffer size");
160
175
 
161
- return (unsigned) NUM2INT(size);
176
+ return NUM2SIZET(size);
162
177
  }
163
178
 
164
179
  /**
@@ -188,7 +203,7 @@ Coolio_Buffer_initialize(int argc, VALUE * argv, VALUE self)
188
203
  struct buffer *buf;
189
204
 
190
205
  if (rb_scan_args(argc, argv, "01", &node_size_obj) == 1) {
191
- Data_Get_Struct(self, struct buffer, buf);
206
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
192
207
 
193
208
  /*
194
209
  * Make sure we're not changing the buffer size after data
@@ -212,7 +227,7 @@ static VALUE
212
227
  Coolio_Buffer_clear(VALUE self)
213
228
  {
214
229
  struct buffer *buf;
215
- Data_Get_Struct(self, struct buffer, buf);
230
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
216
231
 
217
232
  buffer_clear(buf);
218
233
 
@@ -229,9 +244,9 @@ static VALUE
229
244
  Coolio_Buffer_size(VALUE self)
230
245
  {
231
246
  struct buffer *buf;
232
- Data_Get_Struct(self, struct buffer, buf);
247
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
233
248
 
234
- return INT2NUM(buf->size);
249
+ return SIZET2NUM(buf->size);
235
250
  }
236
251
 
237
252
  /**
@@ -244,7 +259,7 @@ static VALUE
244
259
  Coolio_Buffer_empty(VALUE self)
245
260
  {
246
261
  struct buffer *buf;
247
- Data_Get_Struct(self, struct buffer, buf);
262
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
248
263
 
249
264
  return buf->size > 0 ? Qfalse : Qtrue;
250
265
  }
@@ -259,7 +274,7 @@ static VALUE
259
274
  Coolio_Buffer_append(VALUE self, VALUE data)
260
275
  {
261
276
  struct buffer *buf;
262
- Data_Get_Struct(self, struct buffer, buf);
277
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
263
278
 
264
279
  /* Is this needed? Never seen anyone else do it... */
265
280
  data = rb_convert_type(data, T_STRING, "String", "to_str");
@@ -278,7 +293,7 @@ static VALUE
278
293
  Coolio_Buffer_prepend(VALUE self, VALUE data)
279
294
  {
280
295
  struct buffer *buf;
281
- Data_Get_Struct(self, struct buffer, buf);
296
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
282
297
 
283
298
  data = rb_convert_type(data, T_STRING, "String", "to_str");
284
299
  buffer_prepend(buf, RSTRING_PTR(data), RSTRING_LEN(data));
@@ -301,15 +316,18 @@ static VALUE
301
316
  Coolio_Buffer_read(int argc, VALUE * argv, VALUE self)
302
317
  {
303
318
  VALUE length_obj, str;
304
- int length;
319
+ size_t length;
305
320
  struct buffer *buf;
306
321
 
307
- Data_Get_Struct(self, struct buffer, buf);
322
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
308
323
 
309
324
  if (rb_scan_args(argc, argv, "01", &length_obj) == 1) {
310
- length = NUM2INT(length_obj);
311
- if(length < 1)
325
+ /* Read signed so a negative argument still raises ArgumentError here
326
+ * rather than RangeError out of the conversion */
327
+ long requested = NUM2LONG(length_obj);
328
+ if(requested < 1)
312
329
  rb_raise(rb_eArgError, "length must be greater than zero");
330
+ length = (size_t) requested;
313
331
  if(length > buf->size)
314
332
  length = buf->size;
315
333
  } else
@@ -318,7 +336,7 @@ Coolio_Buffer_read(int argc, VALUE * argv, VALUE self)
318
336
  if(buf->size == 0)
319
337
  return rb_str_new2("");
320
338
 
321
- str = rb_str_new(0, length);
339
+ str = rb_str_new(0, (long) length);
322
340
  buffer_read(buf, RSTRING_PTR(str), length);
323
341
 
324
342
  return str;
@@ -340,7 +358,10 @@ Coolio_Buffer_read_frame(VALUE self, VALUE data, VALUE mark)
340
358
  char mark_c = (char) NUM2INT(mark);
341
359
  struct buffer *buf;
342
360
 
343
- Data_Get_Struct(self, struct buffer, buf);
361
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
362
+
363
+ StringValue(data);
364
+ rb_str_modify(data);
344
365
 
345
366
  if (buffer_read_frame(buf, data, mark_c)) {
346
367
  return Qtrue;
@@ -361,9 +382,9 @@ Coolio_Buffer_to_str(VALUE self)
361
382
  VALUE str;
362
383
  struct buffer *buf;
363
384
 
364
- Data_Get_Struct(self, struct buffer, buf);
385
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
365
386
 
366
- str = rb_str_new(0, buf->size);
387
+ str = rb_str_new(0, (long) buf->size);
367
388
  buffer_copy(buf, RSTRING_PTR(str), buf->size);
368
389
 
369
390
  return str;
@@ -381,14 +402,14 @@ static VALUE
381
402
  Coolio_Buffer_read_from(VALUE self, VALUE io)
382
403
  {
383
404
  struct buffer *buf;
384
- int ret;
405
+ ssize_t ret;
385
406
  #if defined(HAVE_RB_IO_T) || defined(HAVE_RB_IO_DESCRIPTOR)
386
407
  rb_io_t *fptr;
387
408
  #else
388
409
  OpenFile *fptr;
389
410
  #endif
390
411
 
391
- Data_Get_Struct(self, struct buffer, buf);
412
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
392
413
  io = rb_convert_type(io, T_FILE, "IO", "to_io");
393
414
  GetOpenFile(io, fptr);
394
415
  rb_io_set_nonblock(fptr);
@@ -398,7 +419,7 @@ Coolio_Buffer_read_from(VALUE self, VALUE io)
398
419
  #else
399
420
  ret = buffer_read_from(buf, FPTR_TO_FD(fptr));
400
421
  #endif
401
- return ret == -1 ? Qnil : INT2NUM(ret);
422
+ return ret == -1 ? Qnil : SSIZET2NUM(ret);
402
423
  }
403
424
 
404
425
  /**
@@ -419,15 +440,15 @@ Coolio_Buffer_write_to(VALUE self, VALUE io)
419
440
  OpenFile *fptr;
420
441
  #endif
421
442
 
422
- Data_Get_Struct(self, struct buffer, buf);
443
+ TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf);
423
444
  io = rb_convert_type(io, T_FILE, "IO", "to_io");
424
445
  GetOpenFile(io, fptr);
425
446
  rb_io_set_nonblock(fptr);
426
447
 
427
448
  #ifdef HAVE_RB_IO_DESCRIPTOR
428
- return INT2NUM(buffer_write_to(buf, rb_io_descriptor(io)));
449
+ return SSIZET2NUM(buffer_write_to(buf, rb_io_descriptor(io)));
429
450
  #else
430
- return INT2NUM(buffer_write_to(buf, FPTR_TO_FD(fptr)));
451
+ return SSIZET2NUM(buffer_write_to(buf, FPTR_TO_FD(fptr)));
431
452
  #endif
432
453
  }
433
454
 
@@ -438,11 +459,8 @@ Coolio_Buffer_write_to(VALUE self, VALUE io)
438
459
 
439
460
  /* Create a new buffer */
440
461
  static struct buffer *
441
- buffer_new(void)
462
+ buffer_init(struct buffer *buf)
442
463
  {
443
- struct buffer *buf;
444
-
445
- buf = (struct buffer *) xmalloc(sizeof(struct buffer));
446
464
  buf->head = buf->tail = buf->pool_head = buf->pool_tail = 0;
447
465
  buf->size = 0;
448
466
  buf->node_size = default_node_size;
@@ -472,7 +490,7 @@ buffer_free(struct buffer * buf)
472
490
  buffer_clear(buf);
473
491
  buffer_free_pool(buf);
474
492
 
475
- free(buf);
493
+ xfree(buf);
476
494
  }
477
495
 
478
496
  /* Free the memory pool */
@@ -484,7 +502,7 @@ buffer_free_pool(struct buffer * buf)
484
502
  while (buf->pool_head) {
485
503
  tmp = buf->pool_head;
486
504
  buf->pool_head = tmp->next;
487
- free(tmp);
505
+ xfree(tmp);
488
506
  }
489
507
 
490
508
  buf->pool_tail = 0;
@@ -528,7 +546,7 @@ buffer_node_free(struct buffer * buf, struct buffer_node * node)
528
546
 
529
547
  /* Prepend data to the front of the buffer */
530
548
  static void
531
- buffer_prepend(struct buffer * buf, char *str, unsigned len)
549
+ buffer_prepend(struct buffer * buf, char *str, size_t len)
532
550
  {
533
551
  struct buffer_node *node, *tmp;
534
552
  buf->size += len;
@@ -569,9 +587,9 @@ buffer_prepend(struct buffer * buf, char *str, unsigned len)
569
587
 
570
588
  /* Append data to the front of the buffer */
571
589
  static void
572
- buffer_append(struct buffer * buf, char *str, unsigned len)
590
+ buffer_append(struct buffer * buf, char *str, size_t len)
573
591
  {
574
- unsigned nbytes;
592
+ size_t nbytes;
575
593
  buf->size += len;
576
594
 
577
595
  /* If it fits in the remaining space in the tail */
@@ -606,9 +624,9 @@ buffer_append(struct buffer * buf, char *str, unsigned len)
606
624
 
607
625
  /* Read data from the buffer (and clear what we've read) */
608
626
  static void
609
- buffer_read(struct buffer * buf, char *str, unsigned len)
627
+ buffer_read(struct buffer * buf, char *str, size_t len)
610
628
  {
611
- unsigned nbytes;
629
+ size_t nbytes;
612
630
  struct buffer_node *tmp;
613
631
 
614
632
  while (buf->size > 0 && len > 0) {
@@ -642,7 +660,7 @@ buffer_read(struct buffer * buf, char *str, unsigned len)
642
660
  static int
643
661
  buffer_read_frame(struct buffer * buf, VALUE str, char frame_mark)
644
662
  {
645
- unsigned nbytes = 0;
663
+ size_t nbytes = 0;
646
664
  struct buffer_node *tmp;
647
665
 
648
666
  while (buf->size > 0) {
@@ -657,7 +675,7 @@ buffer_read_frame(struct buffer * buf, VALUE str, char frame_mark)
657
675
  }
658
676
 
659
677
  /* Copy less than everything if we found a frame byte */
660
- rb_str_cat(str, s, nbytes);
678
+ rb_str_cat(str, s, (long) nbytes);
661
679
 
662
680
  /* Fixup the buffer pointers to indicate the bytes were consumed */
663
681
  head->start += nbytes;
@@ -681,9 +699,9 @@ buffer_read_frame(struct buffer * buf, VALUE str, char frame_mark)
681
699
 
682
700
  /* Copy data from the buffer without clearing it */
683
701
  static void
684
- buffer_copy(struct buffer * buf, char *str, unsigned len)
702
+ buffer_copy(struct buffer * buf, char *str, size_t len)
685
703
  {
686
- unsigned nbytes;
704
+ size_t nbytes;
687
705
  struct buffer_node *node;
688
706
 
689
707
  node = buf->head;
@@ -702,10 +720,10 @@ buffer_copy(struct buffer * buf, char *str, unsigned len)
702
720
  }
703
721
 
704
722
  /* Write data from the buffer to a file descriptor */
705
- static int
723
+ static ssize_t
706
724
  buffer_write_to(struct buffer * buf, int fd)
707
725
  {
708
- int bytes_written, total_bytes_written = 0;
726
+ ssize_t bytes_written, total_bytes_written = 0;
709
727
  struct buffer_node *tmp;
710
728
 
711
729
  while (buf->head) {
@@ -723,7 +741,7 @@ buffer_write_to(struct buffer * buf, int fd)
723
741
  buf->size -= bytes_written;
724
742
 
725
743
  /* If the write blocked... */
726
- if (bytes_written < buf->head->end - buf->head->start) {
744
+ if ((size_t) bytes_written < buf->head->end - buf->head->start) {
727
745
  buf->head->start += bytes_written;
728
746
  return total_bytes_written;
729
747
  }
@@ -741,11 +759,11 @@ buffer_write_to(struct buffer * buf, int fd)
741
759
 
742
760
  /* Read data from a file descriptor to a buffer */
743
761
  /* Append data to the front of the buffer */
744
- static int
762
+ static ssize_t
745
763
  buffer_read_from(struct buffer * buf, int fd)
746
764
  {
747
- int bytes_read, total_bytes_read = 0;
748
- unsigned nbytes;
765
+ ssize_t bytes_read, total_bytes_read = 0;
766
+ size_t nbytes;
749
767
 
750
768
  /* Empty list needs initialized */
751
769
  if (!buf->head) {
@@ -775,7 +793,7 @@ buffer_read_from(struct buffer * buf, int fd)
775
793
  buf->tail->next = buffer_node_new(buf);
776
794
  buf->tail = buf->tail->next;
777
795
  }
778
- } while (bytes_read == nbytes);
796
+ } while ((size_t) bytes_read == nbytes);
779
797
 
780
798
  return total_bytes_read;
781
799
  }
@@ -55,6 +55,12 @@ struct Coolio_Watcher
55
55
  int enabled;
56
56
  VALUE loop;
57
57
 
58
+ /* Stable copy of the watched path for ev_stat watchers. libev retains the
59
+ * path pointer passed to ev_stat_init() for the lifetime of the watcher, so
60
+ * it must not point into a Ruby String whose buffer GC.compact may relocate.
61
+ * NULL for watcher types that don't use it. */
62
+ char *stat_path;
63
+
58
64
  void (*dispatch_callback)(VALUE self, int revents);
59
65
  };
60
66
 
@@ -68,4 +74,7 @@ void Init_coolio_timer_watcher();
68
74
  void Init_coolio_stat_watcher();
69
75
  void Init_coolio_utils();
70
76
 
77
+ struct Coolio_Loop *Coolio_Loop_ptr(VALUE loop);
78
+ struct Coolio_Watcher *Coolio_Watcher_ptr(VALUE watcher);
79
+
71
80
  #endif
@@ -11,7 +11,6 @@ have_func('rb_thread_alone')
11
11
  have_func('rb_str_set_len')
12
12
  have_library('rt', 'clock_gettime')
13
13
 
14
- have_func("rb_io_descriptor")
15
14
  have_library("c", "main")
16
15
  if have_macro("HAVE_RB_IO_T", "ruby/io.h")
17
16
  have_struct_member("rb_io_t", "fd", "ruby/io.h")
@@ -82,7 +82,7 @@ static VALUE Coolio_IOWatcher_initialize(int argc, VALUE *argv, VALUE self)
82
82
  else
83
83
  rb_raise(rb_eArgError, "invalid event type: '%s' (must be 'r', 'w', or 'rw')", flags_str);
84
84
 
85
- Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
85
+ watcher_data = Coolio_Watcher_ptr(self);
86
86
  io = rb_convert_type(io, T_FILE, "IO", "to_io");
87
87
 
88
88
  watcher_data->dispatch_callback = Coolio_IOWatcher_dispatch_callback;