123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- #define CAML_NAME_SPACE
- #include <caml/alloc.h>
- #include <caml/callback.h>
- #include <caml/fail.h>
- #include <caml/memory.h>
- #include <caml/mlvalues.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <uv.h>
- #if (UV_VERSION_MAJOR <= 0)
- # error "libuv1-dev required, uv version 0.x found"
- #endif
- // ------------- UTILITY MACROS -------------------------------------
- // access the data of a handle or request
- #define UV_HANDLE_DATA(h) (((uv_handle_t *)(h))->data)
- #define UV_HANDLE_DATA_SUB(h, t) ((t *)((uv_handle_t *)(h))->data)
- #define UV_REQ_DATA(r) (((uv_req_t *)(r))->data)
- #define UV_REQ_DATA_A(r) ((value *)(&UV_REQ_DATA(r)))
- #define UV_ALLOC(t) ((t *)malloc(sizeof(t)))
- // ------------- ERROR HANDLING -------------------------------------
- #define UV_ALLOC_CHECK(var, type) \
- type *var = UV_ALLOC(type); \
- if (var == NULL) { \
- caml_failwith("malloc " #type " failed"); \
- } else {}
- #define UV_ALLOC_CHECK_C(var, type, cleanup) \
- type *var = UV_ALLOC(type); \
- if (var == NULL) { \
- cleanup; \
- caml_failwith("malloc " #type " failed"); \
- } else {}
- // TODO: proper exceptions for libuv errors
- #define UV_ERROR_CHECK(expr) do { \
- int __tmp_result = expr; \
- if (__tmp_result < 0) { \
- caml_failwith(strdup(uv_strerror(__tmp_result))); \
- } \
- } while (0)
- #define UV_ERROR_CHECK_C(expr, cleanup) do { \
- int __tmp_result = expr; \
- if (__tmp_result < 0) { \
- cleanup; \
- caml_failwith(strdup(uv_strerror(__tmp_result))); \
- } \
- } while (0)
- // ------------- LOOP -----------------------------------------------
- CAMLprim value w_loop_init(value unit) {
- CAMLparam1(unit);
- UV_ALLOC_CHECK(loop, uv_loop_t);
- UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop));
- CAMLreturn((value)loop);
- }
- CAMLprim value w_loop_close(value loop) {
- CAMLparam1(loop);
- UV_ERROR_CHECK(uv_loop_close((uv_loop_t *)loop));
- free((uv_loop_t *)loop);
- CAMLreturn(Val_unit);
- }
- CAMLprim value w_run(value loop, value mode) {
- CAMLparam2(loop, mode);
- CAMLreturn(Val_bool(uv_run((uv_loop_t *)loop, (uv_run_mode)mode) == 0));
- }
- CAMLprim value w_loop_alive(value loop) {
- CAMLparam1(loop);
- CAMLreturn(Val_bool(uv_loop_alive((uv_loop_t *)loop) != 0));
- }
- CAMLprim value w_stop(value loop) {
- CAMLparam1(loop);
- uv_stop((uv_loop_t *)loop);
- CAMLreturn(Val_unit);
- }
- // ------------- FILESYSTEM -----------------------------------------
- // TODO: exception handling (optional arguments ...?)
- static void handle_fs_cb(uv_fs_t *req) {
- CAMLparam0();
- value cb = (value)UV_REQ_DATA(req);
- if (req->result < 0)
- caml_failwith(uv_strerror(req->result));
- //hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result));
- else
- caml_callback(cb, Val_unit);
- uv_fs_req_cleanup(req);
- caml_remove_global_root(UV_REQ_DATA_A(req));
- free(req);
- CAMLreturn0;
- }
- static value handle_fs_cb_sync(uv_fs_t *req) {
- return Val_unit;
- }
- #define UV_FS_HANDLER(name, setup) \
- static void name(uv_fs_t *req) { \
- CAMLparam0(); \
- value cb = (value)UV_REQ_DATA(req); \
- if (req->result < 0) \
- caml_failwith(uv_strerror(req->result)); \
- else { \
- value value2; \
- do setup while (0); \
- caml_callback(cb, value2); \
- } \
- uv_fs_req_cleanup(req); \
- caml_remove_global_root(UV_REQ_DATA_A(req)); \
- free(req); \
- CAMLreturn0; \
- } \
- static value name ## _sync(uv_fs_t *req) { \
- CAMLparam0(); \
- value value2; \
- do setup while (0); \
- CAMLreturn(value2); \
- }
- UV_FS_HANDLER(handle_fs_cb_bytes, value2 = caml_copy_string((const char *)req->ptr););
- UV_FS_HANDLER(handle_fs_cb_path, value2 = caml_copy_string((const char *)req->path););
- UV_FS_HANDLER(handle_fs_cb_int, value2 = (value)req->result;);
- UV_FS_HANDLER(handle_fs_cb_file, value2 = (value)req->result;);
- UV_FS_HANDLER(handle_fs_cb_stat, {
- value2 = caml_alloc(21, 0);
- Field(value2, 0) = Val_long(req->statbuf.st_dev);
- Field(value2, 1) = Val_long(req->statbuf.st_mode & S_IFMT);
- Field(value2, 2) = Val_long(req->statbuf.st_mode & 07777);
- Field(value2, 3) = Val_long(req->statbuf.st_nlink);
- Field(value2, 4) = Val_long(req->statbuf.st_uid);
- Field(value2, 5) = Val_long(req->statbuf.st_gid);
- Field(value2, 6) = Val_long(req->statbuf.st_rdev);
- Field(value2, 7) = Val_long(req->statbuf.st_ino);
- Field(value2, 8) = caml_copy_int64(req->statbuf.st_size);
- Field(value2, 9) = Val_long(req->statbuf.st_blksize);
- Field(value2, 10) = Val_long(req->statbuf.st_blocks);
- Field(value2, 11) = Val_long(req->statbuf.st_flags);
- Field(value2, 12) = Val_long(req->statbuf.st_gen);
- Field(value2, 13) = caml_copy_int64(req->statbuf.st_atim.tv_sec);
- Field(value2, 14) = Val_long(req->statbuf.st_atim.tv_nsec);
- Field(value2, 15) = caml_copy_int64(req->statbuf.st_mtim.tv_sec);
- Field(value2, 16) = Val_long(req->statbuf.st_mtim.tv_nsec);
- Field(value2, 17) = caml_copy_int64(req->statbuf.st_ctim.tv_sec);
- Field(value2, 18) = Val_long(req->statbuf.st_ctim.tv_nsec);
- Field(value2, 19) = caml_copy_int64(req->statbuf.st_birthtim.tv_sec);
- Field(value2, 20) = Val_long(req->statbuf.st_birthtim.tv_nsec);
- });
- UV_FS_HANDLER(handle_fs_cb_scandir, {
- uv_dirent_t ent;
- value2 = Val_int(0);
- while (uv_fs_scandir_next(req, &ent) != UV_EOF) {
- value dirent = caml_alloc(2, 0);
- Store_field(dirent, 0, caml_copy_string(ent.name));
- Store_field(dirent, 1, ent.type);
- value node = caml_alloc(2, 0);
- Store_field(node, 0, dirent); // car
- Store_field(node, 1, value2); // cdr
- value2 = node;
- }
- });
- /*
- #define UV_REQ_WRAP(name, reqtype, sign, call, handler) \
- CAMLprim value w_ ## name(sign, value cb) { \
- UV_ALLOC_CHECK(req, reqtype); \
- UV_REQ_DATA(req) = (void *)cb; \
- UV_ERROR_CHECK_C(uv_ ## name(req, call, handler), free(req)); \
- caml_register_global_root(UV_REQ_DATA(req)); \
- CAMLreturn0; \
- }
- #define UV_REQ_WRAP_LOOP(name, reqtype, sign, call, ffi, handler) \
- CAMLprim value w_ ## name(value *loop, sign, value cb) { \
- UV_ALLOC_CHECK(req, reqtype); \
- UV_REQ_DATA(req) = (void *)cb; \
- UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, handler), free(req)); \
- caml_register_global_root(UV_REQ_DATA(req)); \
- CAMLreturn0; \
- }
- #define UV_REQ_WRAP_LOOP_SYNC(name, ret, reqtype, sign, call, ffiret, ffi, handler, doret) \
- CAMLprim value w_ ## name ## _sync(uv_loop_t *loop, sign) { \
- UV_ALLOC_CHECK(req, reqtype); \
- UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, NULL), free(req)); \
- doret handler ## _sync(req); \
- }
- */
- /*
- #define COMMA ,
- #define FS_WRAP1_LOOP(name, ret, arg1, ffiret, ffi, ffihandler, handler, doret) \
- UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1, _arg1, ffi ffihandler, handler); \
- UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1, _arg1, ffiret, ffi, handler, doret)
- #define FS_WRAP2_LOOP(name, ret, arg1, arg2, ffiret, ffi, ffihandler, handler, doret) \
- UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffi ffihandler, handler); \
- UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffiret, ffi, handler, doret)
- #define FS_WRAP3_LOOP(name, ret, arg1, arg2, arg3, ffiret, ffi, ffihandler, handler, doret) \
- UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, ffi ffihandler, handler); \
- 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)
- #define FS_WRAP4_LOOP(name, ret, arg1, arg2, arg3, arg4, ffiret, ffi, ffihandler, handler, doret) \
- 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); \
- 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)
- */
- #define FS_WRAP1(name, arg1conv, handler) \
- CAMLprim value w_ ## name(value loop, value arg1, value cb) { \
- CAMLparam3(loop, arg1, cb); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- UV_REQ_DATA(req) = (void *)cb; \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), handler), free((uv_fs_t *)req)); \
- CAMLreturn(Val_unit); \
- } \
- CAMLprim value w_ ## name ## _sync(value loop, value arg1) { \
- CAMLparam2(loop, arg1); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), NULL), free((uv_fs_t *)req)); \
- UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
- value ret = handler ## _sync(req); \
- uv_fs_req_cleanup(req); \
- free(req); \
- CAMLreturn(ret); \
- }
- #define FS_WRAP2(name, arg1conv, arg2conv, handler) \
- CAMLprim value w_ ## name(value loop, value arg1, value arg2, value cb) { \
- CAMLparam4(loop, arg1, arg2, cb); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- UV_REQ_DATA(req) = (void *)cb; \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), handler), free((uv_fs_t *)req)); \
- CAMLreturn(Val_unit); \
- } \
- CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2) { \
- CAMLparam3(loop, arg1, arg2); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), NULL), free((uv_fs_t *)req)); \
- UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
- value ret = handler ## _sync(req); \
- uv_fs_req_cleanup(req); \
- free(req); \
- CAMLreturn(ret); \
- }
- #define FS_WRAP3(name, arg1conv, arg2conv, arg3conv, handler) \
- CAMLprim value w_ ## name(value loop, value arg1, value arg2, value arg3, value cb) { \
- CAMLparam5(loop, arg1, arg2, arg3, cb); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- UV_REQ_DATA(req) = (void *)cb; \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- 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)); \
- CAMLreturn(Val_unit); \
- } \
- CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2, value arg3) { \
- CAMLparam4(loop, arg1, arg2, arg3); \
- UV_ALLOC_CHECK(req, uv_fs_t); \
- caml_register_global_root(UV_REQ_DATA_A(req)); \
- 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)); \
- UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
- value ret = handler ## _sync(req); \
- uv_fs_req_cleanup(req); \
- free(req); \
- CAMLreturn(ret); \
- }
- /**
- FIXME:
- w_fs_read, w_fs_write, w_fs_read_sync, and w_fs_write_sync
- have a signature different from libuv due to no struct passing support in
- hashlink; currently only a single uv_buf_t can be passed at a time.
- **/
- /*
- 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) {
- UV_ALLOC_CHECK(req, uv_fs_t);
- UV_REQ_DATA(req) = (void *)cb;
- UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
- hl_add_root(UV_REQ_DATA(req));
- }
- HL_PRIM int HL_NAME(w_fs_read_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
- UV_ALLOC_CHECK(req, uv_fs_t);
- UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, NULL), free(req));
- return handle_fs_cb_int_sync(req);
- }
- 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) {
- UV_ALLOC_CHECK(req, uv_fs_t);
- UV_REQ_DATA(req) = (void *)cb;
- UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
- hl_add_root(UV_REQ_DATA(req));
- }
- HL_PRIM int HL_NAME(w_fs_write_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
- UV_ALLOC_CHECK(req, uv_fs_t);
- UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, NULL), free(req));
- return handle_fs_cb_int_sync(req);
- }
- */
- FS_WRAP1(fs_close, (uv_file), handle_fs_cb);
- FS_WRAP3(fs_open, String_val, (int), (int), handle_fs_cb_file);
- FS_WRAP1(fs_unlink, String_val, handle_fs_cb);
- FS_WRAP2(fs_mkdir, String_val, (int), handle_fs_cb);
- FS_WRAP1(fs_mkdtemp, String_val, handle_fs_cb_path);
- FS_WRAP1(fs_rmdir, String_val, handle_fs_cb);
- FS_WRAP2(fs_scandir, String_val, (int), handle_fs_cb_scandir);
- FS_WRAP1(fs_stat, String_val, handle_fs_cb_stat);
- FS_WRAP1(fs_fstat, (uv_file), handle_fs_cb_stat);
- FS_WRAP1(fs_lstat, String_val, handle_fs_cb_stat);
- FS_WRAP2(fs_rename, String_val, String_val, handle_fs_cb);
- FS_WRAP1(fs_fsync, (uv_file), handle_fs_cb);
- FS_WRAP1(fs_fdatasync, (uv_file), handle_fs_cb);
- FS_WRAP2(fs_ftruncate, (uv_file), Int64_val, handle_fs_cb);
- //FS_WRAP4(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, );
- FS_WRAP2(fs_access, String_val, (int), handle_fs_cb);
- FS_WRAP2(fs_chmod, String_val, (int), handle_fs_cb);
- FS_WRAP2(fs_fchmod, (uv_file), (int), handle_fs_cb);
- FS_WRAP3(fs_utime, String_val, Double_val, Double_val, handle_fs_cb);
- FS_WRAP3(fs_futime, (uv_file), Double_val, Double_val, handle_fs_cb);
- FS_WRAP2(fs_link, String_val, String_val, handle_fs_cb);
- FS_WRAP3(fs_symlink, String_val, String_val, (int), handle_fs_cb);
- FS_WRAP1(fs_readlink, String_val, handle_fs_cb_bytes);
- FS_WRAP1(fs_realpath, String_val, handle_fs_cb_bytes);
- FS_WRAP3(fs_chown, String_val, (uv_uid_t), (uv_gid_t), handle_fs_cb);
- FS_WRAP3(fs_fchown, (uv_file), (uv_uid_t), (uv_gid_t), handle_fs_cb);
|