fiddle 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <fiddle.h>
3
3
 
4
- #define SafeStringValueCStr(v) (rb_check_safe_obj(rb_string_value(&v)), StringValueCStr(v))
5
-
6
4
  VALUE rb_cHandle;
7
5
 
8
6
  struct dl_handle {
@@ -76,14 +74,14 @@ rb_fiddle_handle_close(VALUE self)
76
74
  /* Check dlclose for successful return value */
77
75
  if(ret) {
78
76
  #if defined(HAVE_DLERROR)
79
- rb_raise(rb_eFiddleError, "%s", dlerror());
77
+ rb_raise(rb_eFiddleDLError, "%s", dlerror());
80
78
  #else
81
- rb_raise(rb_eFiddleError, "could not close handle");
79
+ rb_raise(rb_eFiddleDLError, "could not close handle");
82
80
  #endif
83
81
  }
84
82
  return INT2NUM(ret);
85
83
  }
86
- rb_raise(rb_eFiddleError, "dlclose() called too many times");
84
+ rb_raise(rb_eFiddleDLError, "dlclose() called too many times");
87
85
 
88
86
  UNREACHABLE;
89
87
  }
@@ -145,11 +143,11 @@ rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
145
143
  cflag = RTLD_LAZY | RTLD_GLOBAL;
146
144
  break;
147
145
  case 1:
148
- clib = NIL_P(lib) ? NULL : SafeStringValueCStr(lib);
146
+ clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
149
147
  cflag = RTLD_LAZY | RTLD_GLOBAL;
150
148
  break;
151
149
  case 2:
152
- clib = NIL_P(lib) ? NULL : SafeStringValueCStr(lib);
150
+ clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
153
151
  cflag = NUM2INT(flag);
154
152
  break;
155
153
  default:
@@ -179,12 +177,12 @@ rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
179
177
  ptr = dlopen(clib, cflag);
180
178
  #if defined(HAVE_DLERROR)
181
179
  if( !ptr && (err = dlerror()) ){
182
- rb_raise(rb_eFiddleError, "%s", err);
180
+ rb_raise(rb_eFiddleDLError, "%s", err);
183
181
  }
184
182
  #else
185
183
  if( !ptr ){
186
184
  err = dlerror();
187
- rb_raise(rb_eFiddleError, "%s", err);
185
+ rb_raise(rb_eFiddleDLError, "%s", err);
188
186
  }
189
187
  #endif
190
188
  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
@@ -280,7 +278,7 @@ rb_fiddle_handle_sym(VALUE self, VALUE sym)
280
278
 
281
279
  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
282
280
  if( ! fiddle_handle->open ){
283
- rb_raise(rb_eFiddleError, "closed handle");
281
+ rb_raise(rb_eFiddleDLError, "closed handle");
284
282
  }
285
283
 
286
284
  return fiddle_handle_sym(fiddle_handle->ptr, sym);
@@ -319,7 +317,7 @@ fiddle_handle_sym(void *handle, VALUE symbol)
319
317
  # define CHECK_DLERROR
320
318
  #endif
321
319
  void (*func)();
322
- const char *name = SafeStringValueCStr(symbol);
320
+ const char *name = StringValueCStr(symbol);
323
321
 
324
322
  #ifdef HAVE_DLERROR
325
323
  dlerror();
@@ -368,7 +366,7 @@ fiddle_handle_sym(void *handle, VALUE symbol)
368
366
  }
369
367
  #endif
