PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/fiddle/closure.c

https://github.com/diabolo/ruby
C | 236 lines | 198 code | 37 blank | 1 comment | 14 complexity | 365ab056b946ceee3071764e2bfc46f3 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. #include <fiddle.h>
  2. VALUE cFiddleClosure;
  3. typedef struct {
  4. void * code;
  5. ffi_closure *pcl;
  6. ffi_cif * cif;
  7. int argc;
  8. ffi_type **argv;
  9. } fiddle_closure;
  10. #if defined(MACOSX) || defined(__linux)
  11. #define DONT_USE_FFI_CLOSURE_ALLOC
  12. #endif
  13. static void
  14. dealloc(void * ptr)
  15. {
  16. fiddle_closure * cls = (fiddle_closure *)ptr;
  17. #ifndef DONT_USE_FFI_CLOSURE_ALLOC
  18. ffi_closure_free(cls->pcl);
  19. #else
  20. munmap(cls->pcl, sizeof(cls->pcl));
  21. #endif
  22. xfree(cls->cif);
  23. if (cls->argv) xfree(cls->argv);
  24. xfree(cls);
  25. }
  26. static size_t
  27. closure_memsize(const void * ptr)
  28. {
  29. fiddle_closure * cls = (fiddle_closure *)ptr;
  30. size_t size = 0;
  31. if (ptr) {
  32. size += sizeof(*cls);
  33. #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
  34. size += ffi_raw_size(cls->cif);
  35. #endif
  36. size += sizeof(*cls->argv);
  37. size += sizeof(ffi_closure);
  38. }
  39. return size;
  40. }
  41. const rb_data_type_t closure_data_type = {
  42. "fiddle/closure",
  43. 0, dealloc, closure_memsize,
  44. };
  45. void
  46. callback(ffi_cif *cif, void *resp, void **args, void *ctx)
  47. {
  48. VALUE self = (VALUE)ctx;
  49. VALUE rbargs = rb_iv_get(self, "@args");
  50. VALUE ctype = rb_iv_get(self, "@ctype");
  51. int argc = RARRAY_LENINT(rbargs);
  52. VALUE *params = xcalloc(argc, sizeof(VALUE *));
  53. VALUE ret;
  54. VALUE cPointer;
  55. int i, type;
  56. cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
  57. for (i = 0; i < argc; i++) {
  58. type = NUM2INT(RARRAY_PTR(rbargs)[i]);
  59. switch (type) {
  60. case TYPE_VOID:
  61. argc = 0;
  62. break;
  63. case TYPE_INT:
  64. params[i] = INT2NUM(*(int *)args[i]);
  65. break;
  66. case TYPE_VOIDP:
  67. params[i] = rb_funcall(cPointer, rb_intern("[]"), 1,
  68. PTR2NUM(*(void **)args[i]));
  69. break;
  70. case TYPE_LONG:
  71. params[i] = LONG2NUM(*(long *)args[i]);
  72. break;
  73. case TYPE_CHAR:
  74. params[i] = INT2NUM(*(char *)args[i]);
  75. break;
  76. case TYPE_DOUBLE:
  77. params[i] = rb_float_new(*(double *)args[i]);
  78. break;
  79. case TYPE_FLOAT:
  80. params[i] = rb_float_new(*(float *)args[i]);
  81. break;
  82. #if HAVE_LONG_LONG
  83. case TYPE_LONG_LONG:
  84. params[i] = rb_ull2inum(*(unsigned LONG_LONG *)args[i]);
  85. break;
  86. #endif
  87. default:
  88. rb_raise(rb_eRuntimeError, "closure args: %d", type);
  89. }
  90. }
  91. ret = rb_funcall2(self, rb_intern("call"), argc, params);
  92. type = NUM2INT(ctype);
  93. switch (type) {
  94. case TYPE_VOID:
  95. break;
  96. case TYPE_LONG:
  97. *(long *)resp = NUM2LONG(ret);
  98. break;
  99. case TYPE_CHAR:
  100. *(char *)resp = NUM2INT(ret);
  101. break;
  102. case TYPE_VOIDP:
  103. *(void **)resp = NUM2PTR(ret);
  104. break;
  105. case TYPE_INT:
  106. *(int *)resp = NUM2INT(ret);
  107. break;
  108. case TYPE_DOUBLE:
  109. *(double *)resp = NUM2DBL(ret);
  110. break;
  111. case TYPE_FLOAT:
  112. *(float *)resp = (float)NUM2DBL(ret);
  113. break;
  114. #if HAVE_LONG_LONG
  115. case TYPE_LONG_LONG:
  116. *(unsigned LONG_LONG *)resp = rb_big2ull(ret);
  117. break;
  118. #endif
  119. default:
  120. rb_raise(rb_eRuntimeError, "closure retval: %d", type);
  121. }
  122. xfree(params);
  123. }
  124. static VALUE
  125. allocate(VALUE klass)
  126. {
  127. fiddle_closure * closure;
  128. VALUE i = TypedData_Make_Struct(klass, fiddle_closure,
  129. &closure_data_type, closure);
  130. #ifndef DONT_USE_FFI_CLOSURE_ALLOC
  131. closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
  132. #else
  133. closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
  134. MAP_ANON | MAP_PRIVATE, -1, 0);
  135. #endif
  136. closure->cif = xmalloc(sizeof(ffi_cif));
  137. return i;
  138. }
  139. static VALUE
  140. initialize(int rbargc, VALUE argv[], VALUE self)
  141. {
  142. VALUE ret;
  143. VALUE args;
  144. VALUE abi;
  145. fiddle_closure * cl;
  146. ffi_cif * cif;
  147. ffi_closure *pcl;
  148. ffi_status result;
  149. int i, argc;
  150. if (2 == rb_scan_args(rbargc, argv, "21", &ret, &args, &abi))
  151. abi = INT2NUM(FFI_DEFAULT_ABI);
  152. Check_Type(args, T_ARRAY);
  153. argc = RARRAY_LENINT(args);
  154. TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
  155. cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));
  156. for (i = 0; i < argc; i++) {
  157. int type = NUM2INT(RARRAY_PTR(args)[i]);
  158. cl->argv[i] = INT2FFI_TYPE(type);
  159. }
  160. cl->argv[argc] = NULL;
  161. rb_iv_set(self, "@ctype", ret);
  162. rb_iv_set(self, "@args", args);
  163. cif = cl->cif;
  164. pcl = cl->pcl;
  165. result = ffi_prep_cif(cif, NUM2INT(abi), argc,
  166. INT2FFI_TYPE(NUM2INT(ret)),
  167. cl->argv);
  168. if (FFI_OK != result)
  169. rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
  170. #ifndef DONT_USE_FFI_CLOSURE_ALLOC
  171. result = ffi_prep_closure_loc(pcl, cif, callback,
  172. (void *)self, cl->code);
  173. #else
  174. result = ffi_prep_closure(pcl, cif, callback, (void *)self);
  175. cl->code = (void *)pcl;
  176. mprotect(pcl, sizeof(pcl), PROT_READ | PROT_EXEC);
  177. #endif
  178. if (FFI_OK != result)
  179. rb_raise(rb_eRuntimeError, "error prepping closure %d", result);
  180. return self;
  181. }
  182. static VALUE
  183. to_i(VALUE self)
  184. {
  185. fiddle_closure * cl;
  186. void *code;
  187. TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl);
  188. code = cl->code;
  189. return PTR2NUM(code);
  190. }
  191. void
  192. Init_fiddle_closure()
  193. {
  194. cFiddleClosure = rb_define_class_under(mFiddle, "Closure", rb_cObject);
  195. rb_define_alloc_func(cFiddleClosure, allocate);
  196. rb_define_method(cFiddleClosure, "initialize", initialize, -1);
  197. rb_define_method(cFiddleClosure, "to_i", to_i, 0);
  198. }
  199. /* vim: set noet sw=4 sts=4 */