uv_stubs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #define CAML_NAME_SPACE
  2. #include <caml/alloc.h>
  3. #include <caml/callback.h>
  4. #include <caml/fail.h>
  5. #include <caml/memory.h>
  6. #include <caml/mlvalues.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <uv.h>
  10. #if (UV_VERSION_MAJOR <= 0)
  11. # error "libuv1-dev required, uv version 0.x found"
  12. #endif
  13. // ------------- UTILITY MACROS -------------------------------------
  14. // access the data of a handle or request
  15. #define UV_HANDLE_DATA(h) (((uv_handle_t *)(h))->data)
  16. #define UV_HANDLE_DATA_SUB(h, t) ((t *)((uv_handle_t *)(h))->data)
  17. #define UV_REQ_DATA(r) (((uv_req_t *)(r))->data)
  18. #define UV_REQ_DATA_A(r) ((value *)(&UV_REQ_DATA(r)))
  19. #define UV_ALLOC(t) ((t *)malloc(sizeof(t)))
  20. // ------------- ERROR HANDLING -------------------------------------
  21. #define UV_ALLOC_CHECK(var, type) \
  22. type *var = UV_ALLOC(type); \
  23. if (var == NULL) { \
  24. caml_failwith("malloc " #type " failed"); \
  25. } else {}
  26. #define UV_ALLOC_CHECK_C(var, type, cleanup) \
  27. type *var = UV_ALLOC(type); \
  28. if (var == NULL) { \
  29. cleanup; \
  30. caml_failwith("malloc " #type " failed"); \
  31. } else {}
  32. // TODO: proper exceptions for libuv errors
  33. #define UV_ERROR_CHECK(expr) do { \
  34. int __tmp_result = expr; \
  35. if (__tmp_result < 0) { \
  36. caml_failwith(strdup(uv_strerror(__tmp_result))); \
  37. } \
  38. } while (0)
  39. #define UV_ERROR_CHECK_C(expr, cleanup) do { \
  40. int __tmp_result = expr; \
  41. if (__tmp_result < 0) { \
  42. cleanup; \
  43. caml_failwith(strdup(uv_strerror(__tmp_result))); \
  44. } \
  45. } while (0)
  46. // ------------- LOOP -----------------------------------------------
  47. CAMLprim value w_loop_init(value unit) {
  48. CAMLparam1(unit);
  49. UV_ALLOC_CHECK(loop, uv_loop_t);
  50. UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop));
  51. CAMLreturn((value)loop);
  52. }
  53. CAMLprim value w_loop_close(value loop) {
  54. CAMLparam1(loop);
  55. UV_ERROR_CHECK(uv_loop_close((uv_loop_t *)loop));
  56. free((uv_loop_t *)loop);
  57. CAMLreturn(Val_unit);
  58. }
  59. CAMLprim value w_run(value loop, value mode) {
  60. CAMLparam2(loop, mode);
  61. CAMLreturn(Val_bool(uv_run((uv_loop_t *)loop, (uv_run_mode)mode) == 0));
  62. }
  63. CAMLprim value w_loop_alive(value loop) {
  64. CAMLparam1(loop);
  65. CAMLreturn(Val_bool(uv_loop_alive((uv_loop_t *)loop) != 0));
  66. }
  67. CAMLprim value w_stop(value loop) {
  68. CAMLparam1(loop);
  69. uv_stop((uv_loop_t *)loop);
  70. CAMLreturn(Val_unit);
  71. }
  72. // ------------- FILESYSTEM -----------------------------------------
  73. // TODO: exception handling (optional arguments ...?)
  74. static void handle_fs_cb(uv_fs_t *req) {
  75. CAMLparam0();
  76. value cb = (value)UV_REQ_DATA(req);
  77. if (req->result < 0)
  78. caml_failwith(uv_strerror(req->result));
  79. //hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result));
  80. else
  81. caml_callback(cb, Val_unit);
  82. uv_fs_req_cleanup(req);
  83. caml_remove_global_root(UV_REQ_DATA_A(req));
  84. free(req);
  85. CAMLreturn0;
  86. }
  87. static value handle_fs_cb_sync(uv_fs_t *req) {
  88. return Val_unit;
  89. }
  90. #define UV_FS_HANDLER(name, setup) \
  91. static void name(uv_fs_t *req) { \
  92. CAMLparam0(); \
  93. value cb = (value)UV_REQ_DATA(req); \
  94. if (req->result < 0) \
  95. caml_failwith(uv_strerror(req->result)); \
  96. else { \
  97. value value2; \
  98. do setup while (0); \
  99. caml_callback(cb, value2); \
  100. } \
  101. uv_fs_req_cleanup(req); \
  102. caml_remove_global_root(UV_REQ_DATA_A(req)); \
  103. free(req); \
  104. CAMLreturn0; \
  105. } \
  106. static value name ## _sync(uv_fs_t *req) { \
  107. CAMLparam0(); \
  108. value value2; \
  109. do setup while (0); \
  110. CAMLreturn(value2); \
  111. }
  112. UV_FS_HANDLER(handle_fs_cb_bytes, value2 = caml_copy_string((const char *)req->ptr););
  113. UV_FS_HANDLER(handle_fs_cb_path, value2 = caml_copy_string((const char *)req->path););
  114. UV_FS_HANDLER(handle_fs_cb_int, value2 = (value)req->result;);
  115. UV_FS_HANDLER(handle_fs_cb_file, value2 = (value)req->result;);
  116. UV_FS_HANDLER(handle_fs_cb_stat, {
  117. value2 = caml_alloc(21, 0);
  118. Field(value2, 0) = Val_long(req->statbuf.st_dev);
  119. Field(value2, 1) = Val_long(req->statbuf.st_mode & S_IFMT);
  120. Field(value2, 2) = Val_long(req->statbuf.st_mode & 07777);
  121. Field(value2, 3) = Val_long(req->statbuf.st_nlink);
  122. Field(value2, 4) = Val_long(req->statbuf.st_uid);
  123. Field(value2, 5) = Val_long(req->statbuf.st_gid);
  124. Field(value2, 6) = Val_long(req->statbuf.st_rdev);
  125. Field(value2, 7) = Val_long(req->statbuf.st_ino);
  126. Field(value2, 8) = caml_copy_int64(req->statbuf.st_size);
  127. Field(value2, 9) = Val_long(req->statbuf.st_blksize);
  128. Field(value2, 10) = Val_long(req->statbuf.st_blocks);
  129. Field(value2, 11) = Val_long(req->statbuf.st_flags);
  130. Field(value2, 12) = Val_long(req->statbuf.st_gen);
  131. Field(value2, 13) = caml_copy_int64(req->statbuf.st_atim.tv_sec);
  132. Field(value2, 14) = Val_long(req->statbuf.st_atim.tv_nsec);
  133. Field(value2, 15) = caml_copy_int64(req->statbuf.st_mtim.tv_sec);
  134. Field(value2, 16) = Val_long(req->statbuf.st_mtim.tv_nsec);
  135. Field(value2, 17) = caml_copy_int64(req->statbuf.st_ctim.tv_sec);
  136. Field(value2, 18) = Val_long(req->statbuf.st_ctim.tv_nsec);
  137. Field(value2, 19) = caml_copy_int64(req->statbuf.st_birthtim.tv_sec);
  138. Field(value2, 20) = Val_long(req->statbuf.st_birthtim.tv_nsec);
  139. });
  140. UV_FS_HANDLER(handle_fs_cb_scandir, {
  141. uv_dirent_t ent;
  142. value2 = Val_int(0);
  143. while (uv_fs_scandir_next(req, &ent) != UV_EOF) {
  144. value dirent = caml_alloc(2, 0);
  145. Store_field(dirent, 0, caml_copy_string(ent.name));
  146. Store_field(dirent, 1, ent.type);
  147. value node = caml_alloc(2, 0);
  148. Store_field(node, 0, dirent); // car
  149. Store_field(node, 1, value2); // cdr
  150. value2 = node;
  151. }
  152. });
  153. /*
  154. #define UV_REQ_WRAP(name, reqtype, sign, call, handler) \
  155. CAMLprim value w_ ## name(sign, value cb) { \
  156. UV_ALLOC_CHECK(req, reqtype); \
  157. UV_REQ_DATA(req) = (void *)cb; \
  158. UV_ERROR_CHECK_C(uv_ ## name(req, call, handler), free(req)); \
  159. caml_register_global_root(UV_REQ_DATA(req)); \
  160. CAMLreturn0; \
  161. }
  162. #define UV_REQ_WRAP_LOOP(name, reqtype, sign, call, ffi, handler) \
  163. CAMLprim value w_ ## name(value *loop, sign, value cb) { \
  164. UV_ALLOC_CHECK(req, reqtype); \
  165. UV_REQ_DATA(req) = (void *)cb; \
  166. UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, handler), free(req)); \
  167. caml_register_global_root(UV_REQ_DATA(req)); \
  168. CAMLreturn0; \
  169. }
  170. #define UV_REQ_WRAP_LOOP_SYNC(name, ret, reqtype, sign, call, ffiret, ffi, handler, doret) \
  171. CAMLprim value w_ ## name ## _sync(uv_loop_t *loop, sign) { \
  172. UV_ALLOC_CHECK(req, reqtype); \
  173. UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, NULL), free(req)); \
  174. doret handler ## _sync(req); \
  175. }
  176. */
  177. /*
  178. #define COMMA ,
  179. #define FS_WRAP1_LOOP(name, ret, arg1, ffiret, ffi, ffihandler, handler, doret) \
  180. UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1, _arg1, ffi ffihandler, handler); \
  181. UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1, _arg1, ffiret, ffi, handler, doret)
  182. #define FS_WRAP2_LOOP(name, ret, arg1, arg2, ffiret, ffi, ffihandler, handler, doret) \
  183. UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffi ffihandler, handler); \
  184. UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffiret, ffi, handler, doret)
  185. #define FS_WRAP3_LOOP(name, ret, arg1, arg2, arg3, ffiret, ffi, ffihandler, handler, doret) \
  186. UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, ffi ffihandler, handler); \
  187. UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, ffiret, ffi, handler, doret)
  188. #define FS_WRAP4_LOOP(name, ret, arg1, arg2, arg3, arg4, ffiret, ffi, ffihandler, handler, doret) \
  189. UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffi ffihandler, handler); \
  190. UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffiret, ffi, handler, doret)
  191. */
  192. #define FS_WRAP1(name, arg1conv, handler) \
  193. CAMLprim value w_ ## name(value loop, value arg1, value cb) { \
  194. CAMLparam3(loop, arg1, cb); \
  195. UV_ALLOC_CHECK(req, uv_fs_t); \
  196. UV_REQ_DATA(req) = (void *)cb; \
  197. caml_register_global_root(UV_REQ_DATA_A(req)); \
  198. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), handler), free((uv_fs_t *)req)); \
  199. CAMLreturn(Val_unit); \
  200. } \
  201. CAMLprim value w_ ## name ## _sync(value loop, value arg1) { \
  202. CAMLparam2(loop, arg1); \
  203. UV_ALLOC_CHECK(req, uv_fs_t); \
  204. caml_register_global_root(UV_REQ_DATA_A(req)); \
  205. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), NULL), free((uv_fs_t *)req)); \
  206. UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
  207. value ret = handler ## _sync(req); \
  208. uv_fs_req_cleanup(req); \
  209. free(req); \
  210. CAMLreturn(ret); \
  211. }
  212. #define FS_WRAP2(name, arg1conv, arg2conv, handler) \
  213. CAMLprim value w_ ## name(value loop, value arg1, value arg2, value cb) { \
  214. CAMLparam4(loop, arg1, arg2, cb); \
  215. UV_ALLOC_CHECK(req, uv_fs_t); \
  216. UV_REQ_DATA(req) = (void *)cb; \
  217. caml_register_global_root(UV_REQ_DATA_A(req)); \
  218. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), handler), free((uv_fs_t *)req)); \
  219. CAMLreturn(Val_unit); \
  220. } \
  221. CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2) { \
  222. CAMLparam3(loop, arg1, arg2); \
  223. UV_ALLOC_CHECK(req, uv_fs_t); \
  224. caml_register_global_root(UV_REQ_DATA_A(req)); \
  225. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), NULL), free((uv_fs_t *)req)); \
  226. UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
  227. value ret = handler ## _sync(req); \
  228. uv_fs_req_cleanup(req); \
  229. free(req); \
  230. CAMLreturn(ret); \
  231. }
  232. #define FS_WRAP3(name, arg1conv, arg2conv, arg3conv, handler) \
  233. CAMLprim value w_ ## name(value loop, value arg1, value arg2, value arg3, value cb) { \
  234. CAMLparam5(loop, arg1, arg2, arg3, cb); \
  235. UV_ALLOC_CHECK(req, uv_fs_t); \
  236. UV_REQ_DATA(req) = (void *)cb; \
  237. caml_register_global_root(UV_REQ_DATA_A(req)); \
  238. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), arg3conv(arg3), handler), free((uv_fs_t *)req)); \
  239. CAMLreturn(Val_unit); \
  240. } \
  241. CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2, value arg3) { \
  242. CAMLparam4(loop, arg1, arg2, arg3); \
  243. UV_ALLOC_CHECK(req, uv_fs_t); \
  244. caml_register_global_root(UV_REQ_DATA_A(req)); \
  245. UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), arg3conv(arg3), NULL), free((uv_fs_t *)req)); \
  246. UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
  247. value ret = handler ## _sync(req); \
  248. uv_fs_req_cleanup(req); \
  249. free(req); \
  250. CAMLreturn(ret); \
  251. }
  252. /**
  253. FIXME:
  254. w_fs_read, w_fs_write, w_fs_read_sync, and w_fs_write_sync
  255. have a signature different from libuv due to no struct passing support in
  256. hashlink; currently only a single uv_buf_t can be passed at a time.
  257. **/
  258. /*
  259. HL_PRIM void HL_NAME(w_fs_read)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset, vclosure *cb) {
  260. UV_ALLOC_CHECK(req, uv_fs_t);
  261. UV_REQ_DATA(req) = (void *)cb;
  262. UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
  263. hl_add_root(UV_REQ_DATA(req));
  264. }
  265. HL_PRIM int HL_NAME(w_fs_read_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
  266. UV_ALLOC_CHECK(req, uv_fs_t);
  267. UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, NULL), free(req));
  268. return handle_fs_cb_int_sync(req);
  269. }
  270. HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset, vclosure *cb) {
  271. UV_ALLOC_CHECK(req, uv_fs_t);
  272. UV_REQ_DATA(req) = (void *)cb;
  273. UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
  274. hl_add_root(UV_REQ_DATA(req));
  275. }
  276. HL_PRIM int HL_NAME(w_fs_write_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
  277. UV_ALLOC_CHECK(req, uv_fs_t);
  278. UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, NULL), free(req));
  279. return handle_fs_cb_int_sync(req);
  280. }
  281. */
  282. FS_WRAP1(fs_close, (uv_file), handle_fs_cb);
  283. FS_WRAP3(fs_open, String_val, (int), (int), handle_fs_cb_file);
  284. FS_WRAP1(fs_unlink, String_val, handle_fs_cb);
  285. FS_WRAP2(fs_mkdir, String_val, (int), handle_fs_cb);
  286. FS_WRAP1(fs_mkdtemp, String_val, handle_fs_cb_path);
  287. FS_WRAP1(fs_rmdir, String_val, handle_fs_cb);
  288. FS_WRAP2(fs_scandir, String_val, (int), handle_fs_cb_scandir);
  289. FS_WRAP1(fs_stat, String_val, handle_fs_cb_stat);
  290. FS_WRAP1(fs_fstat, (uv_file), handle_fs_cb_stat);
  291. FS_WRAP1(fs_lstat, String_val, handle_fs_cb_stat);
  292. FS_WRAP2(fs_rename, String_val, String_val, handle_fs_cb);
  293. FS_WRAP1(fs_fsync, (uv_file), handle_fs_cb);
  294. FS_WRAP1(fs_fdatasync, (uv_file), handle_fs_cb);
  295. FS_WRAP2(fs_ftruncate, (uv_file), Int64_val, handle_fs_cb);
  296. //FS_WRAP4(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, );
  297. FS_WRAP2(fs_access, String_val, (int), handle_fs_cb);
  298. FS_WRAP2(fs_chmod, String_val, (int), handle_fs_cb);
  299. FS_WRAP2(fs_fchmod, (uv_file), (int), handle_fs_cb);
  300. FS_WRAP3(fs_utime, String_val, Double_val, Double_val, handle_fs_cb);
  301. FS_WRAP3(fs_futime, (uv_file), Double_val, Double_val, handle_fs_cb);
  302. FS_WRAP2(fs_link, String_val, String_val, handle_fs_cb);
  303. FS_WRAP3(fs_symlink, String_val, String_val, (int), handle_fs_cb);
  304. FS_WRAP1(fs_readlink, String_val, handle_fs_cb_bytes);
  305. FS_WRAP1(fs_realpath, String_val, handle_fs_cb_bytes);
  306. FS_WRAP3(fs_chown, String_val, (uv_uid_t), (uv_gid_t), handle_fs_cb);
  307. FS_WRAP3(fs_fchown, (uv_file), (uv_uid_t), (uv_gid_t), handle_fs_cb);