370
368
  if( !func ){
371
- rb_raise(rb_eFiddleError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
369
+ rb_raise(rb_eFiddleDLError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
372
370
  }
373
371
 
374
372
  return PTR2NUM(func);
@@ -0,0 +1,123 @@
1
+ #include <fiddle.h>
2
+
3
+ VALUE rb_cPinned;
4
+ VALUE rb_eFiddleClearedReferenceError;
5
+
6
+ struct pinned_data {
7
+ VALUE ptr;
8
+ };
9
+
10
+ static void
11
+ pinned_mark(void *ptr)
12
+ {
13
+ struct pinned_data *data = (struct pinned_data*)ptr;
14
+ /* Ensure reference is pinned */
15
+ if (data->ptr) {
16
+ rb_gc_mark(data->ptr);
17
+ }
18
+ }
19
+
20
+ static size_t
21
+ pinned_memsize(const void *ptr)
22
+ {
23
+ return sizeof(struct pinned_data);
24
+ }
25
+
26
+ static const rb_data_type_t pinned_data_type = {
27
+ "fiddle/pinned",
28
+ {pinned_mark, xfree, pinned_memsize, },
29
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
30
+ };
31
+
32
+ static VALUE
33
+ allocate(VALUE klass)
34
+ {
35
+ struct pinned_data *data;
36
+ VALUE obj = TypedData_Make_Struct(klass, struct pinned_data, &pinned_data_type, data);
37
+ data->ptr = 0;
38
+ return obj;
39
+ }
40
+
41
+ /*
42
+ * call-seq:
43
+ * Fiddle::Pinned.new(object) => pinned_object
44
+ *
45
+ * Create a new pinned object reference. The Fiddle::Pinned instance will
46
+ * prevent the GC from moving +object+.
47
+ */
48
+ static VALUE
49
+ initialize(VALUE self, VALUE ref)
50
+ {
51
+ struct pinned_data *data;
52
+ TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
53
+ RB_OBJ_WRITE(self, &data->ptr, ref);
54
+ return self;
55
+ }
56
+
57
+ /*
58
+ * call-seq: ref
59
+ *
60
+ * Return the object that this pinned instance references.
61
+ */
62
+ static VALUE
63
+ ref(VALUE self)
64
+ {
65
+ struct pinned_data *data;
66
+ TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
67
+ if (data->ptr) {
68
+ return data->ptr;
69
+ } else {
70
+ rb_raise(rb_eFiddleClearedReferenceError, "`ref` called on a cleared object");
71
+ }
72
+ }
73
+
74
+ /*
75
+ * call-seq: clear
76
+ *
77
+ * Clear the reference to the object this is pinning.
78
+ */
79
+ static VALUE
80
+ clear(VALUE self)
81
+ {
82
+ struct pinned_data *data;
83
+ TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
84
+ data->ptr = 0;
85
+ return self;
86
+ }
87
+
88
+ /*
89
+ * call-seq: cleared?
90
+ *
91
+ * Returns true if the reference has been cleared, otherwise returns false.
92
+ */
93
+ static VALUE
94
+ cleared_p(VALUE self)
95
+ {
96
+ struct pinned_data *data;
97
+ TypedData_Get_Struct(self, struct pinned_data, &pinned_data_type, data);
98
+ if (data->ptr) {
99
+ return Qfalse;
100
+ } else {
101
+ return Qtrue;
102
+ }
103
+ }
104
+
105
+ extern VALUE rb_eFiddleError;
106
+
107
+ void
108
+ Init_fiddle_pinned(void)
109
+ {
110
+ rb_cPinned = rb_define_class_under(mFiddle, "Pinned", rb_cObject);
111
+ rb_define_alloc_func(rb_cPinned, allocate);
112
+ rb_define_method(rb_cPinned, "initialize", initialize, 1);
113
+ rb_define_method(rb_cPinned, "ref", ref, 0);
114
+ rb_define_method(rb_cPinned, "clear", clear, 0);
115
+ rb_define_method(rb_cPinned, "cleared?", cleared_p, 0);
116
+
117
+ /*
118
+ * Document-class: Fiddle::ClearedReferenceError
119
+ *
120
+ * Cleared reference exception
121
+ */
122
+ rb_eFiddleClearedReferenceError = rb_define_class_under(mFiddle, "ClearedReferenceError", rb_eFiddleError);
123
+ }
@@ -2,6 +2,7 @@
2
2
  * $Id$
3
3
  */
4
4
 
5
+ #include <stdbool.h>
5
6
  #include <ruby/ruby.h>
6
7
  #include <ruby/io.h>
7
8
  #include <ctype.h>
@@ -24,6 +25,7 @@ struct ptr_data {
24
25
  void *ptr;
25
26
  long size;
26
27
  freefunc_t free;
28
+ bool freed;
27
29
  VALUE wrap[2];
28
30
  };
29
31
 
@@ -57,14 +59,19 @@ fiddle_ptr_mark(void *ptr)
57
59
  }
58
60
 
59
61
  static void
60
- fiddle_ptr_free(void *ptr)
62
+ fiddle_ptr_free_ptr(void *ptr)
61
63
  {
62
64
  struct ptr_data *data = ptr;
63
- if (data->ptr) {
64
- if (data->free) {
65
- (*(data->free))(data->ptr);
66
- }
65
+ if (data->ptr && data->free && !data->freed) {
66
+ data->freed = true;
67
+ (*(data->free))(data->ptr);
67
68
  }
69
+ }
70
+
71
+ static void
72
+ fiddle_ptr_free(void *ptr)
73
+ {
74
+ fiddle_ptr_free_ptr(ptr);
68
75
  xfree(ptr);
69
76
  }
70
77
 
@@ -89,8 +96,8 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
89
96
  val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
90
97
  data->ptr = ptr;
91
98
  data->free = func;
99
+ data->freed = false;
92
100
  data->size = size;
93
- OBJ_TAINT(val);
94
101
 
95
102
  return val;
96
103
  }
@@ -102,13 +109,13 @@ rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
102
109
  }
