PageRenderTime 52ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/dl/closure.c

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