103
110
 
104
111
  static VALUE
105
- rb_fiddle_ptr_malloc(long size, freefunc_t func)
112
+ rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
106
113
  {
107
114
  void *ptr;
108
115
 
109
116
  ptr = ruby_xmalloc((size_t)size);
110
117
  memset(ptr,0,(size_t)size);
111
- return rb_fiddle_ptr_new(ptr, size, func);
118
+ return rb_fiddle_ptr_new2(klass, ptr, size, func);
112
119
  }
113
120
 
114
121
  static void *
@@ -141,6 +148,7 @@ rb_fiddle_ptr_s_allocate(VALUE klass)
141
148
  data->ptr = 0;
142
149
  data->size = 0;
143
150
  data->free = 0;
151
+ data->freed = false;
144
152
 
145
153
  return obj;
146
154
  }
@@ -192,16 +200,53 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
192
200
  return Qnil;
193
201
  }
194
202
 
203
+ static VALUE
204
+ rb_fiddle_ptr_call_free(VALUE self);
205
+
195
206
  /*
196
207
  * call-seq:
197
- *
198
208
  * Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
209
+ * Fiddle::Pointer.malloc(size, freefunc) { |pointer| ... } => ...
210
+ *
211
+ * == Examples
212
+ *
213
+ * # Automatically freeing the pointer when the block is exited - recommended
214
+ * Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
215
+ * ...
216
+ * end
217
+ *
218
+ * # Manually freeing but relying on the garbage collector otherwise
219
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
220
+ * ...
221
+ * pointer.call_free
222
+ *
223
+ * # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
224
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
225
+ * ...
226
+ *
227
+ * # Only manually freeing
228
+ * pointer = Fiddle::Pointer.malloc(size)
229
+ * begin
230
+ * ...
231
+ * ensure
232
+ * Fiddle.free pointer
233
+ * end
234
+ *
235
+ * # No free function and no call to free - the native memory will leak if the pointer is garbage collected
236
+ * pointer = Fiddle::Pointer.malloc(size)
237
+ * ...
199
238
  *
200
239
  * Allocate +size+ bytes of memory and associate it with an optional
201
- * +freefunc+ that will be called when the pointer is garbage collected.
240
+ * +freefunc+.
241
+ *
242
+ * If a block is supplied, the pointer will be yielded to the block instead of
243
+ * being returned, and the return value of the block will be returned. A
244
+ * +freefunc+ must be supplied if a block is.
202
245
  *
203
- * +freefunc+ must be an address pointing to a function or an instance of
204
- * Fiddle::Function
246
+ * If a +freefunc+ is supplied it will be called once, when the pointer is
247
+ * garbage collected or when the block is left if a block is supplied or
248
+ * when the user calls +call_free+, whichever happens first. +freefunc+ must be
249
+ * an address pointing to a function or an instance of +Fiddle::Function+.
205
250
  */
206
251
  static VALUE
207
252
  rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
@@ -223,10 +268,17 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
223
268
  rb_bug("rb_fiddle_ptr_s_malloc");
224
269
  }
225
270
 
226
- obj = rb_fiddle_ptr_malloc(s,f);
271
+ obj = rb_fiddle_ptr_malloc(klass, s,f);
227
272
  if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
228
273
 
229
- return obj;
274
+ if (rb_block_given_p()) {
275
+ if (!f) {
276
+ rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
277
+ }
278
+ return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
279
+ } else {
280
+ return obj;
281
+ }
230
282
  }
231
283
 
232
284
  /*
@@ -351,6 +403,34 @@ rb_fiddle_ptr_free_get(VALUE self)
351
403
  return rb_fiddle_new_function(address, arg_types, ret_type);
352
404
  }
353
405
 
406
+ /*
407
+ * call-seq: call_free => nil
408
+ *
409
+ * Call the free function for this pointer. Calling more than once will do
410
+ * nothing. Does nothing if there is no free function attached.
411
+ */
412
+ static VALUE
413
+ rb_fiddle_ptr_call_free(VALUE self)
414
+ {
415
+ struct ptr_data *pdata;
416
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
417
+ fiddle_ptr_free_ptr(pdata);
418
+ return Qnil;
419
+ }
420
+
421
+ /*
422
+ * call-seq: freed? => bool
423
+ *
424
+ * Returns if the free function for this pointer has been called.
425
+ */
426
+ static VALUE
427
+ rb_fiddle_ptr_freed_p(VALUE self)
428
+ {
429
+ struct ptr_data *pdata;
430
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
431
+ return pdata->freed ? Qtrue : Qfalse;
432
+ }
433
+
354
434
  /*
355
435
  * call-seq:
356
436
  *
@@ -376,11 +456,11 @@ rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
376
456
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
377
457
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
378
458
  case 0:
379
- val = rb_tainted_str_new2((char*)(data->ptr));
459
+ val = rb_str_new2((char*)(data->ptr));
380
460
  break;
381
461
  case 1:
382
462
  len = NUM2INT(arg1);
383
- val = rb_tainted_str_new((char*)(data->ptr), len);
463
+ val = rb_str_new((char*)(data->ptr), len);
384
464
  break;
385
465
  default:
386
466
  rb_bug("rb_fiddle_ptr_to_s");
@@ -414,11 +494,11 @@ rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
414
494
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
415
495
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
416
496
  case 0:
417
- val = rb_tainted_str_new((char*)(data->ptr),data->size);
497
+ val = rb_str_new((char*)(data->ptr),data->size);
418
498
  break;
419
499
  case 1:
420
500
  len = NUM2INT(arg1);
421
- val = rb_tainted_str_new((char*)(data->ptr), len);
501
+ val = rb_str_new((char*)(data->ptr), len);
422
502
  break;
423
503
  default:
424
504
  rb_bug("rb_fiddle_ptr_to_str");
@@ -440,7 +520,7 @@ rb_fiddle_ptr_inspect(VALUE self)
440
520
 
441
521
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
442
522
  return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
443
- RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
523
+ RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
444
524
  }
445
525
 
446
526
  /*
@@ -542,7 +622,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
542
622
  struct ptr_data *data;
543
623
 
544
624
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
545
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
625
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
546
626
  switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
547
627
  case 1:
548
628
  offset = NUM2ULONG(arg0);
@@ -551,7 +631,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
551
631
  case 2:
552
632
  offset = NUM2ULONG(arg0);
553
633
  len = NUM2ULONG(arg1);
554
- retval = rb_tainted_str_new((char *)data->ptr + offset, len);
634
+ retval = rb_str_new((char *)data->ptr + offset, len);
555
635
  break;
556
636
  default:
557
637
  rb_bug("rb_fiddle_ptr_aref()");
@@ -580,7 +660,7 @@ rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
580
660
  struct ptr_data *data;
581
661
 
582
662
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
583
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
663
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
584
664
  switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
585
665
  case 2:
586
666
  offset = NUM2ULONG(arg0);
@@ -661,7 +741,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
661
741
  wrap = 0;
662
742
  }
663
743
  else{
664
- rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
744
+ rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
665
745
  }
666
746
  }
667
747
  else{
@@ -669,7 +749,6 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
669
749
  if (num == val) wrap = 0;
670
750
  ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
671
751
  }
672
- OBJ_INFECT(ptr, val);
673
752
  if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
674
753
  return ptr;
675
754
  }
@@ -677,6 +756,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
677
756
  void
678
757
  Init_fiddle_pointer(void)
679
758
  {
759
+ #undef rb_intern
680
760
  id_to_ptr = rb_intern("to_ptr");
681
761
 
682
762
  /* Document-class: Fiddle::Pointer
@@ -692,6 +772,8 @@ Init_fiddle_pointer(void)
692
772
  rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
693
773
  rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
694
774
  rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
775
+ rb_define_method(rb_cPointer, "call_free", rb_fiddle_ptr_call_free, 0);
776
+ rb_define_method(rb_cPointer, "freed?", rb_fiddle_ptr_freed_p, 0);
695
777
  rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
696
778
  rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
697
779
  rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);