From 293b2e4d06714b607eff87f151ddec6b3130124e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 17 May 2019 12:17:20 +0100 Subject: [PATCH 01/22] wip; parse fs.rst to produce libuv wrappers --- libs/uv/apiparse/Parse.hx | 58 ++++ libs/uv/apiparse/fs.rst | 629 ++++++++++++++++++++++++++++++++++++++ libs/uv/uv.c | 233 +++++++++++++- 3 files changed, 912 insertions(+), 8 deletions(-) create mode 100644 libs/uv/apiparse/Parse.hx create mode 100644 libs/uv/apiparse/fs.rst diff --git a/libs/uv/apiparse/Parse.hx b/libs/uv/apiparse/Parse.hx new file mode 100644 index 000000000..319b7dab9 --- /dev/null +++ b/libs/uv/apiparse/Parse.hx @@ -0,0 +1,58 @@ +import sys.io.File; + +using StringTools; + +class Parse { + public static function main():Void { + function getFunctions(path:String):Array { + return File.getContent(path).split("\n").filter(line -> line.startsWith(".. c:function:: ")); + } + var fsRE = ~/\.\. c:function:: int uv_fs_([^\(]+)\(uv_loop_t\* loop, uv_fs_t\* req, (([a-z\*\[\]_ 0-9]+, )+)uv_fs_cb cb\)/; + var wrap = []; + var haxe = []; + for (f in getFunctions("fs.rst")) { + if (!fsRE.match(f)) continue; + var name = fsRE.matched(1); + // skip functions that are not in 1.8.0 + // could parse ".. versionadded" but this is simpler + if ([ + "opendir", + "closedir", + "readdir", + "copyfile", + "lchown" + ].indexOf(name) != -1) continue; + var signature = fsRE.matched(2); + signature = signature.substr(0, signature.length - 2); // remove last comma + var ffi = []; + var haxeArgs = []; + var wrapArgs = [ for (arg in signature.split(", ")) { + var argSplit = arg.split(" "); + var argName = argSplit.pop(); + var argType = argSplit.join(" "); + var isArr = argName.endsWith("[]"); + if (isArr) argType += "*"; + var modArgs = (switch (argType) { + case "uv_file": ["_FILE", "file:UVFile"]; + case "uv_dir_t*": ["_DIR", "dir:UVDir"]; + case "const uv_buf_t*" if (isArr): ["_ARR", "_:hl.NativeArray"]; + case "uv_uid_t" | "uv_gid_t": ["_I32", "_:Int"]; // might be system specific? + + case "int" | "unsigned int": ["_I32", "_:Int"]; + case "int64_t" | "size_t": ["_I64", "_:hl.I64"]; + case "double": ["_F64", "_:Float"]; + case "const char*": ["_BYTES", "_:hl.Bytes"]; + + case _: throw argType; + }); + ffi.push(modArgs[0]); + haxeArgs.push(modArgs.length > 1 ? modArgs[1] : "_:Dynamic"); + argType; + } ]; + wrap.push('UV_WRAP${wrapArgs.length}(fs_$name, ${wrapArgs.join(", ")}, ${ffi.join(" ")});'); + haxe.push('@:hlNative("uv", "w_fs_$name") public static function fs_$name(loop:UVLoop, ${haxeArgs.join(", ")}, cb:UVError->Void):Void {}'); + } + Sys.println(wrap.join("\n")); + Sys.println(haxe.join("\n")); + } +} diff --git a/libs/uv/apiparse/fs.rst b/libs/uv/apiparse/fs.rst new file mode 100644 index 000000000..4200bf750 --- /dev/null +++ b/libs/uv/apiparse/fs.rst @@ -0,0 +1,629 @@ + +.. _fs: + +File system operations +====================== + +libuv provides a wide variety of cross-platform sync and async file system +operations. All functions defined in this document take a callback, which is +allowed to be NULL. If the callback is NULL the request is completed synchronously, +otherwise it will be performed asynchronously. + +All file operations are run on the threadpool. See :ref:`threadpool` for information +on the threadpool size. + +.. note:: + On Windows `uv_fs_*` functions use utf-8 encoding. + +Data types +---------- + +.. c:type:: uv_fs_t + + File system request type. + +.. c:type:: uv_timespec_t + + Portable equivalent of ``struct timespec``. + + :: + + typedef struct { + long tv_sec; + long tv_nsec; + } uv_timespec_t; + +.. c:type:: uv_stat_t + + Portable equivalent of ``struct stat``. + + :: + + typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_flags; + uint64_t st_gen; + uv_timespec_t st_atim; + uv_timespec_t st_mtim; + uv_timespec_t st_ctim; + uv_timespec_t st_birthtim; + } uv_stat_t; + +.. c:type:: uv_fs_type + + File system request type. + + :: + + typedef enum { + UV_FS_UNKNOWN = -1, + UV_FS_CUSTOM, + UV_FS_OPEN, + UV_FS_CLOSE, + UV_FS_READ, + UV_FS_WRITE, + UV_FS_SENDFILE, + UV_FS_STAT, + UV_FS_LSTAT, + UV_FS_FSTAT, + UV_FS_FTRUNCATE, + UV_FS_UTIME, + UV_FS_FUTIME, + UV_FS_ACCESS, + UV_FS_CHMOD, + UV_FS_FCHMOD, + UV_FS_FSYNC, + UV_FS_FDATASYNC, + UV_FS_UNLINK, + UV_FS_RMDIR, + UV_FS_MKDIR, + UV_FS_MKDTEMP, + UV_FS_RENAME, + UV_FS_SCANDIR, + UV_FS_LINK, + UV_FS_SYMLINK, + UV_FS_READLINK, + UV_FS_CHOWN, + UV_FS_FCHOWN, + UV_FS_REALPATH, + UV_FS_COPYFILE, + UV_FS_LCHOWN, + UV_FS_OPENDIR, + UV_FS_READDIR, + UV_FS_CLOSEDIR + } uv_fs_type; + +.. c:type:: uv_dirent_t + + Cross platform (reduced) equivalent of ``struct dirent``. + Used in :c:func:`uv_fs_scandir_next`. + + :: + + typedef enum { + UV_DIRENT_UNKNOWN, + UV_DIRENT_FILE, + UV_DIRENT_DIR, + UV_DIRENT_LINK, + UV_DIRENT_FIFO, + UV_DIRENT_SOCKET, + UV_DIRENT_CHAR, + UV_DIRENT_BLOCK + } uv_dirent_type_t; + + typedef struct uv_dirent_s { + const char* name; + uv_dirent_type_t type; + } uv_dirent_t; + +.. c:type:: uv_dir_t + + Data type used for streaming directory iteration. + Used by :c:func:`uv_fs_opendir()`, :c:func:`uv_fs_readdir()`, and + :c:func:`uv_fs_closedir()`. `dirents` represents a user provided array of + `uv_dirent_t`s used to hold results. `nentries` is the user provided maximum + array size of `dirents`. + + :: + + typedef struct uv_dir_s { + uv_dirent_t* dirents; + size_t nentries; + } uv_dir_t; + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_loop_t* uv_fs_t.loop + + Loop that started this request and where completion will be reported. + Readonly. + +.. c:member:: uv_fs_type uv_fs_t.fs_type + + FS request type. + +.. c:member:: const char* uv_fs_t.path + + Path affecting the request. + +.. c:member:: ssize_t uv_fs_t.result + + Result of the request. < 0 means error, success otherwise. On requests such + as :c:func:`uv_fs_read` or :c:func:`uv_fs_write` it indicates the amount of + data that was read or written, respectively. + +.. c:member:: uv_stat_t uv_fs_t.statbuf + + Stores the result of :c:func:`uv_fs_stat` and other stat requests. + +.. c:member:: void* uv_fs_t.ptr + + Stores the result of :c:func:`uv_fs_readlink` and + :c:func:`uv_fs_realpath` and serves as an alias to `statbuf`. + +.. seealso:: The :c:type:`uv_req_t` members also apply. + + +API +--- + +.. c:function:: void uv_fs_req_cleanup(uv_fs_t* req) + + Cleanup request. Must be called after a request is finished to deallocate + any memory libuv might have allocated. + +.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to :man:`close(2)`. + +.. c:function:: int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) + + Equivalent to :man:`open(2)`. + + .. note:: + On Windows libuv uses `CreateFileW` and thus the file is always opened + in binary mode. Because of this the O_BINARY and O_TEXT flags are not + supported. + +.. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) + + Equivalent to :man:`preadv(2)`. + +.. c:function:: int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`unlink(2)`. + +.. c:function:: int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) + + Equivalent to :man:`pwritev(2)`. + +.. c:function:: int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) + + Equivalent to :man:`mkdir(2)`. + + .. note:: + `mode` is currently not implemented on Windows. + +.. c:function:: int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb) + + Equivalent to :man:`mkdtemp(3)`. + + .. note:: + The result can be found as a null terminated string at `req->path`. + +.. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`rmdir(2)`. + +.. c:function:: int uv_fs_opendir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Opens `path` as a directory stream. On success, a `uv_dir_t` is allocated + and returned via `req->ptr`. This memory is not freed by + `uv_fs_req_cleanup()`, although `req->ptr` is set to `NULL`. The allocated + memory must be freed by calling `uv_fs_closedir()`. On failure, no memory + is allocated. + + The contents of the directory can be iterated over by passing the resulting + `uv_dir_t` to `uv_fs_readdir()`. + + .. versionadded:: 1.28.0 + +.. c:function:: int uv_fs_closedir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb) + + Closes the directory stream represented by `dir` and frees the memory + allocated by `uv_fs_opendir()`. + + .. versionadded:: 1.28.0 + +.. c:function:: int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb) + + Iterates over the directory stream, `dir`, returned by a successful + `uv_fs_opendir()` call. Prior to invoking `uv_fs_readdir()`, the caller + must set `dir->dirents` and `dir->nentries`, representing the array of + :c:type:`uv_dirent_t` elements used to hold the read directory entries and + its size. + + On success, the result is an integer >= 0 representing the number of entries + read from the stream. + + .. versionadded:: 1.28.0 + + .. warning:: + `uv_fs_readdir()` is not thread safe. + + .. note:: + This function does not return the "." and ".." entries. + + .. note:: + On success this function allocates memory that must be freed using + `uv_fs_req_cleanup()`. + +.. c:function:: int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) +.. c:function:: int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) + + Equivalent to :man:`scandir(3)`, with a slightly different API. Once the callback + for the request is called, the user can use :c:func:`uv_fs_scandir_next` to + get `ent` populated with the next directory entry data. When there are no + more entries ``UV_EOF`` will be returned. + + .. note:: + Unlike `scandir(3)`, this function does not return the "." and ".." entries. + + .. note:: + On Linux, getting the type of an entry is only supported by some file systems (btrfs, ext2, + ext3 and ext4 at the time of this writing), check the :man:`getdents(2)` man page. + +.. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) +.. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) +.. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`lstat(2)` respectively. + +.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) + + Equivalent to :man:`rename(2)`. + +.. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to :man:`fsync(2)`. + + .. note:: + For AIX, `uv_fs_fsync` returns `UV_EBADF` on file descriptors referencing + non regular files. + +.. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to :man:`fdatasync(2)`. + +.. c:function:: int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb) + + Equivalent to :man:`ftruncate(2)`. + +.. c:function:: int uv_fs_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) + + Copies a file from `path` to `new_path`. Supported `flags` are described below. + + - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with + `UV_EEXIST` if the destination path already exists. The default behavior + is to overwrite the destination if it exists. + - `UV_FS_COPYFILE_FICLONE`: If present, `uv_fs_copyfile()` will attempt to + create a copy-on-write reflink. If the underlying platform does not + support copy-on-write, then a fallback copy mechanism is used. + - `UV_FS_COPYFILE_FICLONE_FORCE`: If present, `uv_fs_copyfile()` will + attempt to create a copy-on-write reflink. If the underlying platform does + not support copy-on-write, then an error is returned. + + .. warning:: + If the destination path is created, but an error occurs while copying + the data, then the destination path is removed. There is a brief window + of time between closing and removing the file where another process + could access the file. + + .. versionadded:: 1.14.0 + + .. versionchanged:: 1.20.0 `UV_FS_COPYFILE_FICLONE` and + `UV_FS_COPYFILE_FICLONE_FORCE` are supported. + +.. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) + + Limited equivalent to :man:`sendfile(2)`. + +.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) + + Equivalent to :man:`access(2)` on Unix. Windows uses ``GetFileAttributesW()``. + +.. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) +.. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb) + + Equivalent to :man:`chmod(2)` and :man:`fchmod(2)` respectively. + +.. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) +.. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) + + Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively. + + .. note:: + AIX: This function only works for AIX 7.1 and newer. It can still be called on older + versions but will return ``UV_ENOSYS``. + + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows + +.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) + + Equivalent to :man:`link(2)`. + +.. c:function:: int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) + + Equivalent to :man:`symlink(2)`. + + .. note:: + On Windows the `flags` parameter can be specified to control how the symlink will + be created: + + * ``UV_FS_SYMLINK_DIR``: indicates that `path` points to a directory. + + * ``UV_FS_SYMLINK_JUNCTION``: request that the symlink is created + using junction points. + +.. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`readlink(2)`. + The resulting string is stored in `req->ptr`. + +.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle `_. + The resulting string is stored in `req->ptr`. + + .. warning:: + This function has certain platform-specific caveats that were discovered when used in Node. + + * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are + found while resolving the given path. This limit is hardcoded and cannot be sidestepped. + * Windows: while this function works in the common case, there are a number of corner cases + where it doesn't: + + - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) + cannot be resolved. + - Inconsistent casing when using drive letters. + - Resolved path bypasses subst'd drives. + + While this function can still be used, it's not recommended if scenarios such as the + above need to be supported. + + The background story and some more details on these issues can be checked + `here `_. + + .. note:: + This function is not implemented on Windows XP and Windows Server 2003. + On these systems, UV_ENOSYS is returned. + + .. versionadded:: 1.8.0 + +.. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) +.. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) +.. c:function:: int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) + + Equivalent to :man:`chown(2)`, :man:`fchown(2)` and :man:`lchown(2)` respectively. + + .. note:: + These functions are not implemented on Windows. + + .. versionchanged:: 1.21.0 implemented uv_fs_lchown + +.. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) + + Returns `req->fs_type`. + + .. versionadded:: 1.19.0 + +.. c:function:: ssize_t uv_fs_get_result(const uv_fs_t* req) + + Returns `req->result`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) + + Returns `req->ptr`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_fs_get_path(const uv_fs_t* req) + + Returns `req->path`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) + + Returns `&req->statbuf`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. + +Helper functions +---------------- + +.. c:function:: uv_os_fd_t uv_get_osfhandle(int fd) + + For a file descriptor in the C runtime, get the OS-dependent handle. + On UNIX, returns the ``fd`` intact. On Windows, this calls `_get_osfhandle `_. + Note that the return value is still owned by the C runtime, + any attempts to close it or to use it after closing the fd may lead to malfunction. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_open_osfhandle(uv_os_fd_t os_fd) + + For a OS-dependent handle, get the file descriptor in the C runtime. + On UNIX, returns the ``os_fd`` intact. On Windows, this calls `_open_osfhandle `_. + Note that the return value is still owned by the CRT, + any attempts to close it or to use it after closing the handle may lead to malfunction. + + .. versionadded:: 1.23.0 + +File open constants +------------------- + +.. c:macro:: UV_FS_O_APPEND + + The file is opened in append mode. Before each write, the file offset is + positioned at the end of the file. + +.. c:macro:: UV_FS_O_CREAT + + The file is created if it does not already exist. + +.. c:macro:: UV_FS_O_DIRECT + + File I/O is done directly to and from user-space buffers, which must be + aligned. Buffer size and address should be a multiple of the physical sector + size of the block device. + + .. note:: + `UV_FS_O_DIRECT` is supported on Linux, and on Windows via + `FILE_FLAG_NO_BUFFERING `_. + `UV_FS_O_DIRECT` is not supported on macOS. + +.. c:macro:: UV_FS_O_DIRECTORY + + If the path is not a directory, fail the open. + + .. note:: + `UV_FS_O_DIRECTORY` is not supported on Windows. + +.. c:macro:: UV_FS_O_DSYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and a minimum of metadata are flushed to disk. + + .. note:: + `UV_FS_O_DSYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_EXCL + + If the `O_CREAT` flag is set and the file already exists, fail the open. + + .. note:: + In general, the behavior of `O_EXCL` is undefined if it is used without + `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can + be used without `O_CREAT` if pathname refers to a block device. If the + block device is in use by the system (e.g., mounted), the open will fail + with the error `EBUSY`. + +.. c:macro:: UV_FS_O_EXLOCK + + Atomically obtain an exclusive lock. + + .. note:: + `UV_FS_O_EXLOCK` is only supported on macOS and Windows. + + .. versionchanged:: 1.17.0 support is added for Windows. + +.. c:macro:: UV_FS_O_NOATIME + + Do not update the file access time when the file is read. + + .. note:: + `UV_FS_O_NOATIME` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOCTTY + + If the path identifies a terminal device, opening the path will not cause + that terminal to become the controlling terminal for the process (if the + process does not already have one). + + .. note:: + `UV_FS_O_NOCTTY` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOFOLLOW + + If the path is a symbolic link, fail the open. + + .. note:: + `UV_FS_O_NOFOLLOW` is not supported on Windows. + +.. c:macro:: UV_FS_O_NONBLOCK + + Open the file in nonblocking mode if possible. + + .. note:: + `UV_FS_O_NONBLOCK` is not supported on Windows. + +.. c:macro:: UV_FS_O_RANDOM + + Access is intended to be random. The system can use this as a hint to + optimize file caching. + + .. note:: + `UV_FS_O_RANDOM` is only supported on Windows via + `FILE_FLAG_RANDOM_ACCESS `_. + +.. c:macro:: UV_FS_O_RDONLY + + Open the file for read-only access. + +.. c:macro:: UV_FS_O_RDWR + + Open the file for read-write access. + +.. c:macro:: UV_FS_O_SEQUENTIAL + + Access is intended to be sequential from beginning to end. The system can + use this as a hint to optimize file caching. + + .. note:: + `UV_FS_O_SEQUENTIAL` is only supported on Windows via + `FILE_FLAG_SEQUENTIAL_SCAN `_. + +.. c:macro:: UV_FS_O_SHORT_LIVED + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_SHORT_LIVED` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_SYMLINK + + Open the symbolic link itself rather than the resource it points to. + +.. c:macro:: UV_FS_O_SYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and all metadata are flushed to disk. + + .. note:: + `UV_FS_O_SYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_TEMPORARY + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_TEMPORARY` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_TRUNC + + If the file exists and is a regular file, and the file is opened + successfully for write access, its length shall be truncated to zero. + +.. c:macro:: UV_FS_O_WRONLY + + Open the file for write-only access. \ No newline at end of file diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 1273bb53b..bb1895216 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -11,7 +11,230 @@ # error "libuv1-dev required, uv version 0.x found" #endif +// ------------- TYPES ---------------------------------------------- + +// Handle types + +#define _LOOP _ABSTRACT(uv_loop_t) +#define _HANDLE _ABSTRACT(uv_handle_t) +#define _DIR _ABSTRACT(uv_dir_t) +#define _STREAM _ABSTRACT(uv_stream_t) +#define _TCP _HANDLE +//_ABSTRACT(uv_tcp_t) +#define _UDP _ABSTRACT(uv_udp_t) +#define _PIPE _ABSTRACT(uv_pipe_t) +#define _TTY _ABSTRACT(uv_tty_t) +#define _POLL _ABSTRACT(uv_poll_t) +#define _TIMER _ABSTRACT(uv_timer_t) +#define _PREPARE _ABSTRACT(uv_prepare_t) +#define _CHECK _ABSTRACT(uv_check_t) +#define _IDLE _ABSTRACT(uv_idle_t) +#define _ASYNC _ABSTRACT(uv_async_t) +#define _PROCESS _ABSTRACT(uv_process_t) +#define _FS_EVENT _ABSTRACT(uv_fs_event_t) +#define _FS_POLL _ABSTRACT(uv_fs_poll_t) +#define _SIGNAL _ABSTRACT(uv_signal_t) + +// Request types + +#define _REQ _ABSTRACT(uv_req_t) +#define _GETADDRINFO _ABSTRACT(uv_getaddrinfo_t) +#define _GETNAMEINFO _ABSTRACT(uv_getnameinfo_t) +#define _SHUTDOWN _ABSTRACT(uv_shutdown_t) +#define _WRITE _ABSTRACT(uv_write_t) +#define _CONNECT _ABSTRACT(uv_connect_t) +#define _UDP_SEND _ABSTRACT(uv_udp_send_t) +#define _FS _ABSTRACT(uv_fs_t) +#define _WORK _ABSTRACT(uv_work_t) + +// Other types + +#define _CPU_INFO _ABSTRACT(uv_cpu_info_t) +#define _INTERFACE_ADDRESS _ABSTRACT(uv_interface_address_t) +#define _DIRENT _ABSTRACT(uv_dirent_t) +#define _PASSWD _ABSTRACT(uv_passwd_t) +#define _UTSNAME _ABSTRACT(uv_utsname_t) +#define _FILE _ABSTRACT(uv_file) +#define _BUF _ABSTRACT(uv_buf_t) + +// Non-UV types + typedef struct sockaddr uv_sockaddr; +#define _SOCKADDR _ABSTRACT(uv_sockaddr) + +// Error type +#define _ERROR _OBJ(_OBJ(_BYTES _I32)) + +// ------------- UTILITY MACROS ------------------------------------- + +#define UV_HANDLE_DATA(h) (((uv_handle_t *)(h))->data) +#define UV_REQ_DATA(r) (((uv_req_t *)(r))->data) +#define UV_DATA(h) ((events_data *)((h)->data)) +#define UV_ALLOC(t) ((t *)malloc(sizeof(t))) + +// ------------- MEMORY MANAGEMENT ---------------------------------- +/* +static events_data *init_hl_data(void) { + events_data *d = hl_gc_alloc_raw(sizeof(events_data)); + memset(d,0,sizeof(events_data)); + return d; +} + +static void init_hl_data_handle(uv_handle_t *handle) { + UV_HANDLE_DATA(h) = init_hl_data(); + hl_add_root(&UV_HANDLE_DATA(h)); +} + +static void init_hl_data_req(uv_req_t *req) { + UV_REQ_DATA(h) = init_hl_data(); + hl_add_root(&UV_REQ_DATA(h)); +} + +static void clean_hl_data_handle(uv_handle_t *h) { + hl_remove_root(UV_HANDLE_DATA(h)); + UV_HANDLE_DATA(h) = NULL; + / * + events_data *ev = UV_DATA(h); + if( !ev ) return; + trigger_callb(h, EVT_CLOSE, NULL, 0, false); + free(ev->write_data); + hl_remove_root(&h->data); + h->data = NULL; + free(h); + * / +} + +static void clean_hl_data_req(uv_req_t *h) { + hl_remove_root(UV_REQ_DATA(h)); + UV_REQ_DATA(h) = NULL; +} +*/ + +// ------------- ERROR HANDLING ------------------------------------- + +static vdynamic * (*construct_error)(vbyte *); + +HL_PRIM void HL_NAME(glue_register_error)(vclosure *cb) { + construct_error = (vdynamic * (*)(vbyte *))cb->fun; +} + +DEFINE_PRIM(_VOID, glue_register_error, _FUN(_DYN, _BYTES)); + +#define UV_ALLOC_CHECK(var, type) \ + type *var = UV_ALLOC(type); \ + if (var == NULL) { \ + hl_throw(construct_error((vbyte *)"malloc " #type " failed")); \ + } else {} +#define UV_ERROR_CHECK(expr) do { \ + int __tmp_result = expr; \ + if (__tmp_result < 0) { \ + vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result))); \ + hl_throw(err); \ + } \ + } while (0) + +// ------------- LOOP ----------------------------------------------- + +HL_PRIM uv_loop_t * HL_NAME(w_loop_init)(void) { + UV_ALLOC_CHECK(loop, uv_loop_t); + UV_ERROR_CHECK(uv_loop_init(loop)); + return loop; +} + +HL_PRIM bool HL_NAME(w_loop_close)(uv_loop_t *loop) { + UV_ERROR_CHECK(uv_loop_close(loop)); + free(loop); + return true; +} + +HL_PRIM bool HL_NAME(w_run)(uv_loop_t *loop, uv_run_mode mode) { + return uv_run(loop, mode) == 0; +} + +HL_PRIM bool HL_NAME(w_loop_alive)(uv_loop_t *loop) { + return uv_loop_alive(loop) != 0; +} + +DEFINE_PRIM(_LOOP, w_loop_init, _NO_ARG); +// DEFINE_ PRIM(_I32, loop_configure, _LOOP ...); +DEFINE_PRIM(_BOOL, w_loop_close, _LOOP); +DEFINE_PRIM(_LOOP, default_loop, _NO_ARG); +DEFINE_PRIM(_BOOL, w_run, _LOOP _I32); +DEFINE_PRIM(_BOOL, w_loop_alive, _LOOP); +DEFINE_PRIM(_VOID, stop, _LOOP); + +// ------------- HANDLE --------------------------------------------- +// ------------- FILESYSTEM ----------------------------------------- + +void handle_fs_cb(uv_fs_t *req) { + int result = req->result; + vclosure *cb = (vclosure *)UV_REQ_DATA(req); + uv_fs_req_cleanup(req); + hl_remove_root(UV_REQ_DATA(req)); + free(req); + vdynamic *err = NULL; + if (result < 0) { + err = construct_error((vbyte *)strdup(uv_strerror(result))); + } + vdynamic **args = &err; + hl_dyn_call(cb, args, 1); +} + +#define UV_WRAP(name, sign, call, ffi) \ + HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t *loop, sign, vclosure *cb) { \ + UV_ALLOC_CHECK(req, uv_fs_t); \ + UV_REQ_DATA(req) = (void *)cb; \ + hl_add_root(UV_REQ_DATA(req)); \ + UV_ERROR_CHECK(uv_ ## name(loop, req, call, handle_fs_cb)); \ + } \ + DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi _FUN(_VOID, _ERROR)); + +#define COMMA , +#define UV_WRAP1(name, arg1, sign) \ + UV_WRAP(name, arg1 _arg1, _arg1, sign) +#define UV_WRAP2(name, arg1, arg2, sign) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign) +#define UV_WRAP3(name, arg1, arg2, arg3, sign) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign) +#define UV_WRAP4(name, arg1, arg2, arg3, arg4, sign) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign) + +UV_WRAP1(fs_close, uv_file, _FILE); +UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32); +UV_WRAP4(fs_read, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64); +UV_WRAP1(fs_unlink, const char*, _BYTES); +UV_WRAP4(fs_write, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64); +UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32); +UV_WRAP1(fs_mkdtemp, const char*, _BYTES); +UV_WRAP1(fs_rmdir, const char*, _BYTES); +UV_WRAP2(fs_scandir, const char*, int, _BYTES _I32); +UV_WRAP1(fs_stat, const char*, _BYTES); +UV_WRAP1(fs_fstat, uv_file, _FILE); +UV_WRAP1(fs_lstat, const char*, _BYTES); +UV_WRAP2(fs_rename, const char*, const char*, _BYTES _BYTES); +UV_WRAP1(fs_fsync, uv_file, _FILE); +UV_WRAP1(fs_fdatasync, uv_file, _FILE); +UV_WRAP2(fs_ftruncate, uv_file, int64_t, _FILE _I64); +UV_WRAP4(fs_sendfile, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64); +UV_WRAP2(fs_access, const char*, int, _BYTES _I32); +UV_WRAP2(fs_chmod, const char*, int, _BYTES _I32); +UV_WRAP2(fs_fchmod, uv_file, int, _FILE _I32); +UV_WRAP3(fs_utime, const char*, double, double, _BYTES _F64 _F64); +UV_WRAP3(fs_futime, uv_file, double, double, _FILE _F64 _F64); +UV_WRAP2(fs_link, const char*, const char*, _BYTES _BYTES); +UV_WRAP3(fs_symlink, const char*, const char*, int, _BYTES _BYTES _I32); +UV_WRAP1(fs_readlink, const char*, _BYTES); +UV_WRAP1(fs_realpath, const char*, _BYTES); +UV_WRAP3(fs_chown, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32); +UV_WRAP3(fs_fchown, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32); + +#undef UV_WRAP1 +#undef UV_WRAP2 +#undef UV_WRAP3 +#undef UV_WRAP +#undef COMMA + +/* #define EVT_CLOSE 1 @@ -28,12 +251,7 @@ typedef struct { void *write_data; } events_data; -#define UV_DATA(h) ((events_data*)((h)->data)) - -#define _LOOP _ABSTRACT(uv_loop) -#define _HANDLE _ABSTRACT(uv_handle) #define _CALLB _FUN(_VOID,_NO_ARG) -#define UV_ALLOC(t) ((t*)malloc(sizeof(t))) // HANDLE @@ -155,8 +373,6 @@ DEFINE_PRIM(_BOOL, stream_listen, _HANDLE _I32 _CALLB); // TCP -#define _TCP _HANDLE - HL_PRIM uv_tcp_t *HL_NAME(tcp_init_wrap)( uv_loop_t *loop ) { uv_tcp_t *t = UV_ALLOC(uv_tcp_t); if( uv_tcp_init(loop,t) < 0 ) { @@ -229,10 +445,11 @@ DEFINE_PRIM(_VOID, tcp_nodelay_wrap, _TCP _BOOL); // loop + DEFINE_PRIM(_LOOP, default_loop, _NO_ARG); DEFINE_PRIM(_I32, loop_close, _LOOP); DEFINE_PRIM(_I32, run, _LOOP _I32); DEFINE_PRIM(_I32, loop_alive, _LOOP); DEFINE_PRIM(_VOID, stop, _LOOP); - DEFINE_PRIM(_BYTES, strerror, _I32); +*/ From e2e448898962e793fae1ec032c356ab2d7a9f1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 17 May 2019 18:16:32 +0100 Subject: [PATCH 02/22] fs request callback data --- libs/uv/uv.c | 143 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index bb1895216..343a366c2 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -55,6 +55,7 @@ #define _PASSWD _ABSTRACT(uv_passwd_t) #define _UTSNAME _ABSTRACT(uv_utsname_t) #define _FILE _ABSTRACT(uv_file) +#define _STAT _ABSTRACT(uv_stat_t) #define _BUF _ABSTRACT(uv_buf_t) // Non-UV types @@ -166,73 +167,99 @@ DEFINE_PRIM(_VOID, stop, _LOOP); // ------------- HANDLE --------------------------------------------- // ------------- FILESYSTEM ----------------------------------------- -void handle_fs_cb(uv_fs_t *req) { - int result = req->result; - vclosure *cb = (vclosure *)UV_REQ_DATA(req); - uv_fs_req_cleanup(req); - hl_remove_root(UV_REQ_DATA(req)); - free(req); - vdynamic *err = NULL; - if (result < 0) { - err = construct_error((vbyte *)strdup(uv_strerror(result))); +#define UV_FS_HANDLER(name, n_args, setup) \ + void name(uv_fs_t *req) { \ + vdynamic *args[n_args] = {NULL}; \ + if (req->result < 0) \ + args[0] = construct_error((vbyte *)strdup(uv_strerror(req->result))); \ + else \ + setup \ + vclosure *cb = (vclosure *)UV_REQ_DATA(req); \ + uv_fs_req_cleanup(req); \ + hl_remove_root(UV_REQ_DATA(req)); \ + free(req); \ + hl_dyn_call(cb, args, n_args); \ } - vdynamic **args = &err; - hl_dyn_call(cb, args, 1); -} -#define UV_WRAP(name, sign, call, ffi) \ +UV_FS_HANDLER(handle_fs_cb, 1, {}); +UV_FS_HANDLER(handle_fs_cb_bytes, 2, { + puts("handling here"); + printf("path: %s\n", (char *)req->ptr); + args[1] = hl_alloc_dynamic(&hlt_bytes); + args[1]->v.ptr = hl_to_utf16((const char *)req->ptr); +}); +UV_FS_HANDLER(handle_fs_cb_path, 2, { + args[1] = hl_alloc_dynamic(&hlt_bytes); + args[1]->v.ptr = hl_to_utf16((const char *)req->path); +}); +UV_FS_HANDLER(handle_fs_cb_int, 2, { + args[1] = hl_alloc_dynamic(&hlt_i32); + args[1]->v.i = req->result; +}); + +UV_FS_HANDLER(handle_fs_cb_file, 2, { + // TODO: this doesn't work (cast problems?) + args[1] = hl_alloc_dynamic(&hlt_abstract); + args[1]->v.i = req->result; +}); +UV_FS_HANDLER(handle_fs_cb_stat, 2, { + args[1] = hl_alloc_dynamic(&hlt_abstract); + args[1]->v.ptr = &req->statbuf; +}); + +#define _CB _FUN(_VOID, _ERROR) +#define _CB_BYTES _FUN(_VOID, _ERROR _BYTES) +#define _CB_INT _FUN(_VOID, _ERROR _I32) +#define _CB_FILE _FUN(_VOID, _ERROR _FILE) +#define _CB_STAT _FUN(_VOID, _ERROR _STAT) + +#define UV_WRAP(name, sign, call, ffi, handler) \ HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t *loop, sign, vclosure *cb) { \ UV_ALLOC_CHECK(req, uv_fs_t); \ UV_REQ_DATA(req) = (void *)cb; \ hl_add_root(UV_REQ_DATA(req)); \ - UV_ERROR_CHECK(uv_ ## name(loop, req, call, handle_fs_cb)); \ + UV_ERROR_CHECK(uv_ ## name(loop, req, call, handler)); \ } \ - DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi _FUN(_VOID, _ERROR)); + DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi); #define COMMA , -#define UV_WRAP1(name, arg1, sign) \ - UV_WRAP(name, arg1 _arg1, _arg1, sign) -#define UV_WRAP2(name, arg1, arg2, sign) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign) -#define UV_WRAP3(name, arg1, arg2, arg3, sign) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign) -#define UV_WRAP4(name, arg1, arg2, arg3, arg4, sign) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign) - -UV_WRAP1(fs_close, uv_file, _FILE); -UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32); -UV_WRAP4(fs_read, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64); -UV_WRAP1(fs_unlink, const char*, _BYTES); -UV_WRAP4(fs_write, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64); -UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32); -UV_WRAP1(fs_mkdtemp, const char*, _BYTES); -UV_WRAP1(fs_rmdir, const char*, _BYTES); -UV_WRAP2(fs_scandir, const char*, int, _BYTES _I32); -UV_WRAP1(fs_stat, const char*, _BYTES); -UV_WRAP1(fs_fstat, uv_file, _FILE); -UV_WRAP1(fs_lstat, const char*, _BYTES); -UV_WRAP2(fs_rename, const char*, const char*, _BYTES _BYTES); -UV_WRAP1(fs_fsync, uv_file, _FILE); -UV_WRAP1(fs_fdatasync, uv_file, _FILE); -UV_WRAP2(fs_ftruncate, uv_file, int64_t, _FILE _I64); -UV_WRAP4(fs_sendfile, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64); -UV_WRAP2(fs_access, const char*, int, _BYTES _I32); -UV_WRAP2(fs_chmod, const char*, int, _BYTES _I32); -UV_WRAP2(fs_fchmod, uv_file, int, _FILE _I32); -UV_WRAP3(fs_utime, const char*, double, double, _BYTES _F64 _F64); -UV_WRAP3(fs_futime, uv_file, double, double, _FILE _F64 _F64); -UV_WRAP2(fs_link, const char*, const char*, _BYTES _BYTES); -UV_WRAP3(fs_symlink, const char*, const char*, int, _BYTES _BYTES _I32); -UV_WRAP1(fs_readlink, const char*, _BYTES); -UV_WRAP1(fs_realpath, const char*, _BYTES); -UV_WRAP3(fs_chown, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32); -UV_WRAP3(fs_fchown, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32); - -#undef UV_WRAP1 -#undef UV_WRAP2 -#undef UV_WRAP3 -#undef UV_WRAP -#undef COMMA +#define UV_WRAP1(name, arg1, sign, handler) \ + UV_WRAP(name, arg1 _arg1, _arg1, sign, handler) +#define UV_WRAP2(name, arg1, arg2, sign, handler) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign, handler) +#define UV_WRAP3(name, arg1, arg2, arg3, sign, handler) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign, handler) +#define UV_WRAP4(name, arg1, arg2, arg3, arg4, sign, handler) \ + UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign, handler) + +UV_WRAP1(fs_close, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); +UV_WRAP4(fs_read, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64 _CB_INT, handle_fs_cb_int); +UV_WRAP1(fs_unlink, const char*, _BYTES _CB, handle_fs_cb); +UV_WRAP4(fs_write, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64 _CB_INT, handle_fs_cb_int); +UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP1(fs_mkdtemp, const char*, _BYTES _CB_BYTES, handle_fs_cb_path); +UV_WRAP1(fs_rmdir, const char*, _BYTES _CB, handle_fs_cb); +UV_WRAP2(fs_scandir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP1(fs_stat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); +UV_WRAP1(fs_fstat, uv_file, _FILE _CB_STAT, handle_fs_cb_stat); +UV_WRAP1(fs_lstat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); +UV_WRAP2(fs_rename, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); +UV_WRAP1(fs_fsync, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP1(fs_fdatasync, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP2(fs_ftruncate, uv_file, int64_t, _FILE _I64 _CB, handle_fs_cb); +UV_WRAP4(fs_sendfile, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64 _CB, handle_fs_cb); +UV_WRAP2(fs_access, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP2(fs_chmod, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP2(fs_fchmod, uv_file, int, _FILE _I32 _CB, handle_fs_cb); +UV_WRAP3(fs_utime, const char*, double, double, _BYTES _F64 _F64 _CB, handle_fs_cb); +UV_WRAP3(fs_futime, uv_file, double, double, _FILE _F64 _F64 _CB, handle_fs_cb); +UV_WRAP2(fs_link, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); +UV_WRAP3(fs_symlink, const char*, const char*, int, _BYTES _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP1(fs_readlink, const char*, _BYTES _CB_BYTES, handle_fs_cb_bytes); +UV_WRAP1(fs_realpath, const char*, _BYTES _CB_BYTES, handle_fs_cb_bytes); +UV_WRAP3(fs_chown, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32 _CB, handle_fs_cb); +UV_WRAP3(fs_fchown, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32 _CB, handle_fs_cb); /* From 6fb9e3b30d568ce88a23ed82831a9ac29af46c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 21 May 2019 12:03:42 +0100 Subject: [PATCH 03/22] fs read, write, stat --- libs/uv/tmp.txt | 29 ++++++++++++ libs/uv/uv.c | 115 +++++++++++++++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 libs/uv/tmp.txt diff --git a/libs/uv/tmp.txt b/libs/uv/tmp.txt new file mode 100644 index 000000000..3d5726c0a --- /dev/null +++ b/libs/uv/tmp.txt @@ -0,0 +1,29 @@ +HL_PRIM void HL_NAME(w_test)() { + puts("constants:"); +#define SHOW(c) printf(#c ": %x\n", c) + + SHOW(O_APPEND); + SHOW(O_CREAT); + SHOW(O_DIRECT); + SHOW(O_DIRECTORY); + SHOW(O_DSYNC); + SHOW(O_EXCL); + //SHOW(O_EXLOCK); + SHOW(O_NOATIME); + SHOW(O_NOCTTY); + SHOW(O_NOFOLLOW); + SHOW(O_NONBLOCK); + //SHOW(O_RANDOM); // win only? + SHOW(O_RDONLY); + SHOW(O_RDWR); + //SHOW(O_SEQUENTIAL); // win only? + //SHOW(O_SHORT_LIVED); // win only? + //SHOW(O_SYMLINK); + SHOW(O_SYNC); + //SHOW(O_TEMPORARY); // win only? + SHOW(O_TRUNC); + SHOW(O_WRONLY); + +#undef SHOW +} +DEFINE_PRIM(_VOID, w_test, _NO_ARG); \ No newline at end of file diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 343a366c2..8edc11611 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -5,6 +5,7 @@ #else # include # include +# include #endif #if (UV_VERSION_MAJOR <= 0) @@ -55,7 +56,7 @@ #define _PASSWD _ABSTRACT(uv_passwd_t) #define _UTSNAME _ABSTRACT(uv_utsname_t) #define _FILE _ABSTRACT(uv_file) -#define _STAT _ABSTRACT(uv_stat_t) +// #define _STAT _ABSTRACT(uv_stat_t) #define _BUF _ABSTRACT(uv_buf_t) // Non-UV types @@ -63,8 +64,9 @@ typedef struct sockaddr uv_sockaddr; #define _SOCKADDR _ABSTRACT(uv_sockaddr) -// Error type +// Haxe types #define _ERROR _OBJ(_OBJ(_BYTES _I32)) +#define _STAT _OBJ(_I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) // ------------- UTILITY MACROS ------------------------------------- @@ -114,12 +116,13 @@ static void clean_hl_data_req(uv_req_t *h) { // ------------- ERROR HANDLING ------------------------------------- static vdynamic * (*construct_error)(vbyte *); +static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); -HL_PRIM void HL_NAME(glue_register_error)(vclosure *cb) { - construct_error = (vdynamic * (*)(vbyte *))cb->fun; +HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat) { + construct_error = (vdynamic * (*)(vbyte *))c_error->fun; + construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; } - -DEFINE_PRIM(_VOID, glue_register_error, _FUN(_DYN, _BYTES)); +DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32)); #define UV_ALLOC_CHECK(var, type) \ type *var = UV_ALLOC(type); \ @@ -164,48 +167,62 @@ DEFINE_PRIM(_BOOL, w_run, _LOOP _I32); DEFINE_PRIM(_BOOL, w_loop_alive, _LOOP); DEFINE_PRIM(_VOID, stop, _LOOP); +// ------------- MISC ----------------------------------------------- + +HL_PRIM uv_buf_t *HL_NAME(w_buf_init)(vbyte *bytes, unsigned int length) { + uv_buf_t *ptr = (uv_buf_t *)hl_gc_alloc_noptr(sizeof(uv_buf_t)); + *ptr = uv_buf_init((char *)bytes, length); + return ptr; +} +DEFINE_PRIM(_BUF, w_buf_init, _BYTES _I32); + // ------------- HANDLE --------------------------------------------- // ------------- FILESYSTEM ----------------------------------------- -#define UV_FS_HANDLER(name, n_args, setup) \ +void handle_fs_cb(uv_fs_t *req) { + vclosure *cb = UV_REQ_DATA(req); + if (req->result < 0) + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)))); + else + hl_call1(void, cb, vdynamic *, NULL); + uv_fs_req_cleanup(req); + hl_remove_root(UV_REQ_DATA(req)); + free(req); +} + +#define UV_FS_HANDLER(name, type2, setup) \ void name(uv_fs_t *req) { \ - vdynamic *args[n_args] = {NULL}; \ + vclosure *cb = UV_REQ_DATA(req); \ if (req->result < 0) \ - args[0] = construct_error((vbyte *)strdup(uv_strerror(req->result))); \ - else \ - setup \ - vclosure *cb = (vclosure *)UV_REQ_DATA(req); \ + hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result))), type2, (type2)0); \ + else { \ + type2 value2; \ + setup; \ + hl_call2(void, cb, vdynamic *, NULL, type2, value2); \ + } \ uv_fs_req_cleanup(req); \ hl_remove_root(UV_REQ_DATA(req)); \ free(req); \ - hl_dyn_call(cb, args, n_args); \ } -UV_FS_HANDLER(handle_fs_cb, 1, {}); -UV_FS_HANDLER(handle_fs_cb_bytes, 2, { - puts("handling here"); - printf("path: %s\n", (char *)req->ptr); - args[1] = hl_alloc_dynamic(&hlt_bytes); - args[1]->v.ptr = hl_to_utf16((const char *)req->ptr); -}); -UV_FS_HANDLER(handle_fs_cb_path, 2, { - args[1] = hl_alloc_dynamic(&hlt_bytes); - args[1]->v.ptr = hl_to_utf16((const char *)req->path); -}); -UV_FS_HANDLER(handle_fs_cb_int, 2, { - args[1] = hl_alloc_dynamic(&hlt_i32); - args[1]->v.i = req->result; -}); - -UV_FS_HANDLER(handle_fs_cb_file, 2, { - // TODO: this doesn't work (cast problems?) - args[1] = hl_alloc_dynamic(&hlt_abstract); - args[1]->v.i = req->result; -}); -UV_FS_HANDLER(handle_fs_cb_stat, 2, { - args[1] = hl_alloc_dynamic(&hlt_abstract); - args[1]->v.ptr = &req->statbuf; -}); +UV_FS_HANDLER(handle_fs_cb_bytes, vbyte *, value2 = (vbyte *)hl_to_utf16((const char *)req->ptr)); +UV_FS_HANDLER(handle_fs_cb_path, vbyte *, value2 = (vbyte *)hl_to_utf16((const char *)req->path)); +UV_FS_HANDLER(handle_fs_cb_int, int, value2 = req->result); +UV_FS_HANDLER(handle_fs_cb_file, uv_file, value2 = req->result); +UV_FS_HANDLER(handle_fs_cb_stat, vdynamic *, value2 = construct_fs_stat( + req->statbuf.st_dev, + req->statbuf.st_mode, + req->statbuf.st_nlink, + req->statbuf.st_uid, + req->statbuf.st_gid, + req->statbuf.st_rdev, + req->statbuf.st_ino, + req->statbuf.st_size, + req->statbuf.st_blksize, + req->statbuf.st_blocks, + req->statbuf.st_flags, + req->statbuf.st_gen + )); #define _CB _FUN(_VOID, _ERROR) #define _CB_BYTES _FUN(_VOID, _ERROR _BYTES) @@ -232,11 +249,29 @@ UV_FS_HANDLER(handle_fs_cb_stat, 2, { #define UV_WRAP4(name, arg1, arg2, arg3, arg4, sign, handler) \ UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign, handler) +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) { + // note: signature different due to no struct passing support in HL + // currently only a single uv_buf_t can be passed at a time + UV_ALLOC_CHECK(req, uv_fs_t); + UV_REQ_DATA(req) = (void *)cb; + hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK(uv_fs_read(loop, req, file, buf, 1, offset, handle_fs_cb_int)); +} +DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); + +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) { + // note: signature different due to no struct passing support in HL + // currently only a single uv_buf_t can be passed at a time + UV_ALLOC_CHECK(req, uv_fs_t); + UV_REQ_DATA(req) = (void *)cb; + hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK(uv_fs_write(loop, req, file, buf, 1, offset, handle_fs_cb_int)); +} +DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); + UV_WRAP1(fs_close, uv_file, _FILE _CB, handle_fs_cb); UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); -UV_WRAP4(fs_read, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64 _CB_INT, handle_fs_cb_int); UV_WRAP1(fs_unlink, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP4(fs_write, uv_file, const uv_buf_t*, unsigned int, int64_t, _FILE _ARR _I32 _I64 _CB_INT, handle_fs_cb_int); UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); UV_WRAP1(fs_mkdtemp, const char*, _BYTES _CB_BYTES, handle_fs_cb_path); UV_WRAP1(fs_rmdir, const char*, _BYTES _CB, handle_fs_cb); From 917f93cc25eb01707b1351f1f122c0aad6fc7f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 21 May 2019 13:02:36 +0100 Subject: [PATCH 04/22] scandir --- libs/uv/uv.c | 35 ++++++++++++++++++++++++++++++++--- src/hl.h | 5 +++++ src/std/buffer.c | 5 ----- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 8edc11611..58d6bd538 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -117,12 +117,14 @@ static void clean_hl_data_req(uv_req_t *h) { static vdynamic * (*construct_error)(vbyte *); static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); +static vdynamic * (*construct_fs_dirent)(const char *name, int); -HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat) { +HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat, vclosure *c_fs_dirent) { construct_error = (vdynamic * (*)(vbyte *))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; + construct_fs_dirent = (vdynamic * (*)(const char *, int))c_fs_dirent->fun; } -DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32)); +DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32)); #define UV_ALLOC_CHECK(var, type) \ type *var = UV_ALLOC(type); \ @@ -223,12 +225,32 @@ UV_FS_HANDLER(handle_fs_cb_stat, vdynamic *, value2 = construct_fs_stat( req->statbuf.st_flags, req->statbuf.st_gen )); +UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { + uv_dirent_t ent; + vlist *last = NULL; + int count = 0; + while (uv_fs_scandir_next(req, &ent) != UV_EOF) { + count++; + vlist *node = (vlist *)malloc(sizeof(vlist)); + node->v = construct_fs_dirent(ent.name, ent.type); + node->next = last; + last = node; + } + value2 = hl_alloc_array(&hlt_dyn, count); + for (int i = 0; i < count; i++) { + hl_aptr(value2, vdynamic *)[i] = last->v; + vlist *next = last->next; + free(last); + last = next; + } + }); #define _CB _FUN(_VOID, _ERROR) #define _CB_BYTES _FUN(_VOID, _ERROR _BYTES) #define _CB_INT _FUN(_VOID, _ERROR _I32) #define _CB_FILE _FUN(_VOID, _ERROR _FILE) #define _CB_STAT _FUN(_VOID, _ERROR _STAT) +#define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) #define UV_WRAP(name, sign, call, ffi, handler) \ HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t *loop, sign, vclosure *cb) { \ @@ -269,13 +291,20 @@ HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, const uv_buf_t * } DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); +HL_PRIM void HL_NAME(w_fs_scandir)(uv_loop_t *loop, const char *path, int flags, vclosure *cb) { + UV_ALLOC_CHECK(req, uv_fs_t); + UV_REQ_DATA(req) = (void *)cb; + hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK(uv_fs_scandir(loop, req, path, flags, handle_fs_cb_scandir)); +} +DEFINE_PRIM(_VOID, w_fs_scandir, _LOOP _BYTES _I32 _CB_SCANDIR); + UV_WRAP1(fs_close, uv_file, _FILE _CB, handle_fs_cb); UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); UV_WRAP1(fs_unlink, const char*, _BYTES _CB, handle_fs_cb); UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); UV_WRAP1(fs_mkdtemp, const char*, _BYTES _CB_BYTES, handle_fs_cb_path); UV_WRAP1(fs_rmdir, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP2(fs_scandir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); UV_WRAP1(fs_stat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); UV_WRAP1(fs_fstat, uv_file, _FILE _CB_STAT, handle_fs_cb_stat); UV_WRAP1(fs_lstat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); diff --git a/src/hl.h b/src/hl.h index 744208fa5..72533687c 100644 --- a/src/hl.h +++ b/src/hl.h @@ -542,6 +542,11 @@ typedef struct _venum { int index; } venum; +typedef struct vlist { + vdynamic *v; + struct vlist *next; +} vlist; + HL_API hl_type hlt_void; HL_API hl_type hlt_i32; HL_API hl_type hlt_i64; diff --git a/src/std/buffer.c b/src/std/buffer.c index 7fb2360c3..0e649efce 100644 --- a/src/std/buffer.c +++ b/src/std/buffer.c @@ -130,11 +130,6 @@ int hl_buffer_length( hl_buffer *b ) { return b->totlen; } -typedef struct vlist { - vdynamic *v; - struct vlist *next; -} vlist; - static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack ); static void hl_buffer_addr( hl_buffer *b, void *data, hl_type *t, vlist *stack ) { From 22975766350aa7e0abfa75c5a625e1d5dddfd1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Wed, 22 May 2019 17:38:39 +0100 Subject: [PATCH 05/22] TCP, streams --- libs/uv/uv.c | 493 +++++++++++++++++++++++---------------------------- 1 file changed, 219 insertions(+), 274 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 58d6bd538..8fe652f70 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -20,8 +20,7 @@ #define _HANDLE _ABSTRACT(uv_handle_t) #define _DIR _ABSTRACT(uv_dir_t) #define _STREAM _ABSTRACT(uv_stream_t) -#define _TCP _HANDLE -//_ABSTRACT(uv_tcp_t) +#define _TCP _ABSTRACT(uv_tcp_t) #define _UDP _ABSTRACT(uv_udp_t) #define _PIPE _ABSTRACT(uv_pipe_t) #define _TTY _ABSTRACT(uv_tty_t) @@ -59,59 +58,32 @@ // #define _STAT _ABSTRACT(uv_stat_t) #define _BUF _ABSTRACT(uv_buf_t) -// Non-UV types - -typedef struct sockaddr uv_sockaddr; -#define _SOCKADDR _ABSTRACT(uv_sockaddr) - // Haxe types + #define _ERROR _OBJ(_OBJ(_BYTES _I32)) #define _STAT _OBJ(_I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) +// Callback types + +#define _CB _FUN(_VOID, _ERROR) +#define _CB_STR _FUN(_VOID, _ERROR _BYTES) +#define _CB_BYTES _FUN(_VOID, _ERROR _BYTES _I32) +#define _CB_INT _FUN(_VOID, _ERROR _I32) +#define _CB_FILE _FUN(_VOID, _ERROR _FILE) +#define _CB_STAT _FUN(_VOID, _ERROR _STAT) +#define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) + // ------------- 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_DATA(h) ((events_data *)((h)->data)) -#define UV_ALLOC(t) ((t *)malloc(sizeof(t))) -// ------------- MEMORY MANAGEMENT ---------------------------------- -/* -static events_data *init_hl_data(void) { - events_data *d = hl_gc_alloc_raw(sizeof(events_data)); - memset(d,0,sizeof(events_data)); - return d; -} +//# define UV_DATA(h) ((events_data *)((h)->data)) -static void init_hl_data_handle(uv_handle_t *handle) { - UV_HANDLE_DATA(h) = init_hl_data(); - hl_add_root(&UV_HANDLE_DATA(h)); -} - -static void init_hl_data_req(uv_req_t *req) { - UV_REQ_DATA(h) = init_hl_data(); - hl_add_root(&UV_REQ_DATA(h)); -} - -static void clean_hl_data_handle(uv_handle_t *h) { - hl_remove_root(UV_HANDLE_DATA(h)); - UV_HANDLE_DATA(h) = NULL; - / * - events_data *ev = UV_DATA(h); - if( !ev ) return; - trigger_callb(h, EVT_CLOSE, NULL, 0, false); - free(ev->write_data); - hl_remove_root(&h->data); - h->data = NULL; - free(h); - * / -} - -static void clean_hl_data_req(uv_req_t *h) { - hl_remove_root(UV_REQ_DATA(h)); - UV_REQ_DATA(h) = NULL; -} -*/ +#define UV_ALLOC(t) ((t *)malloc(sizeof(t))) +#define UV_GC_ALLOC(t) ((t *)hl_gc_alloc_noptr(sizeof(t))) // ------------- ERROR HANDLING ------------------------------------- @@ -131,6 +103,12 @@ DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _ if (var == NULL) { \ hl_throw(construct_error((vbyte *)"malloc " #type " failed")); \ } else {} +#define UV_ALLOC_CHECK_C(var, type, cleanup) \ + type *var = UV_ALLOC(type); \ + if (var == NULL) { \ + cleanup; \ + hl_throw(construct_error((vbyte *)"malloc " #type " failed")); \ + } else {} #define UV_ERROR_CHECK(expr) do { \ int __tmp_result = expr; \ if (__tmp_result < 0) { \ @@ -138,12 +116,20 @@ DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _ hl_throw(err); \ } \ } while (0) +#define UV_ERROR_CHECK_C(expr, cleanup) do { \ + int __tmp_result = expr; \ + if (__tmp_result < 0) { \ + cleanup; \ + vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result))); \ + hl_throw(err); \ + } \ + } while (0) // ------------- LOOP ----------------------------------------------- HL_PRIM uv_loop_t * HL_NAME(w_loop_init)(void) { UV_ALLOC_CHECK(loop, uv_loop_t); - UV_ERROR_CHECK(uv_loop_init(loop)); + UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop)); return loop; } @@ -172,13 +158,35 @@ DEFINE_PRIM(_VOID, stop, _LOOP); // ------------- MISC ----------------------------------------------- HL_PRIM uv_buf_t *HL_NAME(w_buf_init)(vbyte *bytes, unsigned int length) { - uv_buf_t *ptr = (uv_buf_t *)hl_gc_alloc_noptr(sizeof(uv_buf_t)); - *ptr = uv_buf_init((char *)bytes, length); - return ptr; + uv_buf_t *ptr = UV_GC_ALLOC(uv_buf_t); + *ptr = uv_buf_init((char *)bytes, length); + return ptr; } + DEFINE_PRIM(_BUF, w_buf_init, _BYTES _I32); // ------------- HANDLE --------------------------------------------- + +typedef struct { + vclosure *cb_close; +} uv_w_handle_t; + +void handle_handle_cb_close(uv_handle_t *handle) { + vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_handle_t)->cb_close; + hl_call1(void, cb, vdynamic *, NULL); + free(UV_HANDLE_DATA(handle)); + free(handle); +} + +static void w_close(uv_handle_t *handle, vclosure *cb) { + UV_HANDLE_DATA_SUB(handle, uv_w_handle_t)->cb_close = cb; + uv_close(handle, handle_handle_cb_close); +} + +//DEFINE_PRIM(_VOID, ref, _HANDLE); +//DEFINE_PRIM(_VOID, unref, _HANDLE); +//DEFINE_PRIM(_VOID, w_close, _HANDLE _CB); + // ------------- FILESYSTEM ----------------------------------------- void handle_fs_cb(uv_fs_t *req) { @@ -245,302 +253,239 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { } }); -#define _CB _FUN(_VOID, _ERROR) -#define _CB_BYTES _FUN(_VOID, _ERROR _BYTES) -#define _CB_INT _FUN(_VOID, _ERROR _I32) -#define _CB_FILE _FUN(_VOID, _ERROR _FILE) -#define _CB_STAT _FUN(_VOID, _ERROR _STAT) -#define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) - -#define UV_WRAP(name, sign, call, ffi, handler) \ +#define UV_REQ_WRAP(name, reqtype, sign, call, ffi, handler) \ + HL_PRIM void HL_NAME(w_ ## name)(sign, vclosure *cb) { \ + UV_ALLOC_CHECK(req, reqtype); \ + UV_REQ_DATA(req) = (void *)cb; \ + UV_ERROR_CHECK_C(uv_ ## name(req, call, handler), free(req)); \ + hl_add_root(UV_REQ_DATA(req)); \ + } \ + DEFINE_PRIM(_VOID, w_ ## name, ffi); +#define UV_REQ_WRAP_LOOP(name, reqtype, sign, call, ffi, handler) \ HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t *loop, sign, vclosure *cb) { \ - UV_ALLOC_CHECK(req, uv_fs_t); \ + UV_ALLOC_CHECK(req, reqtype); \ UV_REQ_DATA(req) = (void *)cb; \ + UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, handler), free(req)); \ hl_add_root(UV_REQ_DATA(req)); \ - UV_ERROR_CHECK(uv_ ## name(loop, req, call, handler)); \ } \ DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi); #define COMMA , -#define UV_WRAP1(name, arg1, sign, handler) \ - UV_WRAP(name, arg1 _arg1, _arg1, sign, handler) -#define UV_WRAP2(name, arg1, arg2, sign, handler) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign, handler) -#define UV_WRAP3(name, arg1, arg2, arg3, sign, handler) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign, handler) -#define UV_WRAP4(name, arg1, arg2, arg3, arg4, sign, handler) \ - UV_WRAP(name, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign, handler) +#define UV_WRAP1_LOOP(name, reqtype, arg1, sign, handler) \ + UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1, _arg1, sign, handler) +#define UV_WRAP2_LOOP(name, reqtype, arg1, arg2, sign, handler) \ + UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign, handler) +#define UV_WRAP3_LOOP(name, reqtype, arg1, arg2, arg3, sign, handler) \ + UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign, handler) +#define UV_WRAP4_LOOP(name, reqtype, arg1, arg2, arg3, arg4, sign, handler) \ + UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign, handler) 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) { // note: signature different due to no struct passing support in HL // currently only a single uv_buf_t can be passed at a time 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)); - UV_ERROR_CHECK(uv_fs_read(loop, req, file, buf, 1, offset, handle_fs_cb_int)); } -DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); 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) { // note: signature different due to no struct passing support in HL // currently only a single uv_buf_t can be passed at a time 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)); - UV_ERROR_CHECK(uv_fs_write(loop, req, file, buf, 1, offset, handle_fs_cb_int)); } -DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); HL_PRIM void HL_NAME(w_fs_scandir)(uv_loop_t *loop, const char *path, int flags, vclosure *cb) { UV_ALLOC_CHECK(req, uv_fs_t); UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_fs_scandir(loop, req, path, flags, handle_fs_cb_scandir), free(req)); hl_add_root(UV_REQ_DATA(req)); - UV_ERROR_CHECK(uv_fs_scandir(loop, req, path, flags, handle_fs_cb_scandir)); } + DEFINE_PRIM(_VOID, w_fs_scandir, _LOOP _BYTES _I32 _CB_SCANDIR); +DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); +DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); -UV_WRAP1(fs_close, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP3(fs_open, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); -UV_WRAP1(fs_unlink, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP2(fs_mkdir, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP1(fs_mkdtemp, const char*, _BYTES _CB_BYTES, handle_fs_cb_path); -UV_WRAP1(fs_rmdir, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP1(fs_stat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); -UV_WRAP1(fs_fstat, uv_file, _FILE _CB_STAT, handle_fs_cb_stat); -UV_WRAP1(fs_lstat, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); -UV_WRAP2(fs_rename, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); -UV_WRAP1(fs_fsync, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP1(fs_fdatasync, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP2(fs_ftruncate, uv_file, int64_t, _FILE _I64 _CB, handle_fs_cb); -UV_WRAP4(fs_sendfile, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64 _CB, handle_fs_cb); -UV_WRAP2(fs_access, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP2(fs_chmod, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP2(fs_fchmod, uv_file, int, _FILE _I32 _CB, handle_fs_cb); -UV_WRAP3(fs_utime, const char*, double, double, _BYTES _F64 _F64 _CB, handle_fs_cb); -UV_WRAP3(fs_futime, uv_file, double, double, _FILE _F64 _F64 _CB, handle_fs_cb); -UV_WRAP2(fs_link, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); -UV_WRAP3(fs_symlink, const char*, const char*, int, _BYTES _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP1(fs_readlink, const char*, _BYTES _CB_BYTES, handle_fs_cb_bytes); -UV_WRAP1(fs_realpath, const char*, _BYTES _CB_BYTES, handle_fs_cb_bytes); -UV_WRAP3(fs_chown, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32 _CB, handle_fs_cb); -UV_WRAP3(fs_fchown, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32 _CB, handle_fs_cb); - -/* - -#define EVT_CLOSE 1 - -#define EVT_READ 0 // stream -#define EVT_LISTEN 2 // stream - -#define EVT_WRITE 0 // write_t -#define EVT_CONNECT 0 // connect_t - -#define EVT_MAX 2 +UV_WRAP1_LOOP(fs_close, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP3_LOOP(fs_open, uv_fs_t, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); +UV_WRAP1_LOOP(fs_unlink, uv_fs_t, const char*, _BYTES _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_mkdir, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP1_LOOP(fs_mkdtemp, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_path); +UV_WRAP1_LOOP(fs_rmdir, uv_fs_t, const char*, _BYTES _CB, handle_fs_cb); +UV_WRAP1_LOOP(fs_stat, uv_fs_t, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); +UV_WRAP1_LOOP(fs_fstat, uv_fs_t, uv_file, _FILE _CB_STAT, handle_fs_cb_stat); +UV_WRAP1_LOOP(fs_lstat, uv_fs_t, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); +UV_WRAP2_LOOP(fs_rename, uv_fs_t, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); +UV_WRAP1_LOOP(fs_fsync, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP1_LOOP(fs_fdatasync, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_ftruncate, uv_fs_t, uv_file, int64_t, _FILE _I64 _CB, handle_fs_cb); +UV_WRAP4_LOOP(fs_sendfile, uv_fs_t, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64 _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_access, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_chmod, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_fchmod, uv_fs_t, uv_file, int, _FILE _I32 _CB, handle_fs_cb); +UV_WRAP3_LOOP(fs_utime, uv_fs_t, const char*, double, double, _BYTES _F64 _F64 _CB, handle_fs_cb); +UV_WRAP3_LOOP(fs_futime, uv_fs_t, uv_file, double, double, _FILE _F64 _F64 _CB, handle_fs_cb); +UV_WRAP2_LOOP(fs_link, uv_fs_t, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); +UV_WRAP3_LOOP(fs_symlink, uv_fs_t, const char*, const char*, int, _BYTES _BYTES _I32 _CB, handle_fs_cb); +UV_WRAP1_LOOP(fs_readlink, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_bytes); +UV_WRAP1_LOOP(fs_realpath, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_bytes); +UV_WRAP3_LOOP(fs_chown, uv_fs_t, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32 _CB, handle_fs_cb); +UV_WRAP3_LOOP(fs_fchown, uv_fs_t, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32 _CB, handle_fs_cb); + +// ------------- STREAM --------------------------------------------- typedef struct { - vclosure *events[EVT_MAX + 1]; - void *write_data; -} events_data; - -#define _CALLB _FUN(_VOID,_NO_ARG) - -// HANDLE - -static events_data *init_hl_data( uv_handle_t *h ) { - events_data *d = hl_gc_alloc_raw(sizeof(events_data)); - memset(d,0,sizeof(events_data)); - hl_add_root(&h->data); - h->data = d; - return d; -} - -static void register_callb( uv_handle_t *h, vclosure *c, int event_kind ) { - if( !h || !h->data ) return; - UV_DATA(h)->events[event_kind] = c; -} - -static void clear_callb( uv_handle_t *h, int event_kind ) { - register_callb(h,NULL,event_kind); -} - -static void trigger_callb( uv_handle_t *h, int event_kind, vdynamic **args, int nargs, bool repeat ) { - events_data *ev = UV_DATA(h); - vclosure *c = ev ? ev->events[event_kind] : NULL; - if( !c ) return; - if( !repeat ) ev->events[event_kind] = NULL; - hl_dyn_call(c, args, nargs); -} + uv_w_handle_t w_handle; + vclosure *cb_read; + vclosure *cb_connection; +} uv_w_stream_t; -static void on_close( uv_handle_t *h ) { - events_data *ev = UV_DATA(h); - if( !ev ) return; - trigger_callb(h, EVT_CLOSE, NULL, 0, false); - free(ev->write_data); - hl_remove_root(&h->data); - h->data = NULL; - free(h); +void handle_stream_cb(uv_req_t *req, int status) { + vclosure *cb = UV_REQ_DATA(req); + if (status < 0) + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); + else + hl_call1(void, cb, vdynamic *, NULL); + hl_remove_root(UV_REQ_DATA(req)); + free(req); } -static void free_handle( void *h ) { - if( h ) uv_close((uv_handle_t*)h, on_close); +void handle_stream_cb_connection(uv_stream_t *stream, int status) { + vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection; + if (status < 0) + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); + else + hl_call1(void, cb, vdynamic *, NULL); } -HL_PRIM void HL_NAME(close_handle)( uv_handle_t *h, vclosure *c ) { - register_callb(h, c, EVT_CLOSE); - free_handle(h); +void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = hl_gc_alloc_noptr(suggested_size); + buf->len = suggested_size; } -DEFINE_PRIM(_VOID, close_handle, _HANDLE _CALLB); - -// STREAM - -static void on_write( uv_write_t *wr, int status ) { - vdynamic b; - vdynamic *args = &b; - b.t = &hlt_bool; - b.v.b = status == 0; - trigger_callb((uv_handle_t*)wr,EVT_WRITE,&args,1,false); - on_close((uv_handle_t*)wr); +void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { + vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read; + if (nread < 0) + hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread))), vbyte *, NULL, int, 0); + else + hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len); } -HL_PRIM bool HL_NAME(stream_write)( uv_stream_t *s, vbyte *b, int size, vclosure *c ) { - uv_write_t *wr = UV_ALLOC(uv_write_t); - events_data *d = init_hl_data((uv_handle_t*)wr); - // keep a copy of the data - uv_buf_t buf; - d->write_data = malloc(size); - memcpy(d->write_data,b,size); - buf.base = d->write_data; - buf.len = size; - register_callb((uv_handle_t*)wr,c,EVT_WRITE); - if( uv_write(wr,s,&buf,1,on_write) < 0 ) { - on_close((uv_handle_t*)wr); - return false; - } - return true; +static void w_listen(uv_stream_t *stream, int backlog, vclosure *cb) { + UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection = cb; + UV_ERROR_CHECK(uv_listen(stream, backlog, handle_stream_cb_connection)); } -static void on_alloc( uv_handle_t* h, size_t size, uv_buf_t *buf ) { - *buf = uv_buf_init(malloc(size), (int)size); +static void w_write(uv_stream_t *stream, const uv_buf_t *buf, vclosure *cb) { + // note: signature different due to no struct passing support in HL + // currently only a single uv_buf_t can be passed at a time + UV_ALLOC_CHECK(req, uv_write_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_write(req, stream, buf, 1, (void (*)(uv_write_t *, int))handle_stream_cb), free(req)); + hl_add_root(UV_REQ_DATA(req)); } -static void on_read( uv_stream_t *s, ssize_t nread, const uv_buf_t *buf ) { - vdynamic bytes; - vdynamic len; - vdynamic *args[2]; - bytes.t = &hlt_bytes; - bytes.v.ptr = buf->base; - len.t = &hlt_i32; - len.v.i = (int)nread; - args[0] = &bytes; - args[1] = &len; - trigger_callb((uv_handle_t*)s,EVT_READ,args,2,true); - free(buf->base); +static void w_read_start(uv_stream_t *stream, vclosure *cb) { + UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read = cb; + UV_ERROR_CHECK(uv_read_start(stream, handle_stream_cb_alloc, handle_stream_cb_read)); } -HL_PRIM bool HL_NAME(stream_read_start)( uv_stream_t *s, vclosure *c ) { - register_callb((uv_handle_t*)s,c,EVT_READ); - return uv_read_start(s,on_alloc,on_read) >= 0; -} +//DEFINE_PRIM(_VOID, w_listen, _STREAM _I32 _CB); +//DEFINE_PRIM(_VOID, w_write, _STREAM _BUF _CB); +//DEFINE_PRIM(_VOID, w_read_start, _STREAM _CB_READ); +//DEFINE_PRIM(_VOID, read_stop, _STREAM); +UV_REQ_WRAP(shutdown, uv_shutdown_t, uv_stream_t *stream, stream, _STREAM _CB, (void (*)(uv_shutdown_t *, int))handle_stream_cb); -HL_PRIM void HL_NAME(stream_read_stop)( uv_stream_t *s ) { - uv_read_stop(s); - clear_callb((uv_handle_t*)s,EVT_READ); // clear callback -} +// ------------- TCP ------------------------------------------------ -static void on_listen( uv_stream_t *s, int status ) { - trigger_callb((uv_handle_t*)s, EVT_LISTEN, NULL, 0, true); +HL_PRIM uv_tcp_t *HL_NAME(w_tcp_init)(uv_loop_t *loop) { + UV_ALLOC_CHECK(handle, uv_tcp_t); + UV_ERROR_CHECK_C(uv_tcp_init(loop, handle), free(handle)); + UV_ALLOC_CHECK_C(data, uv_w_stream_t, free(handle)); + memset(data, 0, sizeof(uv_w_stream_t)); + UV_HANDLE_DATA(handle) = data; + return handle; } -HL_PRIM bool HL_NAME(stream_listen)( uv_stream_t *s, int count, vclosure *c ) { - register_callb((uv_handle_t*)s,c,EVT_LISTEN); - return uv_listen(s,count,on_listen) >= 0; +HL_PRIM void HL_NAME(w_tcp_nodelay)(uv_tcp_t *handle, bool enable) { + UV_ERROR_CHECK(uv_tcp_nodelay(handle, enable ? 1 : 0)); } -DEFINE_PRIM(_BOOL, stream_write, _HANDLE _BYTES _I32 _FUN(_VOID,_BOOL)); -DEFINE_PRIM(_BOOL, stream_read_start, _HANDLE _FUN(_VOID,_BYTES _I32)); -DEFINE_PRIM(_VOID, stream_read_stop, _HANDLE); -DEFINE_PRIM(_BOOL, stream_listen, _HANDLE _I32 _CALLB); - -// TCP - -HL_PRIM uv_tcp_t *HL_NAME(tcp_init_wrap)( uv_loop_t *loop ) { - uv_tcp_t *t = UV_ALLOC(uv_tcp_t); - if( uv_tcp_init(loop,t) < 0 ) { - free(t); - return NULL; - } - init_hl_data((uv_handle_t*)t); - return t; +HL_PRIM void HL_NAME(w_tcp_keepalive)(uv_tcp_t *handle, bool enable, unsigned int delay) { + UV_ERROR_CHECK(uv_tcp_keepalive(handle, enable ? 1 : 0, delay)); } -static void on_connect( uv_connect_t *cnx, int status ) { - vdynamic b; - vdynamic *args = &b; - b.t = &hlt_bool; - b.v.b = status == 0; - trigger_callb((uv_handle_t*)cnx,EVT_CONNECT,&args,1,false); - on_close((uv_handle_t*)cnx); +HL_PRIM uv_tcp_t *HL_NAME(w_tcp_accept)(uv_loop_t *loop, uv_tcp_t *server) { + uv_tcp_t *client = HL_NAME(w_tcp_init)(loop); + UV_ERROR_CHECK_C(uv_accept((uv_stream_t *)server, (uv_stream_t *)client), free(client)); + return client; } -HL_PRIM uv_connect_t *HL_NAME(tcp_connect_wrap)( uv_tcp_t *t, int host, int port, vclosure *c ) { - uv_connect_t *cnx = UV_ALLOC(uv_connect_t); +HL_PRIM void HL_NAME(w_tcp_bind_ipv4)(uv_tcp_t *handle, int host, int port) { struct sockaddr_in addr; - memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons((unsigned short)port); - *(int*)&addr.sin_addr.s_addr = host; - if( !t || uv_tcp_connect(cnx,t,(uv_sockaddr *)&addr,on_connect) < 0 ) { - free(cnx); - return NULL; - } - memset(&addr,0,sizeof(addr)); - init_hl_data((uv_handle_t*)cnx); - register_callb((uv_handle_t*)cnx, c, EVT_CONNECT); - return cnx; + addr.sin_addr.s_addr = htonl(host); + UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); +} + +HL_PRIM void HL_NAME(w_tcp_bind_ipv6)(uv_tcp_t *handle, vbyte *host, int port) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons((unsigned short)port); + memcpy(addr.sin6_addr.s6_addr, host, 16); + UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); } -HL_PRIM bool HL_NAME(tcp_bind_wrap)( uv_tcp_t *t, int host, int port ) { +HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t *handle, int host, int port, vclosure *cb) { struct sockaddr_in addr; - memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons((unsigned short)port); - *(int*)&addr.sin_addr.s_addr = host; - return uv_tcp_bind(t,(uv_sockaddr *)&addr,0) >= 0; + addr.sin_addr.s_addr = htonl(host); + UV_ALLOC_CHECK(req, uv_connect_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); + hl_add_root(UV_REQ_DATA(req)); } - -HL_PRIM uv_tcp_t *HL_NAME(tcp_accept_wrap)( uv_tcp_t *t ) { - uv_tcp_t *client = UV_ALLOC(uv_tcp_t); - if( uv_tcp_init(t->loop, client) < 0 ) { - free(client); - return NULL; - } - if( uv_accept((uv_stream_t*)t,(uv_stream_t*)client) < 0 ) { - uv_close((uv_handle_t*)client, NULL); - return NULL; - } - init_hl_data((uv_handle_t*)client); - return client; +HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t *handle, vbyte *host, int port, vclosure *cb) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons((unsigned short)port); + memcpy(addr.sin6_addr.s6_addr, host, 16); + UV_ALLOC_CHECK(req, uv_connect_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); + hl_add_root(UV_REQ_DATA(req)); } -HL_PRIM void HL_NAME(tcp_nodelay_wrap)( uv_tcp_t *t, bool enable ) { - uv_tcp_nodelay(t,enable?1:0); +HL_PRIM void HL_NAME(w_tcp_read_stop)(uv_tcp_t *stream) { + uv_read_stop((uv_stream_t *)stream); } -DEFINE_PRIM(_TCP, tcp_init_wrap, _LOOP); -DEFINE_PRIM(_HANDLE, tcp_connect_wrap, _TCP _I32 _I32 _FUN(_VOID,_BOOL)); -DEFINE_PRIM(_BOOL, tcp_bind_wrap, _TCP _I32 _I32); -DEFINE_PRIM(_HANDLE, tcp_accept_wrap, _HANDLE); -DEFINE_PRIM(_VOID, tcp_nodelay_wrap, _TCP _BOOL); - -// loop +DEFINE_PRIM(_TCP, w_tcp_init, _LOOP); +DEFINE_PRIM(_VOID, w_tcp_nodelay, _TCP _BOOL); +DEFINE_PRIM(_VOID, w_tcp_keepalive, _TCP _BOOL _I32); +DEFINE_PRIM(_TCP, w_tcp_accept, _LOOP _TCP); +DEFINE_PRIM(_VOID, w_tcp_bind_ipv4, _TCP _I32 _I32); +DEFINE_PRIM(_VOID, w_tcp_bind_ipv6, _TCP _BYTES _I32); +DEFINE_PRIM(_VOID, w_tcp_connect_ipv4, _TCP _I32 _I32 _CB); +DEFINE_PRIM(_VOID, w_tcp_connect_ipv6, _TCP _BYTES _I32 _CB); +DEFINE_PRIM(_VOID, w_tcp_read_stop, _TCP); +#define UV_TCP_CAST(name, basename, basetype, sign, call, ffi) \ + HL_PRIM void HL_NAME(name)(uv_tcp_t *stream, sign) { \ + basename((basetype *)stream, call); \ + } \ + DEFINE_PRIM(_VOID, name, _TCP ffi); -DEFINE_PRIM(_LOOP, default_loop, _NO_ARG); -DEFINE_PRIM(_I32, loop_close, _LOOP); -DEFINE_PRIM(_I32, run, _LOOP _I32); -DEFINE_PRIM(_I32, loop_alive, _LOOP); -DEFINE_PRIM(_VOID, stop, _LOOP); -DEFINE_PRIM(_BYTES, strerror, _I32); -*/ +UV_TCP_CAST(w_tcp_listen, w_listen, uv_stream_t, int backlog COMMA vclosure *cb, backlog COMMA cb, _I32 _CB); +UV_TCP_CAST(w_tcp_write, w_write, uv_stream_t, uv_buf_t *buf COMMA vclosure *cb, buf COMMA cb, _BUF _CB); +UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, _CB); +UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); +UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); From f8607cabea64e2e0ad2c4584a668514b63e38c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Thu, 23 May 2019 13:15:28 +0100 Subject: [PATCH 06/22] DNS lookup --- libs/uv/uv.c | 80 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 8fe652f70..10521ebb5 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -72,6 +72,7 @@ #define _CB_FILE _FUN(_VOID, _ERROR _FILE) #define _CB_STAT _FUN(_VOID, _ERROR _STAT) #define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) +#define _CB_GAI _FUN(_VOID, _ERROR _ARR) // ------------- UTILITY MACROS ------------------------------------- @@ -80,23 +81,28 @@ #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_DATA(h) ((events_data *)((h)->data)) - #define UV_ALLOC(t) ((t *)malloc(sizeof(t))) #define UV_GC_ALLOC(t) ((t *)hl_gc_alloc_noptr(sizeof(t))) -// ------------- ERROR HANDLING ------------------------------------- +// ------------- HAXE CONSTRUCTORS ---------------------------------- static vdynamic * (*construct_error)(vbyte *); static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); -static vdynamic * (*construct_fs_dirent)(const char *name, int); +static vdynamic * (*construct_fs_dirent)(const char *name, int type); +static vdynamic * (*construct_addrinfo_ipv4)(int ip); +static vdynamic * (*construct_addrinfo_ipv6)(vbyte *ip); -HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat, vclosure *c_fs_dirent) { +HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat, vclosure *c_fs_dirent, vclosure *c_addrinfo_ipv4, vclosure *c_addrinfo_ipv6) { construct_error = (vdynamic * (*)(vbyte *))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; construct_fs_dirent = (vdynamic * (*)(const char *, int))c_fs_dirent->fun; + construct_addrinfo_ipv4 = (vdynamic * (*)(int))c_addrinfo_ipv4->fun; + construct_addrinfo_ipv6 = (vdynamic * (*)(vbyte *))c_addrinfo_ipv6->fun; } -DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32)); + +DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES)); + +// ------------- ERROR HANDLING ------------------------------------- #define UV_ALLOC_CHECK(var, type) \ type *var = UV_ALLOC(type); \ @@ -171,7 +177,7 @@ typedef struct { vclosure *cb_close; } uv_w_handle_t; -void handle_handle_cb_close(uv_handle_t *handle) { +static void handle_handle_cb_close(uv_handle_t *handle) { vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_handle_t)->cb_close; hl_call1(void, cb, vdynamic *, NULL); free(UV_HANDLE_DATA(handle)); @@ -189,7 +195,7 @@ static void w_close(uv_handle_t *handle, vclosure *cb) { // ------------- FILESYSTEM ----------------------------------------- -void handle_fs_cb(uv_fs_t *req) { +static void handle_fs_cb(uv_fs_t *req) { vclosure *cb = UV_REQ_DATA(req); if (req->result < 0) hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)))); @@ -201,7 +207,7 @@ void handle_fs_cb(uv_fs_t *req) { } #define UV_FS_HANDLER(name, type2, setup) \ - void name(uv_fs_t *req) { \ + static void name(uv_fs_t *req) { \ vclosure *cb = UV_REQ_DATA(req); \ if (req->result < 0) \ hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result))), type2, (type2)0); \ @@ -343,7 +349,7 @@ typedef struct { vclosure *cb_connection; } uv_w_stream_t; -void handle_stream_cb(uv_req_t *req, int status) { +static void handle_stream_cb(uv_req_t *req, int status) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); @@ -353,7 +359,7 @@ void handle_stream_cb(uv_req_t *req, int status) { free(req); } -void handle_stream_cb_connection(uv_stream_t *stream, int status) { +static void handle_stream_cb_connection(uv_stream_t *stream, int status) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection; if (status < 0) hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); @@ -361,12 +367,12 @@ void handle_stream_cb_connection(uv_stream_t *stream, int status) { hl_call1(void, cb, vdynamic *, NULL); } -void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { +static void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = hl_gc_alloc_noptr(suggested_size); buf->len = suggested_size; } -void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { +static void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read; if (nread < 0) hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread))), vbyte *, NULL, int, 0); @@ -489,3 +495,51 @@ UV_TCP_CAST(w_tcp_write, w_write, uv_stream_t, uv_buf_t *buf COMMA vclosure *cb, UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); + +// ------------- DNS ------------------------------------------------ + +static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { + vclosure *cb = UV_REQ_DATA(req); + if (status < 0) + hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status))), varray *, NULL); + else { + int count = 0; + struct addrinfo *cur; + for (cur = res; cur != NULL; cur = cur->ai_next) { + if (cur->ai_family == AF_INET || cur->ai_family == AF_INET6) + count++; + } + varray *arr = hl_alloc_array(&hlt_dyn, count); + cur = res; + for (int i = 0; i < count; i++) { + if (cur->ai_family == AF_INET) + hl_aptr(arr, vdynamic *)[i] = construct_addrinfo_ipv4(((struct sockaddr_in *)cur->ai_addr)->sin_addr.s_addr); + else if (cur->ai_family == AF_INET6) + hl_aptr(arr, vdynamic *)[i] = construct_addrinfo_ipv6(((struct sockaddr_in6 *)cur->ai_addr)->sin6_addr.s6_addr); + cur = cur->ai_next; + } + uv_freeaddrinfo(res); + hl_call2(void, cb, vdynamic *, NULL, varray *, arr); + } + hl_remove_root(UV_REQ_DATA(req)); + free(req); +} + +HL_PRIM void HL_NAME(w_getaddrinfo)(uv_loop_t *loop, vbyte *node, vbyte *service, int hint_flags, int hint_family, int hint_socktype, int hint_protocol, vclosure *cb) { + struct addrinfo hints = { + .ai_flags = hint_flags, + .ai_family = hint_family, + .ai_socktype = hint_socktype, + .ai_protocol = hint_protocol, + .ai_addrlen = 0, + .ai_addr = NULL, + .ai_canonname = NULL, + .ai_next = NULL + }; + UV_ALLOC_CHECK(req, uv_getaddrinfo_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_getaddrinfo(loop, req, handle_dns_gai, (char *)node, (char *)service, &hints), free(req)); + hl_add_root(UV_REQ_DATA(req)); +} + +DEFINE_PRIM(_VOID, w_getaddrinfo, _LOOP _BYTES _BYTES _I32 _I32 _I32 _I32 _CB_GAI) From 0a471ff8cb782157e2782424d6b88712897fe664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Thu, 23 May 2019 19:08:56 +0100 Subject: [PATCH 07/22] DNS reverse lookup --- libs/uv/uv.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 10521ebb5..e7d01a92e 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -73,6 +73,7 @@ #define _CB_STAT _FUN(_VOID, _ERROR _STAT) #define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) #define _CB_GAI _FUN(_VOID, _ERROR _ARR) +#define _CB_GNI _FUN(_VOID, _ERROR _BYTES _BYTES) // ------------- UTILITY MACROS ------------------------------------- @@ -542,4 +543,38 @@ HL_PRIM void HL_NAME(w_getaddrinfo)(uv_loop_t *loop, vbyte *node, vbyte *service hl_add_root(UV_REQ_DATA(req)); } -DEFINE_PRIM(_VOID, w_getaddrinfo, _LOOP _BYTES _BYTES _I32 _I32 _I32 _I32 _CB_GAI) +static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { + vclosure *cb = UV_REQ_DATA(req); + if (status < 0) + hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status))), vbyte *, NULL, vbyte *, NULL); + else + hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hostname, vbyte *, (vbyte *)service); + hl_remove_root(UV_REQ_DATA(req)); + free(req); +} + +HL_PRIM void HL_NAME(w_getnameinfo_ipv4)(uv_loop_t *loop, int ip, int flags, vclosure *cb) { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = htonl(ip); + UV_ALLOC_CHECK(req, uv_getnameinfo_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); + hl_add_root(UV_REQ_DATA(req)); +} + +HL_PRIM void HL_NAME(w_getnameinfo_ipv6)(uv_loop_t *loop, vbyte *ip, int flags, vclosure *cb) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + memcpy(addr.sin6_addr.s6_addr, ip, 16); + UV_ALLOC_CHECK(req, uv_getnameinfo_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); + hl_add_root(UV_REQ_DATA(req)); +} + +DEFINE_PRIM(_VOID, w_getaddrinfo, _LOOP _BYTES _BYTES _I32 _I32 _I32 _I32 _CB_GAI); +DEFINE_PRIM(_VOID, w_getnameinfo_ipv4, _LOOP _I32 _I32 _CB_GNI); +DEFINE_PRIM(_VOID, w_getnameinfo_ipv6, _LOOP _BYTES _I32 _CB_GNI); From ddc90c4e22ef613be6f02406beef3d8e2901f565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 24 May 2019 13:01:04 +0100 Subject: [PATCH 08/22] UDP --- libs/uv/uv.c | 146 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 29 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index e7d01a92e..c7b4e4ffd 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -74,6 +74,7 @@ #define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) #define _CB_GAI _FUN(_VOID, _ERROR _ARR) #define _CB_GNI _FUN(_VOID, _ERROR _BYTES _BYTES) +#define _CB_UDP_RECV _FUN(_VOID, _ERROR _BYTES _I32 _DYN) // ------------- UTILITY MACROS ------------------------------------- @@ -92,16 +93,25 @@ static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, i static vdynamic * (*construct_fs_dirent)(const char *name, int type); static vdynamic * (*construct_addrinfo_ipv4)(int ip); static vdynamic * (*construct_addrinfo_ipv6)(vbyte *ip); - -HL_PRIM void HL_NAME(glue_register)(vclosure *c_error, vclosure *c_fs_stat, vclosure *c_fs_dirent, vclosure *c_addrinfo_ipv4, vclosure *c_addrinfo_ipv6) { +static vdynamic * (*construct_addrport)(vdynamic *addr, int port); + +HL_PRIM void HL_NAME(glue_register)( + vclosure *c_error, + vclosure *c_fs_stat, + vclosure *c_fs_dirent, + vclosure *c_addrinfo_ipv4, + vclosure *c_addrinfo_ipv6, + vclosure *c_addrport +) { construct_error = (vdynamic * (*)(vbyte *))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; construct_fs_dirent = (vdynamic * (*)(const char *, int))c_fs_dirent->fun; construct_addrinfo_ipv4 = (vdynamic * (*)(int))c_addrinfo_ipv4->fun; construct_addrinfo_ipv6 = (vdynamic * (*)(vbyte *))c_addrinfo_ipv6->fun; + construct_addrport = (vdynamic * (*)(vdynamic *, int))c_addrport->fun; } -DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES)); +DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES) _FUN(_DYN, _DYN _I32)); // ------------- ERROR HANDLING ------------------------------------- @@ -406,6 +416,20 @@ static void w_read_start(uv_stream_t *stream, vclosure *cb) { //DEFINE_PRIM(_VOID, read_stop, _STREAM); UV_REQ_WRAP(shutdown, uv_shutdown_t, uv_stream_t *stream, stream, _STREAM _CB, (void (*)(uv_shutdown_t *, int))handle_stream_cb); +// ------------- NETWORK MACROS ------------------------------------- + +#define UV_SOCKADDR_IPV4(var, host, port) \ + struct sockaddr_in var; \ + var.sin_family = AF_INET; \ + var.sin_port = htons((unsigned short)port); \ + var.sin_addr.s_addr = htonl(host); +#define UV_SOCKADDR_IPV6(var, host, port) \ + struct sockaddr_in6 var; \ + memset(&var, 0, sizeof(var)); \ + var.sin6_family = AF_INET6; \ + var.sin6_port = htons((unsigned short)port); \ + memcpy(var.sin6_addr.s6_addr, host, 16); + // ------------- TCP ------------------------------------------------ HL_PRIM uv_tcp_t *HL_NAME(w_tcp_init)(uv_loop_t *loop) { @@ -432,27 +456,17 @@ HL_PRIM uv_tcp_t *HL_NAME(w_tcp_accept)(uv_loop_t *loop, uv_tcp_t *server) { } HL_PRIM void HL_NAME(w_tcp_bind_ipv4)(uv_tcp_t *handle, int host, int port) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons((unsigned short)port); - addr.sin_addr.s_addr = htonl(host); + UV_SOCKADDR_IPV4(addr, host, port); UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); } HL_PRIM void HL_NAME(w_tcp_bind_ipv6)(uv_tcp_t *handle, vbyte *host, int port) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons((unsigned short)port); - memcpy(addr.sin6_addr.s6_addr, host, 16); + UV_SOCKADDR_IPV6(addr, host, port); UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); } HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t *handle, int host, int port, vclosure *cb) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons((unsigned short)port); - addr.sin_addr.s_addr = htonl(host); + UV_SOCKADDR_IPV4(addr, host, port); UV_ALLOC_CHECK(req, uv_connect_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); @@ -460,11 +474,7 @@ HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t *handle, int host, int port, v } HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t *handle, vbyte *host, int port, vclosure *cb) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons((unsigned short)port); - memcpy(addr.sin6_addr.s6_addr, host, 16); + UV_SOCKADDR_IPV6(addr, host, port); UV_ALLOC_CHECK(req, uv_connect_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); @@ -497,6 +507,90 @@ UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); +// ------------- UDP ------------------------------------------------ + +typedef struct { + uv_w_handle_t w_handle; + vclosure *cb_read; +} uv_w_udp_t; + +static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned int flags) { + vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read; + if (nread < 0) + hl_call4(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread))), vbyte *, NULL, int, 0, vdynamic *, NULL); + else { + vdynamic *w_addrport = NULL; + if (addr != NULL) { + vdynamic *w_addr; + if (addr->sa_family == AF_INET) { + w_addr = construct_addrinfo_ipv4(((struct sockaddr_in *)addr)->sin_addr.s_addr); + w_addrport = construct_addrport(w_addr, ((struct sockaddr_in *)addr)->sin_port); + } else if (addr->sa_family == AF_INET6) { + w_addr = construct_addrinfo_ipv6(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr); + w_addrport = construct_addrport(w_addr, ((struct sockaddr_in6 *)addr)->sin6_port); + } + } + hl_call4(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len, vdynamic *, w_addrport); + } +} + +HL_PRIM uv_udp_t *HL_NAME(w_udp_init)(uv_loop_t *loop) { + UV_ALLOC_CHECK(handle, uv_udp_t); + UV_ERROR_CHECK_C(uv_udp_init(loop, handle), free(handle)); + UV_ALLOC_CHECK_C(data, uv_w_udp_t, free(handle)); + memset(data, 0, sizeof(uv_w_udp_t)); + UV_HANDLE_DATA(handle) = data; + return handle; +} + +HL_PRIM void HL_NAME(w_udp_bind_ipv4)(uv_udp_t *handle, int host, int port) { + UV_SOCKADDR_IPV4(addr, host, port); + UV_ERROR_CHECK(uv_udp_bind(handle, (const struct sockaddr *)&addr, 0)); +} + +HL_PRIM void HL_NAME(w_udp_bind_ipv6)(uv_udp_t *handle, vbyte *host, int port) { + UV_SOCKADDR_IPV6(addr, host, port); + UV_ERROR_CHECK(uv_udp_bind(handle, (const struct sockaddr *)&addr, 0)); +} + +HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t *handle, const uv_buf_t *buf, int host, int port, vclosure *cb) { + // note: signature different due to no struct passing support in HL + // currently only a single uv_buf_t can be passed at a time + UV_SOCKADDR_IPV4(addr, host, port); + UV_ALLOC_CHECK(req, uv_udp_send_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_udp_send(req, handle, buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); + hl_add_root(UV_REQ_DATA(req)); +} + +HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t *handle, const uv_buf_t *buf, vbyte *host, int port, vclosure *cb) { + // note: signature different due to no struct passing support in HL + // currently only a single uv_buf_t can be passed at a time + UV_SOCKADDR_IPV6(addr, host, port); + UV_ALLOC_CHECK(req, uv_udp_send_t); + UV_REQ_DATA(req) = (void *)cb; + UV_ERROR_CHECK_C(uv_udp_send(req, handle, buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); + hl_add_root(UV_REQ_DATA(req)); +} + +HL_PRIM void HL_NAME(w_udp_recv_start)(uv_udp_t *handle, vclosure *cb) { + UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read = cb; + UV_ERROR_CHECK(uv_udp_recv_start(handle, handle_stream_cb_alloc, handle_udp_cb_recv)); +} + +HL_PRIM void HL_NAME(w_udp_recv_stop)(uv_udp_t *handle) { + UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read = NULL; + UV_ERROR_CHECK(uv_udp_recv_stop(handle)); +} + +DEFINE_PRIM(_UDP, w_udp_init, _LOOP); +DEFINE_PRIM(_VOID, w_udp_bind_ipv4, _UDP _I32 _I32); +DEFINE_PRIM(_VOID, w_udp_bind_ipv6, _UDP _BYTES _I32); +DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BUF _I32 _I32 _CB); +DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BUF _BYTES _I32 _CB); +DEFINE_PRIM(_VOID, w_udp_recv_start, _UDP _CB_UDP_RECV); +DEFINE_PRIM(_VOID, w_udp_recv_stop, _UDP); + // ------------- DNS ------------------------------------------------ static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { @@ -554,10 +648,7 @@ static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostna } HL_PRIM void HL_NAME(w_getnameinfo_ipv4)(uv_loop_t *loop, int ip, int flags, vclosure *cb) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = htonl(ip); + UV_SOCKADDR_IPV4(addr, ip, 0); UV_ALLOC_CHECK(req, uv_getnameinfo_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); @@ -565,10 +656,7 @@ HL_PRIM void HL_NAME(w_getnameinfo_ipv4)(uv_loop_t *loop, int ip, int flags, vcl } HL_PRIM void HL_NAME(w_getnameinfo_ipv6)(uv_loop_t *loop, vbyte *ip, int flags, vclosure *cb) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - memcpy(addr.sin6_addr.s6_addr, ip, 16); + UV_SOCKADDR_IPV6(addr, ip, 0); UV_ALLOC_CHECK(req, uv_getnameinfo_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); From c1c650de50ee1a6910c4994eb81820ae47fec64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 28 Jun 2019 13:05:35 +0100 Subject: [PATCH 09/22] sync versions of fs functions --- libs/uv/uv.c | 101 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index c7b4e4ffd..5a11ae29f 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -216,6 +216,12 @@ static void handle_fs_cb(uv_fs_t *req) { hl_remove_root(UV_REQ_DATA(req)); free(req); } +static void handle_fs_cb_sync(uv_fs_t *req) { + /* TODO: should we call uv_fs_req_cleanup on error here? */ + UV_ERROR_CHECK_C(req->result, free(req)); + uv_fs_req_cleanup(req); + free(req); +} #define UV_FS_HANDLER(name, type2, setup) \ static void name(uv_fs_t *req) { \ @@ -230,6 +236,15 @@ static void handle_fs_cb(uv_fs_t *req) { uv_fs_req_cleanup(req); \ hl_remove_root(UV_REQ_DATA(req)); \ free(req); \ + } \ + static type2 name ## _sync(uv_fs_t *req) { \ + /* TODO: should we call uv_fs_req_cleanup on error here? */ \ + UV_ERROR_CHECK_C(req->result, free(req)); \ + type2 value2; \ + setup; \ + uv_fs_req_cleanup(req); \ + free(req); \ + return value2; \ } UV_FS_HANDLER(handle_fs_cb_bytes, vbyte *, value2 = (vbyte *)hl_to_utf16((const char *)req->ptr)); @@ -286,16 +301,27 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { hl_add_root(UV_REQ_DATA(req)); \ } \ DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi); +#define UV_REQ_WRAP_LOOP_SYNC(name, ret, reqtype, sign, call, ffiret, ffi, handler, doret) \ + HL_PRIM ret HL_NAME(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_PRIM(ffiret, w_ ## name ## _sync, _LOOP ffi); #define COMMA , -#define UV_WRAP1_LOOP(name, reqtype, arg1, sign, handler) \ - UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1, _arg1, sign, handler) -#define UV_WRAP2_LOOP(name, reqtype, arg1, arg2, sign, handler) \ - UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, sign, handler) -#define UV_WRAP3_LOOP(name, reqtype, arg1, arg2, arg3, sign, handler) \ - UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, sign, handler) -#define UV_WRAP4_LOOP(name, reqtype, arg1, arg2, arg3, arg4, sign, handler) \ - UV_REQ_WRAP_LOOP(name, reqtype, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, sign, handler) +#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) 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) { // note: signature different due to no struct passing support in HL @@ -315,42 +341,35 @@ HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, const uv_buf_t * hl_add_root(UV_REQ_DATA(req)); } -HL_PRIM void HL_NAME(w_fs_scandir)(uv_loop_t *loop, const char *path, int flags, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_fs_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_fs_scandir(loop, req, path, flags, handle_fs_cb_scandir), free(req)); - hl_add_root(UV_REQ_DATA(req)); -} - -DEFINE_PRIM(_VOID, w_fs_scandir, _LOOP _BYTES _I32 _CB_SCANDIR); DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); -UV_WRAP1_LOOP(fs_close, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP3_LOOP(fs_open, uv_fs_t, const char*, int, int, _BYTES _I32 _I32 _CB_FILE, handle_fs_cb_file); -UV_WRAP1_LOOP(fs_unlink, uv_fs_t, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_mkdir, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP1_LOOP(fs_mkdtemp, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_path); -UV_WRAP1_LOOP(fs_rmdir, uv_fs_t, const char*, _BYTES _CB, handle_fs_cb); -UV_WRAP1_LOOP(fs_stat, uv_fs_t, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); -UV_WRAP1_LOOP(fs_fstat, uv_fs_t, uv_file, _FILE _CB_STAT, handle_fs_cb_stat); -UV_WRAP1_LOOP(fs_lstat, uv_fs_t, const char*, _BYTES _CB_STAT, handle_fs_cb_stat); -UV_WRAP2_LOOP(fs_rename, uv_fs_t, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); -UV_WRAP1_LOOP(fs_fsync, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP1_LOOP(fs_fdatasync, uv_fs_t, uv_file, _FILE _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_ftruncate, uv_fs_t, uv_file, int64_t, _FILE _I64 _CB, handle_fs_cb); -UV_WRAP4_LOOP(fs_sendfile, uv_fs_t, uv_file, uv_file, int64_t, size_t, _FILE _FILE _I64 _I64 _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_access, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_chmod, uv_fs_t, const char*, int, _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_fchmod, uv_fs_t, uv_file, int, _FILE _I32 _CB, handle_fs_cb); -UV_WRAP3_LOOP(fs_utime, uv_fs_t, const char*, double, double, _BYTES _F64 _F64 _CB, handle_fs_cb); -UV_WRAP3_LOOP(fs_futime, uv_fs_t, uv_file, double, double, _FILE _F64 _F64 _CB, handle_fs_cb); -UV_WRAP2_LOOP(fs_link, uv_fs_t, const char*, const char*, _BYTES _BYTES _CB, handle_fs_cb); -UV_WRAP3_LOOP(fs_symlink, uv_fs_t, const char*, const char*, int, _BYTES _BYTES _I32 _CB, handle_fs_cb); -UV_WRAP1_LOOP(fs_readlink, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_bytes); -UV_WRAP1_LOOP(fs_realpath, uv_fs_t, const char*, _BYTES _CB_STR, handle_fs_cb_bytes); -UV_WRAP3_LOOP(fs_chown, uv_fs_t, const char*, uv_uid_t, uv_gid_t, _BYTES _I32 _I32 _CB, handle_fs_cb); -UV_WRAP3_LOOP(fs_fchown, uv_fs_t, uv_file, uv_uid_t, uv_gid_t, _FILE _I32 _I32 _CB, handle_fs_cb); +FS_WRAP1_LOOP(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP3_LOOP(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); +FS_WRAP1_LOOP(fs_unlink, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_mkdir, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1_LOOP(fs_mkdtemp, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_path, return); +FS_WRAP1_LOOP(fs_rmdir, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_scandir, varray *, const char *, int, _ARR, _BYTES _I32, _CB_SCANDIR, handle_fs_cb_scandir, return); +FS_WRAP1_LOOP(fs_stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1_LOOP(fs_fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1_LOOP(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP2_LOOP(fs_rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP1_LOOP(fs_fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP1_LOOP(fs_fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I64, _CB, handle_fs_cb, ); +FS_WRAP4_LOOP(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I64 _I64, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_access, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); +FS_WRAP3_LOOP(fs_utime, void, const char*, double, double, _VOID, _BYTES _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP3_LOOP(fs_futime, void, uv_file, double, double, _VOID, _FILE _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_link, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP3_LOOP(fs_symlink, void, const char*, const char*, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1_LOOP(fs_readlink, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP1_LOOP(fs_realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP3_LOOP(fs_chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP3_LOOP(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); // ------------- STREAM --------------------------------------------- From 65f0785738cc2f327579d6ae2f22b5c8e6252b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Wed, 10 Jul 2019 19:19:29 +0200 Subject: [PATCH 10/22] sync versions of fs_read and fs_write --- libs/uv/uv.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 5a11ae29f..e7f1eab26 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -60,7 +60,7 @@ // Haxe types -#define _ERROR _OBJ(_OBJ(_BYTES _I32)) +#define _ERROR _DYN #define _STAT _OBJ(_I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) // Callback types @@ -323,26 +323,43 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { 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) +/** + 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) { - // note: signature different due to no struct passing support in HL - // currently only a single uv_buf_t can be passed at a time 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) { - // note: signature different due to no struct passing support in HL - // currently only a single uv_buf_t can be passed at a time 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); +} + DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); +DEFINE_PRIM(_I32, w_fs_read_sync, _LOOP _FILE _BUF _I32); DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); +DEFINE_PRIM(_I32, w_fs_write_sync, _LOOP _FILE _BUF _I32); FS_WRAP1_LOOP(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); FS_WRAP3_LOOP(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); @@ -357,8 +374,8 @@ FS_WRAP1_LOOP(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle FS_WRAP2_LOOP(fs_rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); FS_WRAP1_LOOP(fs_fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); FS_WRAP1_LOOP(fs_fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I64, _CB, handle_fs_cb, ); -FS_WRAP4_LOOP(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I64 _I64, _CB, handle_fs_cb, ); +FS_WRAP2_LOOP(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I32, _CB, handle_fs_cb, ); +FS_WRAP4_LOOP(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, ); FS_WRAP2_LOOP(fs_access, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); FS_WRAP2_LOOP(fs_chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); FS_WRAP2_LOOP(fs_fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); From 1120cc984e2ca4aee2bf8710c3e10f06f7f11fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 12 Jul 2019 13:31:03 +0200 Subject: [PATCH 11/22] error numbers, fs event --- libs/uv/uv.c | 63 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index e7f1eab26..1c235efbe 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -72,6 +72,7 @@ #define _CB_FILE _FUN(_VOID, _ERROR _FILE) #define _CB_STAT _FUN(_VOID, _ERROR _STAT) #define _CB_SCANDIR _FUN(_VOID, _ERROR _ARR) +#define _CB_FS_EVENT _FUN(_VOID, _ERROR _BYTES _I32) #define _CB_GAI _FUN(_VOID, _ERROR _ARR) #define _CB_GNI _FUN(_VOID, _ERROR _BYTES _BYTES) #define _CB_UDP_RECV _FUN(_VOID, _ERROR _BYTES _I32 _DYN) @@ -88,7 +89,7 @@ // ------------- HAXE CONSTRUCTORS ---------------------------------- -static vdynamic * (*construct_error)(vbyte *); +static vdynamic * (*construct_error)(vbyte *, int); static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); static vdynamic * (*construct_fs_dirent)(const char *name, int type); static vdynamic * (*construct_addrinfo_ipv4)(int ip); @@ -103,7 +104,7 @@ HL_PRIM void HL_NAME(glue_register)( vclosure *c_addrinfo_ipv6, vclosure *c_addrport ) { - construct_error = (vdynamic * (*)(vbyte *))c_error->fun; + construct_error = (vdynamic * (*)(vbyte *, int))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; construct_fs_dirent = (vdynamic * (*)(const char *, int))c_fs_dirent->fun; construct_addrinfo_ipv4 = (vdynamic * (*)(int))c_addrinfo_ipv4->fun; @@ -111,25 +112,25 @@ HL_PRIM void HL_NAME(glue_register)( construct_addrport = (vdynamic * (*)(vdynamic *, int))c_addrport->fun; } -DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES) _FUN(_DYN, _DYN _I32)); +DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES) _FUN(_DYN, _DYN _I32)); // ------------- ERROR HANDLING ------------------------------------- #define UV_ALLOC_CHECK(var, type) \ type *var = UV_ALLOC(type); \ if (var == NULL) { \ - hl_throw(construct_error((vbyte *)"malloc " #type " failed")); \ + hl_throw(construct_error((vbyte *)"malloc " #type " failed", 0)); \ } else {} #define UV_ALLOC_CHECK_C(var, type, cleanup) \ type *var = UV_ALLOC(type); \ if (var == NULL) { \ cleanup; \ - hl_throw(construct_error((vbyte *)"malloc " #type " failed")); \ + hl_throw(construct_error((vbyte *)"malloc " #type " failed", 0)); \ } else {} #define UV_ERROR_CHECK(expr) do { \ int __tmp_result = expr; \ if (__tmp_result < 0) { \ - vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result))); \ + vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result)), __tmp_result); \ hl_throw(err); \ } \ } while (0) @@ -137,7 +138,7 @@ DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES) _FUN(_DYN, _I32 _I32 _I32 _ int __tmp_result = expr; \ if (__tmp_result < 0) { \ cleanup; \ - vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result))); \ + vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result)), __tmp_result); \ hl_throw(err); \ } \ } while (0) @@ -209,7 +210,7 @@ static void w_close(uv_handle_t *handle, vclosure *cb) { static void handle_fs_cb(uv_fs_t *req) { vclosure *cb = UV_REQ_DATA(req); if (req->result < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)))); + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result)); else hl_call1(void, cb, vdynamic *, NULL); uv_fs_req_cleanup(req); @@ -227,7 +228,7 @@ static void handle_fs_cb_sync(uv_fs_t *req) { static void name(uv_fs_t *req) { \ vclosure *cb = UV_REQ_DATA(req); \ if (req->result < 0) \ - hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result))), type2, (type2)0); \ + hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result), type2, (type2)0); \ else { \ type2 value2; \ setup; \ @@ -388,6 +389,38 @@ FS_WRAP1_LOOP(fs_realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle FS_WRAP3_LOOP(fs_chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); FS_WRAP3_LOOP(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); +// ------------- FILESYSTEM EVENTS ---------------------------------- + +static void handle_fs_event_cb(uv_fs_event_t *handle, const char *filename, int events, int status) { + vclosure *cb = UV_HANDLE_DATA(handle); + if (status < 0) + hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), vbyte *, NULL, int, 0); + else + hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hl_to_utf16((const char *)filename), int, events); +} + +HL_PRIM uv_fs_event_t *HL_NAME(w_fs_event_init)(uv_loop_t *loop) { + UV_ALLOC_CHECK(handle, uv_fs_event_t); + UV_ERROR_CHECK_C(uv_fs_event_init(loop, handle), free(handle)); + return handle; +} + +HL_PRIM void HL_NAME(w_fs_event_start)(uv_fs_event_t *handle, const char *path, int flags, vclosure *cb) { + UV_HANDLE_DATA(handle) = (void *)cb; + UV_ERROR_CHECK_C(uv_fs_event_start(handle, handle_fs_event_cb, path, flags), free(handle)); + hl_add_root(UV_HANDLE_DATA(handle)); +} + +HL_PRIM void HL_NAME(w_fs_event_stop)(uv_fs_event_t *handle) { + UV_ERROR_CHECK_C(uv_fs_event_stop(handle), free(handle)); + hl_remove_root(UV_HANDLE_DATA(handle)); + free(handle); +} + +DEFINE_PRIM(_FS_EVENT, w_fs_event_init, _LOOP); +DEFINE_PRIM(_VOID, w_fs_event_start, _FS_EVENT _BYTES _I32 _CB_FS_EVENT); +DEFINE_PRIM(_VOID, w_fs_event_stop, _FS_EVENT); + // ------------- STREAM --------------------------------------------- typedef struct { @@ -399,7 +432,7 @@ typedef struct { static void handle_stream_cb(uv_req_t *req, int status) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status)); else hl_call1(void, cb, vdynamic *, NULL); hl_remove_root(UV_REQ_DATA(req)); @@ -409,7 +442,7 @@ static void handle_stream_cb(uv_req_t *req, int status) { static void handle_stream_cb_connection(uv_stream_t *stream, int status) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection; if (status < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)))); + hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status)); else hl_call1(void, cb, vdynamic *, NULL); } @@ -422,7 +455,7 @@ static void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, u static void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read; if (nread < 0) - hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread))), vbyte *, NULL, int, 0); + hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread)), nread), vbyte *, NULL, int, 0); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len); } @@ -553,7 +586,7 @@ typedef struct { static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned int flags) { vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read; if (nread < 0) - hl_call4(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread))), vbyte *, NULL, int, 0, vdynamic *, NULL); + hl_call4(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread)), nread), vbyte *, NULL, int, 0, vdynamic *, NULL); else { vdynamic *w_addrport = NULL; if (addr != NULL) { @@ -632,7 +665,7 @@ DEFINE_PRIM(_VOID, w_udp_recv_stop, _UDP); static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status))), varray *, NULL); + hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), varray *, NULL); else { int count = 0; struct addrinfo *cur; @@ -676,7 +709,7 @@ HL_PRIM void HL_NAME(w_getaddrinfo)(uv_loop_t *loop, vbyte *node, vbyte *service static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status))), vbyte *, NULL, vbyte *, NULL); + hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), vbyte *, NULL, vbyte *, NULL); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hostname, vbyte *, (vbyte *)service); hl_remove_root(UV_REQ_DATA(req)); From c485390bc38cfede1fd73ff98b2cef554d923755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Thu, 25 Jul 2019 16:28:11 +0200 Subject: [PATCH 12/22] remove error messages from FFI, remove uv_bufs from FFI, close handles properly --- libs/uv/uv.c | 145 +++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 1c235efbe..9c9cbf061 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -89,7 +89,7 @@ // ------------- HAXE CONSTRUCTORS ---------------------------------- -static vdynamic * (*construct_error)(vbyte *, int); +static vdynamic * (*construct_error)(int); static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); static vdynamic * (*construct_fs_dirent)(const char *name, int type); static vdynamic * (*construct_addrinfo_ipv4)(int ip); @@ -104,7 +104,7 @@ HL_PRIM void HL_NAME(glue_register)( vclosure *c_addrinfo_ipv6, vclosure *c_addrport ) { - construct_error = (vdynamic * (*)(vbyte *, int))c_error->fun; + construct_error = (vdynamic * (*)(int))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; construct_fs_dirent = (vdynamic * (*)(const char *, int))c_fs_dirent->fun; construct_addrinfo_ipv4 = (vdynamic * (*)(int))c_addrinfo_ipv4->fun; @@ -112,37 +112,39 @@ HL_PRIM void HL_NAME(glue_register)( construct_addrport = (vdynamic * (*)(vdynamic *, int))c_addrport->fun; } -DEFINE_PRIM(_VOID, glue_register, _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) _FUN(_DYN, _BYTES _I32) _FUN(_DYN, _I32) _FUN(_DYN, _BYTES) _FUN(_DYN, _DYN _I32)); +DEFINE_PRIM( + _VOID, + glue_register, + _FUN(_DYN, _I32) + _FUN(_DYN, _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32) + _FUN(_DYN, _BYTES _I32) + _FUN(_DYN, _I32) + _FUN(_DYN, _BYTES) + _FUN(_DYN, _DYN _I32) +); // ------------- ERROR HANDLING ------------------------------------- -#define UV_ALLOC_CHECK(var, type) \ - type *var = UV_ALLOC(type); \ - if (var == NULL) { \ - hl_throw(construct_error((vbyte *)"malloc " #type " failed", 0)); \ - } else {} #define UV_ALLOC_CHECK_C(var, type, cleanup) \ type *var = UV_ALLOC(type); \ if (var == NULL) { \ cleanup; \ - hl_throw(construct_error((vbyte *)"malloc " #type " failed", 0)); \ + hl_throw(construct_error(0)); \ } else {} -#define UV_ERROR_CHECK(expr) do { \ - int __tmp_result = expr; \ - if (__tmp_result < 0) { \ - vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result)), __tmp_result); \ - hl_throw(err); \ - } \ - } while (0) + +#define UV_ALLOC_CHECK(var, type) UV_ALLOC_CHECK_C(var, type, ) + #define UV_ERROR_CHECK_C(expr, cleanup) do { \ int __tmp_result = expr; \ if (__tmp_result < 0) { \ cleanup; \ - vdynamic *err = construct_error((vbyte *)strdup(uv_strerror(__tmp_result)), __tmp_result); \ + vdynamic *err = construct_error(__tmp_result); \ hl_throw(err); \ } \ } while (0) +#define UV_ERROR_CHECK(expr) UV_ERROR_CHECK_C(expr, ) + // ------------- LOOP ----------------------------------------------- HL_PRIM uv_loop_t * HL_NAME(w_loop_init)(void) { @@ -151,14 +153,13 @@ HL_PRIM uv_loop_t * HL_NAME(w_loop_init)(void) { return loop; } -HL_PRIM bool HL_NAME(w_loop_close)(uv_loop_t *loop) { +HL_PRIM void HL_NAME(w_loop_close)(uv_loop_t *loop) { UV_ERROR_CHECK(uv_loop_close(loop)); free(loop); - return true; } HL_PRIM bool HL_NAME(w_run)(uv_loop_t *loop, uv_run_mode mode) { - return uv_run(loop, mode) == 0; + return uv_run(loop, mode) != 0; } HL_PRIM bool HL_NAME(w_loop_alive)(uv_loop_t *loop) { @@ -166,23 +167,12 @@ HL_PRIM bool HL_NAME(w_loop_alive)(uv_loop_t *loop) { } DEFINE_PRIM(_LOOP, w_loop_init, _NO_ARG); -// DEFINE_ PRIM(_I32, loop_configure, _LOOP ...); -DEFINE_PRIM(_BOOL, w_loop_close, _LOOP); +DEFINE_PRIM(_VOID, w_loop_close, _LOOP); DEFINE_PRIM(_LOOP, default_loop, _NO_ARG); DEFINE_PRIM(_BOOL, w_run, _LOOP _I32); DEFINE_PRIM(_BOOL, w_loop_alive, _LOOP); DEFINE_PRIM(_VOID, stop, _LOOP); -// ------------- MISC ----------------------------------------------- - -HL_PRIM uv_buf_t *HL_NAME(w_buf_init)(vbyte *bytes, unsigned int length) { - uv_buf_t *ptr = UV_GC_ALLOC(uv_buf_t); - *ptr = uv_buf_init((char *)bytes, length); - return ptr; -} - -DEFINE_PRIM(_BUF, w_buf_init, _BYTES _I32); - // ------------- HANDLE --------------------------------------------- typedef struct { @@ -210,7 +200,7 @@ static void w_close(uv_handle_t *handle, vclosure *cb) { static void handle_fs_cb(uv_fs_t *req) { vclosure *cb = UV_REQ_DATA(req); if (req->result < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result)); + hl_call1(void, cb, vdynamic *, construct_error(req->result)); else hl_call1(void, cb, vdynamic *, NULL); uv_fs_req_cleanup(req); @@ -228,7 +218,7 @@ static void handle_fs_cb_sync(uv_fs_t *req) { static void name(uv_fs_t *req) { \ vclosure *cb = UV_REQ_DATA(req); \ if (req->result < 0) \ - hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result), type2, (type2)0); \ + hl_call2(void, cb, vdynamic *, construct_error(req->result), type2, (type2)0); \ else { \ type2 value2; \ setup; \ @@ -331,36 +321,40 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { 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) { +HL_PRIM void HL_NAME(w_fs_read)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position, 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)); + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); + UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, &buf, 1, position, 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) { +HL_PRIM int HL_NAME(w_fs_read_sync)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position) { UV_ALLOC_CHECK(req, uv_fs_t); - UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, NULL), free(req)); + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); + UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, &buf, 1, position, 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) { +HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position, 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)); + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); + UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, &buf, 1, position, 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) { +HL_PRIM int HL_NAME(w_fs_write_sync)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position) { UV_ALLOC_CHECK(req, uv_fs_t); - UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, NULL), free(req)); + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); + UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, &buf, 1, position, NULL), free(req)); return handle_fs_cb_int_sync(req); } -DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BUF _I32 _CB_INT); -DEFINE_PRIM(_I32, w_fs_read_sync, _LOOP _FILE _BUF _I32); -DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BUF _I32 _CB_INT); -DEFINE_PRIM(_I32, w_fs_write_sync, _LOOP _FILE _BUF _I32); +DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BYTES _I32 _I32 _I32 _CB_INT); +DEFINE_PRIM(_I32, w_fs_read_sync, _LOOP _FILE _BYTES _I32 _I32 _I32); +DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BYTES _I32 _I32 _I32 _CB_INT); +DEFINE_PRIM(_I32, w_fs_write_sync, _LOOP _FILE _BYTES _I32 _I32 _I32); FS_WRAP1_LOOP(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); FS_WRAP3_LOOP(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); @@ -394,32 +388,37 @@ FS_WRAP3_LOOP(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I static void handle_fs_event_cb(uv_fs_event_t *handle, const char *filename, int events, int status) { vclosure *cb = UV_HANDLE_DATA(handle); if (status < 0) - hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), vbyte *, NULL, int, 0); + hl_call3(void, cb, vdynamic *, construct_error(status), vbyte *, NULL, int, 0); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hl_to_utf16((const char *)filename), int, events); } -HL_PRIM uv_fs_event_t *HL_NAME(w_fs_event_init)(uv_loop_t *loop) { +HL_PRIM uv_fs_event_t *HL_NAME(w_fs_event_start)(uv_loop_t *loop, const char *path, bool persistent, bool recursive, vclosure *cb) { UV_ALLOC_CHECK(handle, uv_fs_event_t); UV_ERROR_CHECK_C(uv_fs_event_init(loop, handle), free(handle)); - return handle; -} - -HL_PRIM void HL_NAME(w_fs_event_start)(uv_fs_event_t *handle, const char *path, int flags, vclosure *cb) { UV_HANDLE_DATA(handle) = (void *)cb; - UV_ERROR_CHECK_C(uv_fs_event_start(handle, handle_fs_event_cb, path, flags), free(handle)); hl_add_root(UV_HANDLE_DATA(handle)); + UV_ERROR_CHECK_C(uv_fs_event_start(handle, handle_fs_event_cb, path, recursive ? UV_FS_EVENT_RECURSIVE : 0), free(handle)); + if (!persistent) + uv_unref((uv_handle_t *)handle); + return handle; } -HL_PRIM void HL_NAME(w_fs_event_stop)(uv_fs_event_t *handle) { - UV_ERROR_CHECK_C(uv_fs_event_stop(handle), free(handle)); +static void handle_close_cb(uv_handle_t *handle) { + vclosure *cb = UV_HANDLE_DATA(handle); + hl_call1(void, cb, vdynamic *, NULL); hl_remove_root(UV_HANDLE_DATA(handle)); free(handle); } -DEFINE_PRIM(_FS_EVENT, w_fs_event_init, _LOOP); -DEFINE_PRIM(_VOID, w_fs_event_start, _FS_EVENT _BYTES _I32 _CB_FS_EVENT); -DEFINE_PRIM(_VOID, w_fs_event_stop, _FS_EVENT); +HL_PRIM void HL_NAME(w_fs_event_stop)(uv_fs_event_t *handle, vclosure *cb) { + UV_ERROR_CHECK_C(uv_fs_event_stop(handle), free(handle)); + UV_HANDLE_DATA(handle) = (void *)cb; + uv_close((uv_handle_t *)handle, handle_close_cb); +} + +DEFINE_PRIM(_FS_EVENT, w_fs_event_start, _LOOP _BYTES _BOOL _BOOL _CB_FS_EVENT); +DEFINE_PRIM(_VOID, w_fs_event_stop, _FS_EVENT _CB); // ------------- STREAM --------------------------------------------- @@ -432,7 +431,7 @@ typedef struct { static void handle_stream_cb(uv_req_t *req, int status) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status)); + hl_call1(void, cb, vdynamic *, construct_error(status)); else hl_call1(void, cb, vdynamic *, NULL); hl_remove_root(UV_REQ_DATA(req)); @@ -442,7 +441,7 @@ static void handle_stream_cb(uv_req_t *req, int status) { static void handle_stream_cb_connection(uv_stream_t *stream, int status) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection; if (status < 0) - hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status)); + hl_call1(void, cb, vdynamic *, construct_error(status)); else hl_call1(void, cb, vdynamic *, NULL); } @@ -455,7 +454,7 @@ static void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, u static void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read; if (nread < 0) - hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread)), nread), vbyte *, NULL, int, 0); + hl_call3(void, cb, vdynamic *, construct_error(nread), vbyte *, NULL, int, 0); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len); } @@ -571,7 +570,7 @@ DEFINE_PRIM(_VOID, w_tcp_read_stop, _TCP); DEFINE_PRIM(_VOID, name, _TCP ffi); UV_TCP_CAST(w_tcp_listen, w_listen, uv_stream_t, int backlog COMMA vclosure *cb, backlog COMMA cb, _I32 _CB); -UV_TCP_CAST(w_tcp_write, w_write, uv_stream_t, uv_buf_t *buf COMMA vclosure *cb, buf COMMA cb, _BUF _CB); +//UV_TCP_CAST(w_tcp_write, w_write, uv_stream_t, uv_buf_t *buf COMMA vclosure *cb, buf COMMA cb, _BUF _CB); UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); @@ -586,7 +585,7 @@ typedef struct { static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned int flags) { vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read; if (nread < 0) - hl_call4(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(nread)), nread), vbyte *, NULL, int, 0, vdynamic *, NULL); + hl_call4(void, cb, vdynamic *, construct_error(nread), vbyte *, NULL, int, 0, vdynamic *, NULL); else { vdynamic *w_addrport = NULL; if (addr != NULL) { @@ -622,23 +621,23 @@ HL_PRIM void HL_NAME(w_udp_bind_ipv6)(uv_udp_t *handle, vbyte *host, int port) { UV_ERROR_CHECK(uv_udp_bind(handle, (const struct sockaddr *)&addr, 0)); } -HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t *handle, const uv_buf_t *buf, int host, int port, vclosure *cb) { - // note: signature different due to no struct passing support in HL - // currently only a single uv_buf_t can be passed at a time +HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t *handle, vbyte *data, int length, int host, int port, vclosure *cb) { UV_SOCKADDR_IPV4(addr, host, port); UV_ALLOC_CHECK(req, uv_udp_send_t); UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_udp_send(req, handle, buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); + uv_buf_t buf = uv_buf_init((char *)data, length); + UV_ERROR_CHECK_C(uv_udp_send(req, handle, &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); hl_add_root(UV_REQ_DATA(req)); } -HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t *handle, const uv_buf_t *buf, vbyte *host, int port, vclosure *cb) { +HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t *handle, vbyte *data, int length, vbyte *host, int port, vclosure *cb) { // note: signature different due to no struct passing support in HL // currently only a single uv_buf_t can be passed at a time UV_SOCKADDR_IPV6(addr, host, port); UV_ALLOC_CHECK(req, uv_udp_send_t); UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_udp_send(req, handle, buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); + uv_buf_t buf = uv_buf_init((char *)data, length); + UV_ERROR_CHECK_C(uv_udp_send(req, handle, &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); hl_add_root(UV_REQ_DATA(req)); } @@ -655,8 +654,8 @@ HL_PRIM void HL_NAME(w_udp_recv_stop)(uv_udp_t *handle) { DEFINE_PRIM(_UDP, w_udp_init, _LOOP); DEFINE_PRIM(_VOID, w_udp_bind_ipv4, _UDP _I32 _I32); DEFINE_PRIM(_VOID, w_udp_bind_ipv6, _UDP _BYTES _I32); -DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BUF _I32 _I32 _CB); -DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BUF _BYTES _I32 _CB); +DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BYTES _I32 _I32 _I32 _CB); +DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BYTES _I32 _BYTES _I32 _CB); DEFINE_PRIM(_VOID, w_udp_recv_start, _UDP _CB_UDP_RECV); DEFINE_PRIM(_VOID, w_udp_recv_stop, _UDP); @@ -665,7 +664,7 @@ DEFINE_PRIM(_VOID, w_udp_recv_stop, _UDP); static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call2(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), varray *, NULL); + hl_call2(void, cb, vdynamic *, construct_error(status), varray *, NULL); else { int count = 0; struct addrinfo *cur; @@ -709,7 +708,7 @@ HL_PRIM void HL_NAME(w_getaddrinfo)(uv_loop_t *loop, vbyte *node, vbyte *service static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) - hl_call3(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(status)), status), vbyte *, NULL, vbyte *, NULL); + hl_call3(void, cb, vdynamic *, construct_error(status), vbyte *, NULL, vbyte *, NULL); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hostname, vbyte *, (vbyte *)service); hl_remove_root(UV_REQ_DATA(req)); From f844f5525fb518196e2feebc98c31482d960995b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Mon, 16 Sep 2019 16:53:23 +0100 Subject: [PATCH 13/22] hl-eval feature parity --- libs/uv/uv.c | 1206 ++++++++++++++++++++++++++++++++++++-------------- src/hl.h | 2 + 2 files changed, 887 insertions(+), 321 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 9c9cbf061..dd3af9e9f 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -14,49 +14,56 @@ // ------------- TYPES ---------------------------------------------- +/** + Type aliases, used when defining FFI signatures. +**/ + +// This is not quite accurate, since the type is a pointer-pointer. +#define _UV(name) "X" #name "_" + // Handle types -#define _LOOP _ABSTRACT(uv_loop_t) -#define _HANDLE _ABSTRACT(uv_handle_t) -#define _DIR _ABSTRACT(uv_dir_t) -#define _STREAM _ABSTRACT(uv_stream_t) -#define _TCP _ABSTRACT(uv_tcp_t) -#define _UDP _ABSTRACT(uv_udp_t) -#define _PIPE _ABSTRACT(uv_pipe_t) -#define _TTY _ABSTRACT(uv_tty_t) -#define _POLL _ABSTRACT(uv_poll_t) -#define _TIMER _ABSTRACT(uv_timer_t) -#define _PREPARE _ABSTRACT(uv_prepare_t) -#define _CHECK _ABSTRACT(uv_check_t) -#define _IDLE _ABSTRACT(uv_idle_t) -#define _ASYNC _ABSTRACT(uv_async_t) -#define _PROCESS _ABSTRACT(uv_process_t) -#define _FS_EVENT _ABSTRACT(uv_fs_event_t) -#define _FS_POLL _ABSTRACT(uv_fs_poll_t) -#define _SIGNAL _ABSTRACT(uv_signal_t) +#define _LOOP _UV(uv_loop_t) +#define _HANDLE _UV(uv_handle_t) +#define _DIR _UV(uv_dir_t) +#define _STREAM _UV(uv_stream_t) +#define _TCP _UV(uv_tcp_t) +#define _UDP _UV(uv_udp_t) +#define _PIPE _UV(uv_pipe_t) +#define _TTY _UV(uv_tty_t) +#define _POLL _UV(uv_poll_t) +#define _TIMER _UV(uv_timer_t) +#define _PREPARE _UV(uv_prepare_t) +#define _CHECK _UV(uv_check_t) +#define _IDLE _UV(uv_idle_t) +#define _ASYNC _UV(uv_async_t) +#define _PROCESS _UV(uv_process_t) +#define _FS_EVENT _UV(uv_fs_event_t) +#define _FS_POLL _UV(uv_fs_poll_t) +#define _SIGNAL _UV(uv_signal_t) // Request types -#define _REQ _ABSTRACT(uv_req_t) -#define _GETADDRINFO _ABSTRACT(uv_getaddrinfo_t) -#define _GETNAMEINFO _ABSTRACT(uv_getnameinfo_t) -#define _SHUTDOWN _ABSTRACT(uv_shutdown_t) -#define _WRITE _ABSTRACT(uv_write_t) -#define _CONNECT _ABSTRACT(uv_connect_t) -#define _UDP_SEND _ABSTRACT(uv_udp_send_t) -#define _FS _ABSTRACT(uv_fs_t) -#define _WORK _ABSTRACT(uv_work_t) +#define _REQ _UV(uv_req_t) +#define _GETADDRINFO _UV(uv_getaddrinfo_t) +#define _GETNAMEINFO _UV(uv_getnameinfo_t) +#define _SHUTDOWN _UV(uv_shutdown_t) +#define _WRITE _UV(uv_write_t) +#define _CONNECT _UV(uv_connect_t) +#define _UDP_SEND _UV(uv_udp_send_t) +#define _FS _UV(uv_fs_t) +#define _WORK _UV(uv_work_t) // Other types -#define _CPU_INFO _ABSTRACT(uv_cpu_info_t) -#define _INTERFACE_ADDRESS _ABSTRACT(uv_interface_address_t) -#define _DIRENT _ABSTRACT(uv_dirent_t) -#define _PASSWD _ABSTRACT(uv_passwd_t) -#define _UTSNAME _ABSTRACT(uv_utsname_t) -#define _FILE _ABSTRACT(uv_file) -// #define _STAT _ABSTRACT(uv_stat_t) -#define _BUF _ABSTRACT(uv_buf_t) +#define _CPU_INFO _UV(uv_cpu_info_t) +#define _INTERFACE_ADDRESS _UV(uv_interface_address_t) +#define _DIRENT _UV(uv_dirent_t) +// #define _PASSWD _UV(uv_passwd_t) +#define _UTSNAME _UV(uv_utsname_t) +#define _FILE _UV(uv_file) +// #define _STAT _UV(uv_stat_t) +#define _BUF _UV(uv_buf_t) // Haxe types @@ -65,6 +72,7 @@ // Callback types +#define _CB_NOERR _FUN(_VOID, _NO_ARG) #define _CB _FUN(_VOID, _ERROR) #define _CB_STR _FUN(_VOID, _ERROR _BYTES) #define _CB_BYTES _FUN(_VOID, _ERROR _BYTES _I32) @@ -75,26 +83,63 @@ #define _CB_FS_EVENT _FUN(_VOID, _ERROR _BYTES _I32) #define _CB_GAI _FUN(_VOID, _ERROR _ARR) #define _CB_GNI _FUN(_VOID, _ERROR _BYTES _BYTES) -#define _CB_UDP_RECV _FUN(_VOID, _ERROR _BYTES _I32 _DYN) +#define _CB_UDP_RECV _FUN(_VOID, _ERROR _BYTES _I32 _DYN _I32) // ------------- 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) +/** + The `data` field of handles and requests is used to store Haxe callbacks. + These callbacks are called from the various `handle_...` functions, after + pre-processing libuv results as necessary. At runtime, a callback is simply + a `value`. To ensure it is not garbage-collected, we add the data pointer of + the handle or request to HL's global GC roots, then remove it after the + callback is called. + + Handle-specific macros are defined further, in the HANDLE DATA section. +**/ + +// access the data of a request #define UV_REQ_DATA(r) (((uv_req_t *)(r))->data) +#define UV_REQ_DATA_A(r) ((void *)(&UV_REQ_DATA(r))) +// malloc a single value of the given type #define UV_ALLOC(t) ((t *)malloc(sizeof(t))) -#define UV_GC_ALLOC(t) ((t *)hl_gc_alloc_noptr(sizeof(t))) + +// unwrap an abstract block (see UV_ALLOC_CHECK notes below) +#define UV_UNWRAP(v, t) ((t *)*v) + +#define Connect_val(v) UV_UNWRAP(v, uv_connect_t) +#define Fs_val(v) UV_UNWRAP(v, uv_fs_t) +#define FsEvent_val(v) UV_UNWRAP(v, uv_fs_event_t) +#define GetAddrInfo_val(v) UV_UNWRAP(v, uv_getaddrinfo_t) +#define Handle_val(v) UV_UNWRAP(v, uv_handle_t) +#define Loop_val(v) UV_UNWRAP(v, uv_loop_t) +#define Pipe_val(v) UV_UNWRAP(v, uv_pipe_t) +#define Process_val(v) UV_UNWRAP(v, uv_process_t) +#define Shutdown_val(v) UV_UNWRAP(v, uv_shutdown_t) +#define Stream_val(v) UV_UNWRAP(v, uv_stream_t) +#define Tcp_val(v) UV_UNWRAP(v, uv_tcp_t) +#define Timer_val(v) UV_UNWRAP(v, uv_timer_t) +#define Udp_val(v) UV_UNWRAP(v, uv_udp_t) +#define UdpSend_val(v) UV_UNWRAP(v, uv_udp_send_t) +#define Write_val(v) UV_UNWRAP(v, uv_write_t) // ------------- HAXE CONSTRUCTORS ---------------------------------- +/** + To make it easier to construct values expected by the Haxe standard library, + the library provides constructors for various types. These are called from + the methods in this file and either returned or thrown back into Haxe code. +**/ + static vdynamic * (*construct_error)(int); static vdynamic * (*construct_fs_stat)(int, int, int, int, int, int, int, int, int, int, int, int); static vdynamic * (*construct_fs_dirent)(const char *name, int type); static vdynamic * (*construct_addrinfo_ipv4)(int ip); static vdynamic * (*construct_addrinfo_ipv6)(vbyte *ip); static vdynamic * (*construct_addrport)(vdynamic *addr, int port); +static vdynamic * (*construct_pipe_accept_socket)(uv_tcp_t **socket); +static vdynamic * (*construct_pipe_accept_pipe)(uv_pipe_t **pipe); HL_PRIM void HL_NAME(glue_register)( vclosure *c_error, @@ -102,7 +147,9 @@ HL_PRIM void HL_NAME(glue_register)( vclosure *c_fs_dirent, vclosure *c_addrinfo_ipv4, vclosure *c_addrinfo_ipv6, - vclosure *c_addrport + vclosure *c_addrport, + vclosure *c_pipe_accept_socket, + vclosure *c_pipe_accept_pipe ) { construct_error = (vdynamic * (*)(int))c_error->fun; construct_fs_stat = (vdynamic * (*)(int, int, int, int, int, int, int, int, int, int, int, int))c_fs_stat->fun; @@ -110,8 +157,9 @@ HL_PRIM void HL_NAME(glue_register)( construct_addrinfo_ipv4 = (vdynamic * (*)(int))c_addrinfo_ipv4->fun; construct_addrinfo_ipv6 = (vdynamic * (*)(vbyte *))c_addrinfo_ipv6->fun; construct_addrport = (vdynamic * (*)(vdynamic *, int))c_addrport->fun; + construct_pipe_accept_socket = (vdynamic * (*)(uv_tcp_t **))c_pipe_accept_socket->fun; + construct_pipe_accept_pipe = (vdynamic * (*)(uv_pipe_t **))c_pipe_accept_pipe->fun; } - DEFINE_PRIM( _VOID, glue_register, @@ -121,16 +169,36 @@ DEFINE_PRIM( _FUN(_DYN, _I32) _FUN(_DYN, _BYTES) _FUN(_DYN, _DYN _I32) + _FUN(_DYN, _TCP) + _FUN(_DYN, _PIPE) ); // ------------- ERROR HANDLING ------------------------------------- +/** + UV_ERROR throws an error with the given error code. + + UV_ALLOC_CHECK tries to allocate a variable of the given type with the given + name and throws an error if this fails. UV_ALLOC_CHECK_C is the same, but + allows specifying custom clean-up code before the error result is returned. + Allocation returns a value that is a pointer-pointer to the malloc'ed native + value. + + UV_ERROR_CHECK checks for a libuv error in the given int expression (indicated + by a negative value), and in case of an error, throws an error. Once again, + UV_ERROR_CHECK_C is the same, but allows specifying custom clean-up code. +**/ + +#define UV_ERROR(errno) hl_throw(construct_error(errno)) + #define UV_ALLOC_CHECK_C(var, type, cleanup) \ - type *var = UV_ALLOC(type); \ - if (var == NULL) { \ + type *_native = UV_ALLOC(type); \ + if (_native == NULL) { \ cleanup; \ - hl_throw(construct_error(0)); \ - } else {} + UV_ERROR(0); \ + } \ + type **var = hl_gc_alloc_noptr(sizeof(type *)); \ + *var = _native; #define UV_ALLOC_CHECK(var, type) UV_ALLOC_CHECK_C(var, type, ) @@ -138,8 +206,7 @@ DEFINE_PRIM( int __tmp_result = expr; \ if (__tmp_result < 0) { \ cleanup; \ - vdynamic *err = construct_error(__tmp_result); \ - hl_throw(err); \ + UV_ERROR(__tmp_result); \ } \ } while (0) @@ -147,55 +214,44 @@ DEFINE_PRIM( // ------------- LOOP ----------------------------------------------- -HL_PRIM uv_loop_t * HL_NAME(w_loop_init)(void) { +HL_PRIM uv_loop_t ** HL_NAME(w_loop_init)(void) { UV_ALLOC_CHECK(loop, uv_loop_t); - UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop)); + UV_ERROR_CHECK_C(uv_loop_init(Loop_val(loop)), free(Loop_val(loop))); return loop; } +DEFINE_PRIM(_LOOP, w_loop_init, _NO_ARG); -HL_PRIM void HL_NAME(w_loop_close)(uv_loop_t *loop) { - UV_ERROR_CHECK(uv_loop_close(loop)); - free(loop); +HL_PRIM void HL_NAME(w_loop_close)(uv_loop_t **loop) { + UV_ERROR_CHECK(uv_loop_close(Loop_val(loop))); + free(Loop_val(loop)); } +DEFINE_PRIM(_VOID, w_loop_close, _LOOP); -HL_PRIM bool HL_NAME(w_run)(uv_loop_t *loop, uv_run_mode mode) { - return uv_run(loop, mode) != 0; +HL_PRIM bool HL_NAME(w_run)(uv_loop_t **loop, uv_run_mode mode) { + return uv_run(Loop_val(loop), mode) != 0; } +DEFINE_PRIM(_BOOL, w_run, _LOOP _I32); -HL_PRIM bool HL_NAME(w_loop_alive)(uv_loop_t *loop) { - return uv_loop_alive(loop) != 0; +HL_PRIM void HL_NAME(w_stop)(uv_loop_t **loop) { + uv_stop(Loop_val(loop)); } +DEFINE_PRIM(_VOID, w_stop, _LOOP); -DEFINE_PRIM(_LOOP, w_loop_init, _NO_ARG); -DEFINE_PRIM(_VOID, w_loop_close, _LOOP); -DEFINE_PRIM(_LOOP, default_loop, _NO_ARG); -DEFINE_PRIM(_BOOL, w_run, _LOOP _I32); +HL_PRIM bool HL_NAME(w_loop_alive)(uv_loop_t **loop) { + return uv_loop_alive(Loop_val(loop)) != 0; +} DEFINE_PRIM(_BOOL, w_loop_alive, _LOOP); -DEFINE_PRIM(_VOID, stop, _LOOP); - -// ------------- HANDLE --------------------------------------------- -typedef struct { - vclosure *cb_close; -} uv_w_handle_t; - -static void handle_handle_cb_close(uv_handle_t *handle) { - vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_handle_t)->cb_close; - hl_call1(void, cb, vdynamic *, NULL); - free(UV_HANDLE_DATA(handle)); - free(handle); -} +// ------------- FILESYSTEM ----------------------------------------- -static void w_close(uv_handle_t *handle, vclosure *cb) { - UV_HANDLE_DATA_SUB(handle, uv_w_handle_t)->cb_close = cb; - uv_close(handle, handle_handle_cb_close); -} +/** + FS handlers all have the same structure. -//DEFINE_PRIM(_VOID, ref, _HANDLE); -//DEFINE_PRIM(_VOID, unref, _HANDLE); -//DEFINE_PRIM(_VOID, w_close, _HANDLE _CB); + The async version (no suffix) calls the callback with either the result in + the second argument, or an error in the first argument. -// ------------- FILESYSTEM ----------------------------------------- + The sync version (`_sync` suffix) returns the result directly. +**/ static void handle_fs_cb(uv_fs_t *req) { vclosure *cb = UV_REQ_DATA(req); @@ -204,10 +260,11 @@ static void handle_fs_cb(uv_fs_t *req) { else hl_call1(void, cb, vdynamic *, NULL); uv_fs_req_cleanup(req); - hl_remove_root(UV_REQ_DATA(req)); + hl_remove_root(UV_REQ_DATA_A(req)); free(req); } -static void handle_fs_cb_sync(uv_fs_t *req) { +static void handle_fs_cb_sync(uv_fs_t **req_w) { + uv_fs_t *req = Fs_val(req_w); /* TODO: should we call uv_fs_req_cleanup on error here? */ UV_ERROR_CHECK_C(req->result, free(req)); uv_fs_req_cleanup(req); @@ -225,10 +282,11 @@ static void handle_fs_cb_sync(uv_fs_t *req) { hl_call2(void, cb, vdynamic *, NULL, type2, value2); \ } \ uv_fs_req_cleanup(req); \ - hl_remove_root(UV_REQ_DATA(req)); \ + hl_remove_root(UV_REQ_DATA_A(req)); \ free(req); \ } \ - static type2 name ## _sync(uv_fs_t *req) { \ + static type2 name ## _sync(uv_fs_t **req_w) { \ + uv_fs_t *req = Fs_val(req_w); \ /* TODO: should we call uv_fs_req_cleanup on error here? */ \ UV_ERROR_CHECK_C(req->result, free(req)); \ type2 value2; \ @@ -238,6 +296,7 @@ static void handle_fs_cb_sync(uv_fs_t *req) { return value2; \ } +// TODO: return unchanged bytes, do String.fromUTF8 on Haxe side UV_FS_HANDLER(handle_fs_cb_bytes, vbyte *, value2 = (vbyte *)hl_to_utf16((const char *)req->ptr)); UV_FS_HANDLER(handle_fs_cb_path, vbyte *, value2 = (vbyte *)hl_to_utf16((const char *)req->path)); UV_FS_HANDLER(handle_fs_cb_int, int, value2 = req->result); @@ -269,177 +328,304 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { } value2 = hl_alloc_array(&hlt_dyn, count); for (int i = 0; i < count; i++) { - hl_aptr(value2, vdynamic *)[i] = last->v; + hl_aptr(value2, vdynamic *)[count - i - 1] = last->v; vlist *next = last->next; free(last); last = next; } }); -#define UV_REQ_WRAP(name, reqtype, sign, call, ffi, handler) \ - HL_PRIM void HL_NAME(w_ ## name)(sign, vclosure *cb) { \ - UV_ALLOC_CHECK(req, reqtype); \ - UV_REQ_DATA(req) = (void *)cb; \ - UV_ERROR_CHECK_C(uv_ ## name(req, call, handler), free(req)); \ - hl_add_root(UV_REQ_DATA(req)); \ - } \ - DEFINE_PRIM(_VOID, w_ ## name, ffi); -#define UV_REQ_WRAP_LOOP(name, reqtype, sign, call, ffi, handler) \ - HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t *loop, sign, vclosure *cb) { \ - UV_ALLOC_CHECK(req, reqtype); \ - UV_REQ_DATA(req) = (void *)cb; \ - UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, handler), free(req)); \ - hl_add_root(UV_REQ_DATA(req)); \ +/** + Most FS functions from libuv can be wrapped with FS_WRAP (or one of the + FS_WRAP# variants defined below) - create a request, register a callback for + it, register the callback with the GC, perform request. Then, either in the + handler function (synchronous or asynchronous), the result is checked and + given to the Haxe callback if successful, with the appropriate value + conversions done, as defined in the various UV_FS_HANDLERs above. +**/ + +#define FS_WRAP(name, ret, sign, precall, call, ffiret, ffi, ffihandler, handler, doret) \ + HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t **loop, sign, vclosure *cb) { \ + UV_ALLOC_CHECK(req, uv_fs_t); \ + UV_REQ_DATA(Fs_val(req)) = (void *)cb; \ + hl_add_root(UV_REQ_DATA_A(Fs_val(req))); \ + precall \ + UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, handler), free(Fs_val(req))); \ } \ - DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi); -#define UV_REQ_WRAP_LOOP_SYNC(name, ret, reqtype, sign, call, ffiret, ffi, handler, doret) \ - HL_PRIM ret HL_NAME(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)); \ + DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi ffihandler); \ + HL_PRIM ret HL_NAME(w_ ## name ## _sync)(uv_loop_t **loop, sign) { \ + UV_ALLOC_CHECK(req, uv_fs_t); \ + precall \ + UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), free(Fs_val(req))); \ doret handler ## _sync(req); \ } \ DEFINE_PRIM(ffiret, w_ ## name ## _sync, _LOOP ffi); #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, ret, arg1, ffiret, ffi, ffihandler, handler, doret) \ + FS_WRAP(name, ret, arg1 _arg1, , _arg1, ffiret, ffi, ffihandler, handler, doret); +#define FS_WRAP2(name, ret, arg1, arg2, ffiret, ffi, ffihandler, handler, doret) \ + FS_WRAP(name, ret, arg1 _arg1 COMMA arg2 _arg2, , _arg1 COMMA _arg2, ffiret, ffi, ffihandler, handler, doret); +#define FS_WRAP3(name, ret, arg1, arg2, arg3, ffiret, ffi, ffihandler, handler, doret) \ + FS_WRAP(name, ret, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, , _arg1 COMMA _arg2 COMMA _arg3, ffiret, ffi, ffihandler, handler, doret); +#define FS_WRAP4(name, ret, arg1, arg2, arg3, arg4, ffiret, ffi, ffihandler, handler, doret) \ + FS_WRAP(name, ret, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, , _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffiret, ffi, ffihandler, handler, doret); + +FS_WRAP1(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP3(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); +FS_WRAP1(fs_unlink, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2(fs_mkdir, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1(fs_mkdtemp, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_path, return); +FS_WRAP1(fs_rmdir, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2(fs_scandir, varray *, const char *, int, _ARR, _BYTES _I32, _CB_SCANDIR, handle_fs_cb_scandir, return); +FS_WRAP1(fs_stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1(fs_fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP2(fs_rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP1(fs_fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP1(fs_fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP2(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I32, _CB, 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, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2(fs_chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2(fs_fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); +FS_WRAP3(fs_utime, void, const char*, double, double, _VOID, _BYTES _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP3(fs_futime, void, uv_file, double, double, _VOID, _FILE _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP2(fs_link, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP3(fs_symlink, void, const char*, const char*, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1(fs_readlink, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP1(fs_realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP3(fs_chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP3(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); /** - 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. + `fs_read` and `fs_write` require a tiny bit of setup just before the libuv + request is actually started; namely, a buffer structure needs to be set up, + which is simply a wrapper of a pointer to the HL bytes value. + + libuv actually supports multiple buffers in both calls, but this is not + mirrored in the Haxe API, so only a single-buffer call is used. **/ -HL_PRIM void HL_NAME(w_fs_read)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_fs_t); - UV_REQ_DATA(req) = (void *)cb; - uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); - UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, &buf, 1, position, handle_fs_cb_int), free(req)); - hl_add_root(UV_REQ_DATA(req)); +FS_WRAP(fs_read, + int, + uv_file file COMMA vbyte *data COMMA int offset COMMA int length COMMA int position, + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length);, + file COMMA &buf COMMA 1 COMMA position, + _I32, + _FILE _BYTES _I32 _I32 _I32, + _CB_INT, + handle_fs_cb_int, + return); + +FS_WRAP(fs_write, + int, + uv_file file COMMA vbyte *data COMMA int offset COMMA int length COMMA int position, + uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length);, + file COMMA &buf COMMA 1 COMMA position, + _I32, + _FILE _BYTES _I32 _I32 _I32, + _CB_INT, + handle_fs_cb_int, + return); + +// ------------- HANDLE DATA ---------------------------------------- + +/** + There is a single `void *data` field on requests and handles. For requests, + we use this to directly store the pointer to the callback function. For + handles, however, it is sometimes necessary to register multiple different + callbacks, hence a separate allocated struct is needed to hold them all. + All of the fields of the struct are registered with the garbage collector + immediately upon creation, although initially some of the callback fields are + set to NULL pointers. +**/ + +#define UV_HANDLE_DATA(h) (((uv_handle_t *)(h))->data) +#define UV_HANDLE_DATA_SUB(h, t) (((uv_w_handle_t *)UV_HANDLE_DATA(h))->u.t) + +typedef struct { + vclosure *cb_close; + union { + struct { + vclosure *cb1; + vclosure *cb2; + } all; + struct { + vclosure *cb_fs_event; + vclosure *unused1; + } fs_event; + struct { + vclosure *cb_read; + vclosure *cb_connection; + } stream; + struct { + vclosure *cb_read; + vclosure *cb_connection; + } tcp; + struct { + vclosure *cb_read; + vclosure *unused1; + } udp; + struct { + vclosure *cb_timer; + vclosure *unused1; + } timer; + struct { + vclosure *cb_exit; + vclosure *unused1; + } process; + struct { + vclosure *unused1; + vclosure *unused2; + } pipe; + } u; +} uv_w_handle_t; + +static uv_w_handle_t *alloc_data_fs_event(vclosure *cb_fs_event) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + data->u.fs_event.cb_fs_event = cb_fs_event; + hl_add_root(&(data->u.fs_event.cb_fs_event)); + } + return data; } -HL_PRIM int HL_NAME(w_fs_read_sync)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position) { - UV_ALLOC_CHECK(req, uv_fs_t); - uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); - UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, &buf, 1, position, NULL), free(req)); - return handle_fs_cb_int_sync(req); +static uv_w_handle_t *alloc_data_tcp(vclosure *cb_read, vclosure *cb_connection) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + data->u.tcp.cb_read = cb_read; + hl_add_root(&(data->u.tcp.cb_read)); + data->u.tcp.cb_connection = cb_connection; + hl_add_root(&(data->u.tcp.cb_connection)); + } + return data; } -HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, vbyte *data, int32_t offset, int32_t length, int32_t position, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_fs_t); - UV_REQ_DATA(req) = (void *)cb; - uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); - UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, &buf, 1, position, 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, vbyte *data, int32_t offset, int32_t length, int32_t position) { - UV_ALLOC_CHECK(req, uv_fs_t); - uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length); - UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, &buf, 1, position, NULL), free(req)); - return handle_fs_cb_int_sync(req); -} - -DEFINE_PRIM(_VOID, w_fs_read, _LOOP _FILE _BYTES _I32 _I32 _I32 _CB_INT); -DEFINE_PRIM(_I32, w_fs_read_sync, _LOOP _FILE _BYTES _I32 _I32 _I32); -DEFINE_PRIM(_VOID, w_fs_write, _LOOP _FILE _BYTES _I32 _I32 _I32 _CB_INT); -DEFINE_PRIM(_I32, w_fs_write_sync, _LOOP _FILE _BYTES _I32 _I32 _I32); - -FS_WRAP1_LOOP(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP3_LOOP(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); -FS_WRAP1_LOOP(fs_unlink, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_mkdir, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP1_LOOP(fs_mkdtemp, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_path, return); -FS_WRAP1_LOOP(fs_rmdir, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_scandir, varray *, const char *, int, _ARR, _BYTES _I32, _CB_SCANDIR, handle_fs_cb_scandir, return); -FS_WRAP1_LOOP(fs_stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP1_LOOP(fs_fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP1_LOOP(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP2_LOOP(fs_rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); -FS_WRAP1_LOOP(fs_fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP1_LOOP(fs_fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I32, _CB, handle_fs_cb, ); -FS_WRAP4_LOOP(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_access, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); -FS_WRAP3_LOOP(fs_utime, void, const char*, double, double, _VOID, _BYTES _F64 _F64, _CB, handle_fs_cb, ); -FS_WRAP3_LOOP(fs_futime, void, uv_file, double, double, _VOID, _FILE _F64 _F64, _CB, handle_fs_cb, ); -FS_WRAP2_LOOP(fs_link, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); -FS_WRAP3_LOOP(fs_symlink, void, const char*, const char*, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP1_LOOP(fs_readlink, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); -FS_WRAP1_LOOP(fs_realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); -FS_WRAP3_LOOP(fs_chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); -FS_WRAP3_LOOP(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); +static uv_w_handle_t *alloc_data_udp(vclosure *cb_read) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + data->u.udp.cb_read = cb_read; + hl_add_root(&(data->u.udp.cb_read)); + } + return data; +} + +static uv_w_handle_t *alloc_data_timer(vclosure *cb_timer) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + data->u.timer.cb_timer = cb_timer; + hl_add_root(&(data->u.timer.cb_timer)); + } + return data; +} + +static uv_w_handle_t *alloc_data_process(vclosure *cb_exit) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + data->u.process.cb_exit = cb_exit; + hl_add_root(&(data->u.process.cb_exit)); + } + return data; +} + +static uv_w_handle_t *alloc_data_pipe(void) { + uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); + if (data != NULL) { + data->cb_close = NULL; + hl_add_root(&(data->cb_close)); + } + return data; +} + +static void unalloc_data(uv_w_handle_t *data) { + hl_remove_root(&(data->cb_close)); + hl_remove_root(&(data->u.all.cb1)); + hl_remove_root(&(data->u.all.cb2)); + free(data); +} + +static void handle_close_cb(uv_handle_t *handle) { + vclosure *cb = ((uv_w_handle_t *)UV_HANDLE_DATA(handle))->cb_close; + hl_call1(void, cb, vdynamic *, NULL); + unalloc_data(UV_HANDLE_DATA(handle)); + free(handle); +} + +HL_PRIM void HL_NAME(w_close)(uv_handle_t **handle, vclosure *cb) { + ((uv_w_handle_t *)UV_HANDLE_DATA(Handle_val(handle)))->cb_close = cb; + uv_close(Handle_val(handle), handle_close_cb); +} +DEFINE_PRIM(_VOID, w_close, _HANDLE _CB); + +HL_PRIM void HL_NAME(w_ref)(uv_handle_t **handle) { + uv_ref(Handle_val(handle)); +} +DEFINE_PRIM(_VOID, w_ref, _HANDLE); + +HL_PRIM void HL_NAME(w_unref)(uv_handle_t **handle) { + uv_unref(Handle_val(handle)); +} +DEFINE_PRIM(_VOID, w_unref, _HANDLE); // ------------- FILESYSTEM EVENTS ---------------------------------- static void handle_fs_event_cb(uv_fs_event_t *handle, const char *filename, int events, int status) { - vclosure *cb = UV_HANDLE_DATA(handle); + vclosure *cb = UV_HANDLE_DATA_SUB(handle, fs_event).cb_fs_event; if (status < 0) hl_call3(void, cb, vdynamic *, construct_error(status), vbyte *, NULL, int, 0); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hl_to_utf16((const char *)filename), int, events); } -HL_PRIM uv_fs_event_t *HL_NAME(w_fs_event_start)(uv_loop_t *loop, const char *path, bool persistent, bool recursive, vclosure *cb) { +HL_PRIM uv_fs_event_t **HL_NAME(w_fs_event_start)(uv_loop_t **loop, const char *path, bool recursive, vclosure *cb) { UV_ALLOC_CHECK(handle, uv_fs_event_t); - UV_ERROR_CHECK_C(uv_fs_event_init(loop, handle), free(handle)); - UV_HANDLE_DATA(handle) = (void *)cb; - hl_add_root(UV_HANDLE_DATA(handle)); - UV_ERROR_CHECK_C(uv_fs_event_start(handle, handle_fs_event_cb, path, recursive ? UV_FS_EVENT_RECURSIVE : 0), free(handle)); - if (!persistent) - uv_unref((uv_handle_t *)handle); + UV_ERROR_CHECK_C(uv_fs_event_init(Loop_val(loop), FsEvent_val(handle)), free(FsEvent_val(handle))); + UV_HANDLE_DATA(FsEvent_val(handle)) = alloc_data_fs_event(cb); + if (UV_HANDLE_DATA(FsEvent_val(handle)) == NULL) + UV_ERROR(0); + UV_ERROR_CHECK_C( + uv_fs_event_start(FsEvent_val(handle), handle_fs_event_cb, path, recursive ? UV_FS_EVENT_RECURSIVE : 0), + { unalloc_data(UV_HANDLE_DATA(FsEvent_val(handle))); free(FsEvent_val(handle)); } + ); return handle; } - -static void handle_close_cb(uv_handle_t *handle) { - vclosure *cb = UV_HANDLE_DATA(handle); - hl_call1(void, cb, vdynamic *, NULL); - hl_remove_root(UV_HANDLE_DATA(handle)); - free(handle); -} - -HL_PRIM void HL_NAME(w_fs_event_stop)(uv_fs_event_t *handle, vclosure *cb) { - UV_ERROR_CHECK_C(uv_fs_event_stop(handle), free(handle)); - UV_HANDLE_DATA(handle) = (void *)cb; - uv_close((uv_handle_t *)handle, handle_close_cb); +DEFINE_PRIM(_FS_EVENT, w_fs_event_start, _LOOP _BYTES _BOOL _CB_FS_EVENT); + +HL_PRIM void HL_NAME(w_fs_event_stop)(uv_fs_event_t **handle, vclosure *cb) { + UV_ERROR_CHECK_C( + uv_fs_event_stop(FsEvent_val(handle)), + { unalloc_data(UV_HANDLE_DATA(FsEvent_val(handle))); free(FsEvent_val(handle)); } + ); + ((uv_w_handle_t *)UV_HANDLE_DATA(FsEvent_val(handle)))->cb_close = cb; + uv_close(Handle_val(handle), handle_close_cb); } - -DEFINE_PRIM(_FS_EVENT, w_fs_event_start, _LOOP _BYTES _BOOL _BOOL _CB_FS_EVENT); DEFINE_PRIM(_VOID, w_fs_event_stop, _FS_EVENT _CB); // ------------- STREAM --------------------------------------------- -typedef struct { - uv_w_handle_t w_handle; - vclosure *cb_read; - vclosure *cb_connection; -} uv_w_stream_t; - static void handle_stream_cb(uv_req_t *req, int status) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) hl_call1(void, cb, vdynamic *, construct_error(status)); else hl_call1(void, cb, vdynamic *, NULL); - hl_remove_root(UV_REQ_DATA(req)); + hl_remove_root(UV_REQ_DATA_A(req)); free(req); } static void handle_stream_cb_connection(uv_stream_t *stream, int status) { - vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection; + vclosure *cb = UV_HANDLE_DATA_SUB(stream, stream).cb_connection; if (status < 0) hl_call1(void, cb, vdynamic *, construct_error(status)); else @@ -452,37 +638,46 @@ static void handle_stream_cb_alloc(uv_handle_t *handle, size_t suggested_size, u } static void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_buf_t *buf) { - vclosure *cb = UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read; + vclosure *cb = UV_HANDLE_DATA_SUB(stream, stream).cb_read; if (nread < 0) hl_call3(void, cb, vdynamic *, construct_error(nread), vbyte *, NULL, int, 0); else - hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len); + hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, nread); +} + +HL_PRIM void HL_NAME(w_shutdown)(uv_stream_t **stream, vclosure *cb) { + UV_ALLOC_CHECK(req, uv_shutdown_t); + UV_REQ_DATA(Shutdown_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Shutdown_val(req))); + UV_ERROR_CHECK_C(uv_shutdown(Shutdown_val(req), Stream_val(stream), (void (*)(uv_shutdown_t *, int))handle_stream_cb), free(Shutdown_val(req))); } +DEFINE_PRIM(_VOID, w_shutdown, _STREAM _CB); -static void w_listen(uv_stream_t *stream, int backlog, vclosure *cb) { - UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_connection = cb; - UV_ERROR_CHECK(uv_listen(stream, backlog, handle_stream_cb_connection)); +HL_PRIM void HL_NAME(w_listen)(uv_stream_t **stream, int backlog, vclosure *cb) { + UV_HANDLE_DATA_SUB(Stream_val(stream), stream).cb_connection = cb; + UV_ERROR_CHECK(uv_listen(Stream_val(stream), backlog, handle_stream_cb_connection)); } +DEFINE_PRIM(_VOID, w_listen, _STREAM _I32 _CB); -static void w_write(uv_stream_t *stream, const uv_buf_t *buf, vclosure *cb) { - // note: signature different due to no struct passing support in HL - // currently only a single uv_buf_t can be passed at a time +HL_PRIM void HL_NAME(w_write)(uv_stream_t **stream, const vbyte *data, int length, vclosure *cb) { UV_ALLOC_CHECK(req, uv_write_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_write(req, stream, buf, 1, (void (*)(uv_write_t *, int))handle_stream_cb), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_REQ_DATA(Write_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Write_val(req))); + uv_buf_t buf = uv_buf_init((char *)data, length); + UV_ERROR_CHECK_C(uv_write(Write_val(req), Stream_val(stream), &buf, 1, (void (*)(uv_write_t *, int))handle_stream_cb), free(Write_val(req))); } +DEFINE_PRIM(_VOID, w_write, _STREAM _BYTES _I32 _CB); -static void w_read_start(uv_stream_t *stream, vclosure *cb) { - UV_HANDLE_DATA_SUB(stream, uv_w_stream_t)->cb_read = cb; - UV_ERROR_CHECK(uv_read_start(stream, handle_stream_cb_alloc, handle_stream_cb_read)); +HL_PRIM void HL_NAME(w_read_start)(uv_stream_t **stream, vclosure *cb) { + UV_HANDLE_DATA_SUB(Stream_val(stream), stream).cb_read = cb; + UV_ERROR_CHECK(uv_read_start(Stream_val(stream), handle_stream_cb_alloc, handle_stream_cb_read)); } +DEFINE_PRIM(_VOID, w_read_start, _STREAM _CB_BYTES); -//DEFINE_PRIM(_VOID, w_listen, _STREAM _I32 _CB); -//DEFINE_PRIM(_VOID, w_write, _STREAM _BUF _CB); -//DEFINE_PRIM(_VOID, w_read_start, _STREAM _CB_READ); -//DEFINE_PRIM(_VOID, read_stop, _STREAM); -UV_REQ_WRAP(shutdown, uv_shutdown_t, uv_stream_t *stream, stream, _STREAM _CB, (void (*)(uv_shutdown_t *, int))handle_stream_cb); +HL_PRIM void HL_NAME(w_read_stop)(uv_stream_t **stream) { + UV_ERROR_CHECK(uv_read_stop(Stream_val(stream))); +} +DEFINE_PRIM(_VOID, w_read_stop, _STREAM); // ------------- NETWORK MACROS ------------------------------------- @@ -500,67 +695,96 @@ UV_REQ_WRAP(shutdown, uv_shutdown_t, uv_stream_t *stream, stream, _STREAM _CB, ( // ------------- TCP ------------------------------------------------ -HL_PRIM uv_tcp_t *HL_NAME(w_tcp_init)(uv_loop_t *loop) { +HL_PRIM uv_tcp_t **HL_NAME(w_tcp_init)(uv_loop_t **loop) { UV_ALLOC_CHECK(handle, uv_tcp_t); - UV_ERROR_CHECK_C(uv_tcp_init(loop, handle), free(handle)); - UV_ALLOC_CHECK_C(data, uv_w_stream_t, free(handle)); - memset(data, 0, sizeof(uv_w_stream_t)); - UV_HANDLE_DATA(handle) = data; + UV_ERROR_CHECK_C(uv_tcp_init(Loop_val(loop), Tcp_val(handle)), free(Tcp_val(handle))); + UV_HANDLE_DATA(Tcp_val(handle)) = alloc_data_tcp(NULL, NULL); + if (UV_HANDLE_DATA(Tcp_val(handle)) == NULL) + UV_ERROR(0); return handle; } +DEFINE_PRIM(_TCP, w_tcp_init, _LOOP); -HL_PRIM void HL_NAME(w_tcp_nodelay)(uv_tcp_t *handle, bool enable) { - UV_ERROR_CHECK(uv_tcp_nodelay(handle, enable ? 1 : 0)); +HL_PRIM void HL_NAME(w_tcp_nodelay)(uv_tcp_t **handle, bool enable) { + UV_ERROR_CHECK(uv_tcp_nodelay(Tcp_val(handle), enable ? 1 : 0)); } +DEFINE_PRIM(_VOID, w_tcp_nodelay, _TCP _BOOL); -HL_PRIM void HL_NAME(w_tcp_keepalive)(uv_tcp_t *handle, bool enable, unsigned int delay) { - UV_ERROR_CHECK(uv_tcp_keepalive(handle, enable ? 1 : 0, delay)); +HL_PRIM void HL_NAME(w_tcp_keepalive)(uv_tcp_t **handle, bool enable, unsigned int delay) { + UV_ERROR_CHECK(uv_tcp_keepalive(Tcp_val(handle), enable ? 1 : 0, delay)); } +DEFINE_PRIM(_VOID, w_tcp_keepalive, _TCP _BOOL _I32); -HL_PRIM uv_tcp_t *HL_NAME(w_tcp_accept)(uv_loop_t *loop, uv_tcp_t *server) { - uv_tcp_t *client = HL_NAME(w_tcp_init)(loop); - UV_ERROR_CHECK_C(uv_accept((uv_stream_t *)server, (uv_stream_t *)client), free(client)); +HL_PRIM uv_tcp_t **HL_NAME(w_tcp_accept)(uv_loop_t **loop, uv_tcp_t **server) { + uv_tcp_t **client = HL_NAME(w_tcp_init)(loop); + UV_ERROR_CHECK_C(uv_accept(Stream_val(server), Stream_val(client)), free(Tcp_val(client))); return client; } +DEFINE_PRIM(_TCP, w_tcp_accept, _LOOP _TCP); -HL_PRIM void HL_NAME(w_tcp_bind_ipv4)(uv_tcp_t *handle, int host, int port) { +HL_PRIM void HL_NAME(w_tcp_bind_ipv4)(uv_tcp_t **handle, int host, int port) { UV_SOCKADDR_IPV4(addr, host, port); - UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); + UV_ERROR_CHECK(uv_tcp_bind(Tcp_val(handle), (const struct sockaddr *)&addr, 0)); } +DEFINE_PRIM(_VOID, w_tcp_bind_ipv4, _TCP _I32 _I32); -HL_PRIM void HL_NAME(w_tcp_bind_ipv6)(uv_tcp_t *handle, vbyte *host, int port) { +HL_PRIM void HL_NAME(w_tcp_bind_ipv6)(uv_tcp_t **handle, vbyte *host, int port, bool ipv6only) { UV_SOCKADDR_IPV6(addr, host, port); - UV_ERROR_CHECK(uv_tcp_bind(handle, (const struct sockaddr *)&addr, 0)); + UV_ERROR_CHECK(uv_tcp_bind(Tcp_val(handle), (const struct sockaddr *)&addr, ipv6only ? UV_TCP_IPV6ONLY : 0)); } +DEFINE_PRIM(_VOID, w_tcp_bind_ipv6, _TCP _BYTES _I32 _BOOL); -HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t *handle, int host, int port, vclosure *cb) { +HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t **handle, int host, int port, vclosure *cb) { UV_SOCKADDR_IPV4(addr, host, port); UV_ALLOC_CHECK(req, uv_connect_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_REQ_DATA(Connect_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Connect_val(req))); + UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(Connect_val(req))); } +DEFINE_PRIM(_VOID, w_tcp_connect_ipv4, _TCP _I32 _I32 _CB); -HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t *handle, vbyte *host, int port, vclosure *cb) { +HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t **handle, vbyte *host, int port, vclosure *cb) { UV_SOCKADDR_IPV6(addr, host, port); UV_ALLOC_CHECK(req, uv_connect_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_tcp_connect(req, handle, (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_REQ_DATA(Connect_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Connect_val(req))); + UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(Connect_val(req))); +} +DEFINE_PRIM(_VOID, w_tcp_connect_ipv6, _TCP _BYTES _I32 _CB); + +static vdynamic *w_getname(struct sockaddr_storage *addr) { + vdynamic *w_addr; + if (addr->ss_family == AF_INET) { + w_addr = construct_addrinfo_ipv4(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); + return construct_addrport(w_addr, ntohs(((struct sockaddr_in *)addr)->sin_port)); + } else if (addr->ss_family == AF_INET6) { + w_addr = construct_addrinfo_ipv6(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr); + return construct_addrport(w_addr, ntohs(((struct sockaddr_in6 *)addr)->sin6_port)); + } + UV_ERROR(0); +} + +HL_PRIM vdynamic *HL_NAME(w_tcp_getsockname)(uv_tcp_t **handle) { + struct sockaddr_storage storage; + int dummy = sizeof(struct sockaddr_storage); + UV_ERROR_CHECK(uv_tcp_getsockname(Tcp_val(handle), (struct sockaddr *)&storage, &dummy)); + return w_getname(&storage); } +DEFINE_PRIM(_DYN, w_tcp_getsockname, _TCP); +HL_PRIM vdynamic *HL_NAME(w_tcp_getpeername)(uv_tcp_t **handle) { + struct sockaddr_storage storage; + int dummy = sizeof(struct sockaddr_storage); + UV_ERROR_CHECK(uv_tcp_getpeername(Tcp_val(handle), (struct sockaddr *)&storage, &dummy)); + return w_getname(&storage); +} +DEFINE_PRIM(_DYN, w_tcp_getpeername, _TCP); + +/* HL_PRIM void HL_NAME(w_tcp_read_stop)(uv_tcp_t *stream) { uv_read_stop((uv_stream_t *)stream); } -DEFINE_PRIM(_TCP, w_tcp_init, _LOOP); -DEFINE_PRIM(_VOID, w_tcp_nodelay, _TCP _BOOL); -DEFINE_PRIM(_VOID, w_tcp_keepalive, _TCP _BOOL _I32); -DEFINE_PRIM(_TCP, w_tcp_accept, _LOOP _TCP); -DEFINE_PRIM(_VOID, w_tcp_bind_ipv4, _TCP _I32 _I32); -DEFINE_PRIM(_VOID, w_tcp_bind_ipv6, _TCP _BYTES _I32); -DEFINE_PRIM(_VOID, w_tcp_connect_ipv4, _TCP _I32 _I32 _CB); -DEFINE_PRIM(_VOID, w_tcp_connect_ipv6, _TCP _BYTES _I32 _CB); DEFINE_PRIM(_VOID, w_tcp_read_stop, _TCP); #define UV_TCP_CAST(name, basename, basetype, sign, call, ffi) \ @@ -574,94 +798,153 @@ UV_TCP_CAST(w_tcp_listen, w_listen, uv_stream_t, int backlog COMMA vclosure *cb, UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); +*/ // ------------- UDP ------------------------------------------------ -typedef struct { - uv_w_handle_t w_handle; - vclosure *cb_read; -} uv_w_udp_t; - static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned int flags) { - vclosure *cb = UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read; + vclosure *cb = UV_HANDLE_DATA_SUB(handle, udp).cb_read; if (nread < 0) - hl_call4(void, cb, vdynamic *, construct_error(nread), vbyte *, NULL, int, 0, vdynamic *, NULL); + hl_call5(void, cb, vdynamic *, construct_error(nread), vbyte *, NULL, int, 0, vdynamic *, 0, int, 0); else { - vdynamic *w_addrport = NULL; + vdynamic *w_addr = NULL; + int w_port = 0; if (addr != NULL) { - vdynamic *w_addr; if (addr->sa_family == AF_INET) { - w_addr = construct_addrinfo_ipv4(((struct sockaddr_in *)addr)->sin_addr.s_addr); - w_addrport = construct_addrport(w_addr, ((struct sockaddr_in *)addr)->sin_port); + w_addr = construct_addrinfo_ipv4(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); + w_port = ntohs(((struct sockaddr_in *)addr)->sin_port); } else if (addr->sa_family == AF_INET6) { w_addr = construct_addrinfo_ipv6(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr); - w_addrport = construct_addrport(w_addr, ((struct sockaddr_in6 *)addr)->sin6_port); + w_port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); } } - hl_call4(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, buf->len, vdynamic *, w_addrport); + hl_call5(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)buf->base, int, nread, vdynamic *, w_addr, int, w_port); } } -HL_PRIM uv_udp_t *HL_NAME(w_udp_init)(uv_loop_t *loop) { +HL_PRIM uv_udp_t **HL_NAME(w_udp_init)(uv_loop_t **loop) { UV_ALLOC_CHECK(handle, uv_udp_t); - UV_ERROR_CHECK_C(uv_udp_init(loop, handle), free(handle)); - UV_ALLOC_CHECK_C(data, uv_w_udp_t, free(handle)); - memset(data, 0, sizeof(uv_w_udp_t)); - UV_HANDLE_DATA(handle) = data; + UV_ERROR_CHECK_C(uv_udp_init(Loop_val(loop), Udp_val(handle)), free(Udp_val(handle))); + UV_HANDLE_DATA(Udp_val(handle)) = alloc_data_udp(NULL); + if (UV_HANDLE_DATA(Udp_val(handle)) == NULL) + UV_ERROR(0); return handle; } +DEFINE_PRIM(_UDP, w_udp_init, _LOOP); -HL_PRIM void HL_NAME(w_udp_bind_ipv4)(uv_udp_t *handle, int host, int port) { +HL_PRIM void HL_NAME(w_udp_bind_ipv4)(uv_udp_t **handle, int host, int port) { UV_SOCKADDR_IPV4(addr, host, port); - UV_ERROR_CHECK(uv_udp_bind(handle, (const struct sockaddr *)&addr, 0)); + UV_ERROR_CHECK(uv_udp_bind(Udp_val(handle), (const struct sockaddr *)&addr, 0)); } +DEFINE_PRIM(_VOID, w_udp_bind_ipv4, _UDP _I32 _I32); -HL_PRIM void HL_NAME(w_udp_bind_ipv6)(uv_udp_t *handle, vbyte *host, int port) { +HL_PRIM void HL_NAME(w_udp_bind_ipv6)(uv_udp_t **handle, vbyte *host, int port, bool ipv6only) { UV_SOCKADDR_IPV6(addr, host, port); - UV_ERROR_CHECK(uv_udp_bind(handle, (const struct sockaddr *)&addr, 0)); + UV_ERROR_CHECK(uv_udp_bind(Udp_val(handle), (const struct sockaddr *)&addr, ipv6only ? UV_UDP_IPV6ONLY : 0)); } +DEFINE_PRIM(_VOID, w_udp_bind_ipv6, _UDP _BYTES _I32 _BOOL); -HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t *handle, vbyte *data, int length, int host, int port, vclosure *cb) { +HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t **handle, vbyte *data, int length, int host, int port, vclosure *cb) { UV_SOCKADDR_IPV4(addr, host, port); UV_ALLOC_CHECK(req, uv_udp_send_t); - UV_REQ_DATA(req) = (void *)cb; + UV_REQ_DATA(UdpSend_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(UdpSend_val(req))); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_udp_send(req, handle, &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(UdpSend_val(req))); } +DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BYTES _I32 _I32 _I32 _CB); -HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t *handle, vbyte *data, int length, vbyte *host, int port, vclosure *cb) { - // note: signature different due to no struct passing support in HL - // currently only a single uv_buf_t can be passed at a time +HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t **handle, vbyte *data, int length, vbyte *host, int port, vclosure *cb) { UV_SOCKADDR_IPV6(addr, host, port); UV_ALLOC_CHECK(req, uv_udp_send_t); - UV_REQ_DATA(req) = (void *)cb; + UV_REQ_DATA(UdpSend_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(UdpSend_val(req))); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_udp_send(req, handle, &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(UdpSend_val(req))); } +DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BYTES _I32 _BYTES _I32 _CB); -HL_PRIM void HL_NAME(w_udp_recv_start)(uv_udp_t *handle, vclosure *cb) { - UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read = cb; - UV_ERROR_CHECK(uv_udp_recv_start(handle, handle_stream_cb_alloc, handle_udp_cb_recv)); +HL_PRIM void HL_NAME(w_udp_recv_start)(uv_udp_t **handle, vclosure *cb) { + UV_HANDLE_DATA_SUB(Udp_val(handle), udp).cb_read = cb; + UV_ERROR_CHECK(uv_udp_recv_start(Udp_val(handle), handle_stream_cb_alloc, handle_udp_cb_recv)); } +DEFINE_PRIM(_VOID, w_udp_recv_start, _UDP _CB_UDP_RECV); -HL_PRIM void HL_NAME(w_udp_recv_stop)(uv_udp_t *handle) { - UV_HANDLE_DATA_SUB(handle, uv_w_udp_t)->cb_read = NULL; - UV_ERROR_CHECK(uv_udp_recv_stop(handle)); +HL_PRIM void HL_NAME(w_udp_recv_stop)(uv_udp_t **handle) { + UV_ERROR_CHECK(uv_udp_recv_stop(Udp_val(handle))); + UV_HANDLE_DATA_SUB(Udp_val(handle), udp).cb_read = NULL; } - -DEFINE_PRIM(_UDP, w_udp_init, _LOOP); -DEFINE_PRIM(_VOID, w_udp_bind_ipv4, _UDP _I32 _I32); -DEFINE_PRIM(_VOID, w_udp_bind_ipv6, _UDP _BYTES _I32); -DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BYTES _I32 _I32 _I32 _CB); -DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BYTES _I32 _BYTES _I32 _CB); -DEFINE_PRIM(_VOID, w_udp_recv_start, _UDP _CB_UDP_RECV); DEFINE_PRIM(_VOID, w_udp_recv_stop, _UDP); +HL_PRIM void HL_NAME(w_udp_set_membership)(uv_udp_t **handle, const char *address, const char *intfc, bool join) { + UV_ERROR_CHECK(uv_udp_set_membership(Udp_val(handle), address, intfc, join ? UV_JOIN_GROUP : UV_LEAVE_GROUP)); +} +DEFINE_PRIM(_VOID, w_udp_set_membership, _UDP _BYTES _BYTES _BOOL); + +// TODO: why? just cast? +HL_PRIM void HL_NAME(w_udp_close)(uv_udp_t **handle, vclosure *cb) { + HL_NAME(w_close)((uv_handle_t **)handle, cb); +} +DEFINE_PRIM(_VOID, w_udp_close, _UDP _CB); + +HL_PRIM vdynamic *HL_NAME(w_udp_getsockname)(uv_udp_t **handle) { + struct sockaddr_storage storage; + int dummy = sizeof(struct sockaddr_storage); + UV_ERROR_CHECK(uv_udp_getsockname(Udp_val(handle), (struct sockaddr *)&storage, &dummy)); + return w_getname(&storage); +} +DEFINE_PRIM(_DYN, w_udp_getsockname, _UDP); + +HL_PRIM void HL_NAME(w_udp_set_broadcast)(uv_udp_t **handle, bool flag) { + UV_ERROR_CHECK(uv_udp_set_broadcast(Udp_val(handle), flag ? 1 : 0)); +} +DEFINE_PRIM(_VOID, w_udp_set_broadcast, _UDP _BOOL); + +HL_PRIM void HL_NAME(w_udp_set_multicast_interface)(uv_udp_t **handle, const char *intfc) { + UV_ERROR_CHECK(uv_udp_set_multicast_interface(Udp_val(handle), intfc)); +} +DEFINE_PRIM(_VOID, w_udp_set_multicast_interface, _UDP _BYTES); + +HL_PRIM void HL_NAME(w_udp_set_multicast_loopback)(uv_udp_t **handle, bool flag) { + UV_ERROR_CHECK(uv_udp_set_multicast_loop(Udp_val(handle), flag ? 1 : 0)); +} +DEFINE_PRIM(_VOID, w_udp_set_multicast_loopback, _UDP _BOOL); + +HL_PRIM void HL_NAME(w_udp_set_multicast_ttl)(uv_udp_t **handle, int ttl) { + UV_ERROR_CHECK(uv_udp_set_multicast_ttl(Udp_val(handle), ttl)); +} +DEFINE_PRIM(_VOID, w_udp_set_multicast_ttl, _UDP _I32); + +HL_PRIM void HL_NAME(w_udp_set_ttl)(uv_udp_t **handle, int ttl) { + UV_ERROR_CHECK(uv_udp_set_ttl(Udp_val(handle), ttl)); +} +DEFINE_PRIM(_VOID, w_udp_set_ttl, _UDP _I32); + +HL_PRIM int HL_NAME(w_udp_get_recv_buffer_size)(uv_udp_t **handle) { + int size = 0; + return uv_recv_buffer_size(Handle_val(handle), &size); +} +DEFINE_PRIM(_I32, w_udp_get_recv_buffer_size, _UDP); + +HL_PRIM int HL_NAME(w_udp_get_send_buffer_size)(uv_udp_t **handle) { + int size = 0; + return uv_send_buffer_size(Handle_val(handle), &size); +} +DEFINE_PRIM(_I32, w_udp_get_send_buffer_size, _UDP); + +HL_PRIM int HL_NAME(w_udp_set_recv_buffer_size)(uv_udp_t **handle, int size) { + return uv_recv_buffer_size(Handle_val(handle), &size); +} +DEFINE_PRIM(_I32, w_udp_set_recv_buffer_size, _UDP _I32); + +HL_PRIM int HL_NAME(w_udp_set_send_buffer_size)(uv_udp_t **handle, int size) { + return uv_send_buffer_size(Handle_val(handle), &size); +} +DEFINE_PRIM(_I32, w_udp_set_send_buffer_size, _UDP _I32); + // ------------- DNS ------------------------------------------------ -static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { +static void handle_dns_gai_cb(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) hl_call2(void, cb, vdynamic *, construct_error(status), varray *, NULL); @@ -676,7 +959,7 @@ static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *r cur = res; for (int i = 0; i < count; i++) { if (cur->ai_family == AF_INET) - hl_aptr(arr, vdynamic *)[i] = construct_addrinfo_ipv4(((struct sockaddr_in *)cur->ai_addr)->sin_addr.s_addr); + hl_aptr(arr, vdynamic *)[i] = construct_addrinfo_ipv4(ntohl(((struct sockaddr_in *)cur->ai_addr)->sin_addr.s_addr)); else if (cur->ai_family == AF_INET6) hl_aptr(arr, vdynamic *)[i] = construct_addrinfo_ipv6(((struct sockaddr_in6 *)cur->ai_addr)->sin6_addr.s6_addr); cur = cur->ai_next; @@ -684,34 +967,46 @@ static void handle_dns_gai(uv_getaddrinfo_t *req, int status, struct addrinfo *r uv_freeaddrinfo(res); hl_call2(void, cb, vdynamic *, NULL, varray *, arr); } - hl_remove_root(UV_REQ_DATA(req)); + hl_remove_root(UV_REQ_DATA_A(req)); free(req); } -HL_PRIM void HL_NAME(w_getaddrinfo)(uv_loop_t *loop, vbyte *node, vbyte *service, int hint_flags, int hint_family, int hint_socktype, int hint_protocol, vclosure *cb) { +HL_PRIM void HL_NAME(w_dns_getaddrinfo)(uv_loop_t **loop, vbyte *node, bool flag_addrconfig, bool flag_v4mapped, int hint_family, vclosure *cb) { + UV_ALLOC_CHECK(req, uv_getaddrinfo_t); + UV_REQ_DATA(GetAddrInfo_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(GetAddrInfo_val(req))); + int hint_flags_u = 0; + if (flag_addrconfig) + hint_flags_u |= AI_ADDRCONFIG; + if (flag_v4mapped) + hint_flags_u |= AI_V4MAPPED; + int hint_family_u = AF_UNSPEC; + if (hint_family == 4) + hint_family_u = AF_INET; + else if (hint_family == 6) + hint_family_u = AF_INET6; struct addrinfo hints = { - .ai_flags = hint_flags, - .ai_family = hint_family, - .ai_socktype = hint_socktype, - .ai_protocol = hint_protocol, + .ai_flags = hint_flags_u, + .ai_family = hint_family_u, + .ai_socktype = 0, + .ai_protocol = 0, .ai_addrlen = 0, .ai_addr = NULL, .ai_canonname = NULL, .ai_next = NULL }; - UV_ALLOC_CHECK(req, uv_getaddrinfo_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_getaddrinfo(loop, req, handle_dns_gai, (char *)node, (char *)service, &hints), free(req)); - hl_add_root(UV_REQ_DATA(req)); + UV_ERROR_CHECK_C(uv_getaddrinfo(Loop_val(loop), GetAddrInfo_val(req), handle_dns_gai_cb, (char *)node, NULL, &hints), free(GetAddrInfo_val(req))); } +DEFINE_PRIM(_VOID, w_dns_getaddrinfo, _LOOP _BYTES _BOOL _BOOL _I32 _CB_GAI); +/* static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { vclosure *cb = UV_REQ_DATA(req); if (status < 0) hl_call3(void, cb, vdynamic *, construct_error(status), vbyte *, NULL, vbyte *, NULL); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hostname, vbyte *, (vbyte *)service); - hl_remove_root(UV_REQ_DATA(req)); + hl_remove_root(UV_REQ_DATA_A(req)); free(req); } @@ -720,7 +1015,7 @@ HL_PRIM void HL_NAME(w_getnameinfo_ipv4)(uv_loop_t *loop, int ip, int flags, vcl UV_ALLOC_CHECK(req, uv_getnameinfo_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); - hl_add_root(UV_REQ_DATA(req)); + hl_add_root(UV_REQ_DATA_A(req)); } HL_PRIM void HL_NAME(w_getnameinfo_ipv6)(uv_loop_t *loop, vbyte *ip, int flags, vclosure *cb) { @@ -728,9 +1023,278 @@ HL_PRIM void HL_NAME(w_getnameinfo_ipv6)(uv_loop_t *loop, vbyte *ip, int flags, UV_ALLOC_CHECK(req, uv_getnameinfo_t); UV_REQ_DATA(req) = (void *)cb; UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); - hl_add_root(UV_REQ_DATA(req)); + hl_add_root(UV_REQ_DATA_A(req)); } -DEFINE_PRIM(_VOID, w_getaddrinfo, _LOOP _BYTES _BYTES _I32 _I32 _I32 _I32 _CB_GAI); DEFINE_PRIM(_VOID, w_getnameinfo_ipv4, _LOOP _I32 _I32 _CB_GNI); DEFINE_PRIM(_VOID, w_getnameinfo_ipv6, _LOOP _BYTES _I32 _CB_GNI); +*/ + +// ------------- TIMERS --------------------------------------------- + +static void handle_timer_cb(uv_timer_t *handle) { + vclosure *cb = UV_HANDLE_DATA_SUB(handle, timer).cb_timer; + hl_call0(void, cb); +} + +HL_PRIM uv_timer_t **HL_NAME(w_timer_start)(uv_loop_t **loop, int timeout, vclosure *cb) { + UV_ALLOC_CHECK(handle, uv_timer_t); + UV_ERROR_CHECK_C(uv_timer_init(Loop_val(loop), Timer_val(handle)), free(Timer_val(handle))); + UV_HANDLE_DATA(Timer_val(handle)) = alloc_data_timer(cb); + if (UV_HANDLE_DATA(Timer_val(handle)) == NULL) + UV_ERROR(0); + UV_ERROR_CHECK_C( + uv_timer_start(Timer_val(handle), handle_timer_cb, timeout, timeout), + { unalloc_data(UV_HANDLE_DATA(Timer_val(handle))); free(Timer_val(handle)); } + ); + return handle; +} +DEFINE_PRIM(_TIMER, w_timer_start, _LOOP _I32 _CB_NOERR); + +HL_PRIM void HL_NAME(w_timer_stop)(uv_timer_t **handle, vclosure *cb) { + UV_ERROR_CHECK_C( + uv_timer_stop(Timer_val(handle)), + { unalloc_data(UV_HANDLE_DATA(Timer_val(handle))); free(Timer_val(handle)); } + ); + ((uv_w_handle_t *)UV_HANDLE_DATA(Timer_val(handle)))->cb_close = cb; + uv_close(Handle_val(handle), handle_close_cb); +} +DEFINE_PRIM(_VOID, w_timer_stop, _TIMER _CB); + +// ------------- PROCESS -------------------------------------------- + +#define _CB_PROCESS_EXIT _FUN(_VOID, _I32 _I32) + +static void handle_process_cb(uv_process_t *handle, int64_t exit_status, int term_signal) { + vclosure *cb = UV_HANDLE_DATA_SUB(handle, process).cb_exit; + // FIXME: int64 -> int conversion + hl_call2(void, cb, int, exit_status, int, term_signal); +} + +typedef struct { + hl_type *t; + int index; + bool readable; + bool writable; + uv_stream_t **pipe; +} hx_process_io_pipe; + +typedef struct { + hl_type *t; + int index; + uv_stream_t **pipe; +} hx_process_io_ipc; + +HL_PRIM uv_process_t **HL_NAME(w_spawn)(uv_loop_t **loop, vclosure *cb, const char *file, varray *args, varray *env, const char *cwd, int flags, varray *stdio, int uid, int gid) { + UV_ALLOC_CHECK(handle, uv_process_t); + UV_HANDLE_DATA(Process_val(handle)) = alloc_data_process(cb); + if (UV_HANDLE_DATA(Process_val(handle)) == NULL) + UV_ERROR(0); + char **args_u = malloc(sizeof(char *) * (args->size + 1)); + for (int i = 0; i < args->size; i++) + args_u[i] = strdup(hl_aptr(args, char *)[i]); + args_u[args->size] = NULL; + char **env_u = malloc(sizeof(char *) * (env->size + 1)); + for (int i = 0; i < env->size; i++) + env_u[i] = strdup(hl_aptr(env, char *)[i]); + env_u[env->size] = NULL; + uv_stdio_container_t *stdio_u = malloc(sizeof(uv_stdio_container_t) * stdio->size); + for (int i = 0; i < stdio->size; i++) { + venum *stdio_entry = hl_aptr(stdio, venum *)[i]; + switch (stdio_entry->index) { + case 0: // Ignore + stdio_u[i].flags = UV_IGNORE; + break; + case 1: // Inherit + stdio_u[i].flags = UV_INHERIT_FD; + stdio_u[i].data.fd = i; + break; + case 2: // Pipe + stdio_u[i].flags = UV_CREATE_PIPE; + if (((hx_process_io_pipe *)stdio_entry)->readable) + stdio_u[i].flags |= UV_READABLE_PIPE; + if (((hx_process_io_pipe *)stdio_entry)->writable) + stdio_u[i].flags |= UV_WRITABLE_PIPE; + stdio_u[i].data.stream = Stream_val(((hx_process_io_pipe *)stdio_entry)->pipe); + break; + default: // 3, Ipc + stdio_u[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; + stdio_u[i].data.stream = Stream_val(((hx_process_io_ipc *)stdio_entry)->pipe); + break; + } + } + uv_process_options_t options = { + .exit_cb = handle_process_cb, + .file = file, + .args = args_u, + .env = env_u, + .cwd = cwd, + .flags = flags, + .stdio_count = stdio->size, + .stdio = stdio_u, + .uid = uid, + .gid = gid + }; + UV_ERROR_CHECK_C( + uv_spawn(Loop_val(loop), Process_val(handle), &options), + { free(args_u); free(env_u); free(stdio_u); unalloc_data(UV_HANDLE_DATA(Process_val(handle))); free(Process_val(handle)); } + ); + free(args_u); + free(env_u); + free(stdio_u); + return handle; +} +DEFINE_PRIM(_PROCESS, w_spawn, _LOOP _CB_PROCESS_EXIT _BYTES _ARR _ARR _BYTES _I32 _ARR _I32 _I32); + +HL_PRIM void HL_NAME(w_process_kill)(uv_process_t **handle, int signum) { + UV_ERROR_CHECK(uv_process_kill(Process_val(handle), signum)); +} +DEFINE_PRIM(_VOID, w_process_kill, _PROCESS _I32); + +HL_PRIM int HL_NAME(w_process_get_pid)(uv_process_t **handle) { + return Process_val(handle)->pid; +} +DEFINE_PRIM(_I32, w_process_get_pid, _PROCESS); + +// ------------- PIPES ---------------------------------------------- + +HL_PRIM uv_pipe_t **HL_NAME(w_pipe_init)(uv_loop_t **loop, bool ipc) { + UV_ALLOC_CHECK(handle, uv_pipe_t); + UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(handle), ipc ? 1 : 0), free(Pipe_val(handle))); + UV_HANDLE_DATA(Pipe_val(handle)) = alloc_data_pipe(); + if (UV_HANDLE_DATA(Pipe_val(handle)) == NULL) + UV_ERROR(0); + return handle; +} +DEFINE_PRIM(_PIPE, w_pipe_init, _LOOP _BOOL); + +HL_PRIM void HL_NAME(w_pipe_open)(uv_pipe_t **pipe, int fd) { + UV_ERROR_CHECK(uv_pipe_open(Pipe_val(pipe), fd)); +} +DEFINE_PRIM(_VOID, w_pipe_open, _PIPE _I32); + +HL_PRIM uv_pipe_t **HL_NAME(w_pipe_accept)(uv_loop_t **loop, uv_pipe_t **server) { + UV_ALLOC_CHECK(client, uv_pipe_t); + UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(client), 0), free(Pipe_val(client))); + UV_HANDLE_DATA(Pipe_val(client)) = alloc_data_pipe(); + if (UV_HANDLE_DATA(Pipe_val(client)) == NULL) + UV_ERROR(0); + UV_ERROR_CHECK_C(uv_accept(Stream_val(server), Stream_val(client)), free(Pipe_val(client))); + return client; +} +DEFINE_PRIM(_PIPE, w_pipe_accept, _LOOP _PIPE); + +HL_PRIM void HL_NAME(w_pipe_bind_ipc)(uv_pipe_t **handle, const char *path) { + UV_ERROR_CHECK(uv_pipe_bind(Pipe_val(handle), path)); +} +DEFINE_PRIM(_VOID, w_pipe_bind_ipc, _PIPE _BYTES); + +HL_PRIM void HL_NAME(w_pipe_connect_ipc)(uv_pipe_t **handle, const char *path, vclosure *cb) { + UV_ALLOC_CHECK(req, uv_connect_t); + UV_REQ_DATA(Connect_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Connect_val(req))); + uv_pipe_connect(Connect_val(req), Pipe_val(handle), path, (void (*)(uv_connect_t *, int))handle_stream_cb); +} +DEFINE_PRIM(_VOID, w_pipe_connect_ipc, _PIPE _BYTES _CB); + +HL_PRIM int HL_NAME(w_pipe_pending_count)(uv_pipe_t **handle) { + return uv_pipe_pending_count(Pipe_val(handle)); +} +DEFINE_PRIM(_I32, w_pipe_pending_count, _PIPE); + +HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **handle) { + + switch (uv_pipe_pending_type(Pipe_val(handle))) { + case UV_NAMED_PIPE: { + UV_ALLOC_CHECK(client, uv_pipe_t); + UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(client), 0), free(Pipe_val(client))); + UV_HANDLE_DATA(Pipe_val(client)) = alloc_data_pipe(); + if (UV_HANDLE_DATA(Pipe_val(client)) == NULL) + UV_ERROR(0); + UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Pipe_val(client))); + return construct_pipe_accept_pipe(client); + }; break; + case UV_TCP: { + UV_ALLOC_CHECK(client, uv_tcp_t); + UV_ERROR_CHECK_C(uv_tcp_init(Loop_val(loop), Tcp_val(client)), free(Tcp_val(client))); + UV_HANDLE_DATA(Tcp_val(client)) = alloc_data_tcp(NULL,NULL); + if (UV_HANDLE_DATA(Tcp_val(client)) == NULL) + UV_ERROR(0); + UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Tcp_val(client))); + return construct_pipe_accept_socket(client); + }; break; + default: + UV_ERROR(0); + break; + } +} +DEFINE_PRIM(_DYN, w_pipe_accept_pending, _LOOP _PIPE); + +HL_PRIM vbyte *HL_NAME(w_pipe_getsockname)(uv_pipe_t **handle) { + vbyte *path = hl_gc_alloc_noptr(256); + size_t path_size = 255; + UV_ERROR_CHECK(uv_pipe_getsockname(Pipe_val(handle), (char *)path, &path_size)); + path[path_size] = 0; + return path; +} +DEFINE_PRIM(_BYTES, w_pipe_getsockname, _PIPE); + +HL_PRIM vbyte *HL_NAME(w_pipe_getpeername)(uv_pipe_t **handle) { + vbyte *path = hl_gc_alloc_noptr(256); + size_t path_size = 255; + UV_ERROR_CHECK(uv_pipe_getpeername(Pipe_val(handle), (char *)path, &path_size)); + path[path_size] = 0; + return path; +} +DEFINE_PRIM(_BYTES, w_pipe_getpeername, _PIPE); + +HL_PRIM void HL_NAME(w_pipe_write_handle)(uv_pipe_t **handle, vbyte *data, int length, uv_stream_t **send_handle, vclosure *cb) { + UV_ALLOC_CHECK(req, uv_write_t); + UV_REQ_DATA(Write_val(req)) = (void *)cb; + hl_add_root(UV_REQ_DATA_A(Write_val(req))); + uv_buf_t buf = uv_buf_init((char *)data, length); + UV_ERROR_CHECK_C(uv_write2(Write_val(req), Stream_val(handle), &buf, 1, Stream_val(send_handle), (void (*)(uv_write_t *, int))handle_stream_cb), free(Write_val(req))); +} +DEFINE_PRIM(_VOID, w_pipe_write_handle, _PIPE _BYTES _I32 _STREAM _CB); + +// ------------- CASTS ---------------------------------------------- + +/** + TODO: these might not be necessary if there is a way to cast HashLink + abstracts in Haxe code. +**/ + +HL_PRIM uv_handle_t **HL_NAME(w_stream_handle)(uv_stream_t **handle) { + return (uv_handle_t **)handle; +} +DEFINE_PRIM(_HANDLE, w_stream_handle, _STREAM); + +HL_PRIM uv_handle_t **HL_NAME(w_fs_event_handle)(uv_fs_event_t **handle) { + return (uv_handle_t **)handle; +} +DEFINE_PRIM(_HANDLE, w_fs_event_handle, _FS_EVENT); + +HL_PRIM uv_handle_t **HL_NAME(w_timer_handle)(uv_timer_t **handle) { + return (uv_handle_t **)handle; +} +DEFINE_PRIM(_HANDLE, w_timer_handle, _TIMER); + +HL_PRIM uv_handle_t **HL_NAME(w_process_handle)(uv_process_t **handle) { + return (uv_handle_t **)handle; +} +DEFINE_PRIM(_HANDLE, w_process_handle, _PROCESS); + +HL_PRIM uv_stream_t **HL_NAME(w_tcp_stream)(uv_tcp_t **handle) { + return (uv_stream_t **)handle; +} +DEFINE_PRIM(_STREAM, w_tcp_stream, _TCP); + +HL_PRIM uv_stream_t **HL_NAME(w_udp_stream)(uv_udp_t **handle) { + return (uv_stream_t **)handle; +} +DEFINE_PRIM(_STREAM, w_udp_stream, _UDP); + +HL_PRIM uv_stream_t **HL_NAME(w_pipe_stream)(uv_pipe_t **handle) { + return (uv_stream_t **)handle; +} +DEFINE_PRIM(_STREAM, w_pipe_stream, _PIPE); diff --git a/src/hl.h b/src/hl.h index 72533687c..e3066263a 100644 --- a/src/hl.h +++ b/src/hl.h @@ -663,6 +663,8 @@ HL_API vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3))cl->fun)(cl->value,v1,v2,v3) : ((ret(*)(t1,t2,t3))cl->fun)(v1,v2,v3)) #define hl_call4(ret,cl,t1,v1,t2,v2,t3,v3,t4,v4) \ (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3,t4))cl->fun)(cl->value,v1,v2,v3,v4) : ((ret(*)(t1,t2,t3,t4))cl->fun)(v1,v2,v3,v4)) +#define hl_call5(ret,cl,t1,v1,t2,v2,t3,v3,t4,v4,t5,v5) \ + (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3,t4,t5))cl->fun)(cl->value,v1,v2,v3,v4,v5) : ((ret(*)(t1,t2,t3,t4,t5))cl->fun)(v1,v2,v3,v4,v5)) // ----------------------- THREADS -------------------------------------------------- From faa11d2da2c1f1d8ba8ae512d566c58c55ec61d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Mon, 16 Sep 2019 20:27:26 +0100 Subject: [PATCH 14/22] macros for allocating/freeing requests --- libs/uv/uv.c | 98 +++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index dd3af9e9f..7f5bce457 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -102,6 +102,17 @@ #define UV_REQ_DATA(r) (((uv_req_t *)(r))->data) #define UV_REQ_DATA_A(r) ((void *)(&UV_REQ_DATA(r))) +// allocate a request, add its callback to GC roots +#define UV_ALLOC_REQ(name, type, cb) \ + UV_ALLOC_CHECK(name, type); \ + UV_REQ_DATA(UV_UNWRAP(name, type)) = (void *)cb; \ + hl_add_root(UV_REQ_DATA_A(UV_UNWRAP(name, type))); + +// free a request, remove its callback from GC roots +#define UV_FREE_REQ(name) \ + hl_remove_root(UV_REQ_DATA_A(name)); \ + free(name); + // malloc a single value of the given type #define UV_ALLOC(t) ((t *)malloc(sizeof(t))) @@ -260,8 +271,7 @@ static void handle_fs_cb(uv_fs_t *req) { else hl_call1(void, cb, vdynamic *, NULL); uv_fs_req_cleanup(req); - hl_remove_root(UV_REQ_DATA_A(req)); - free(req); + UV_FREE_REQ(req); } static void handle_fs_cb_sync(uv_fs_t **req_w) { uv_fs_t *req = Fs_val(req_w); @@ -282,8 +292,7 @@ static void handle_fs_cb_sync(uv_fs_t **req_w) { hl_call2(void, cb, vdynamic *, NULL, type2, value2); \ } \ uv_fs_req_cleanup(req); \ - hl_remove_root(UV_REQ_DATA_A(req)); \ - free(req); \ + UV_FREE_REQ(req); \ } \ static type2 name ## _sync(uv_fs_t **req_w) { \ uv_fs_t *req = Fs_val(req_w); \ @@ -346,17 +355,15 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { #define FS_WRAP(name, ret, sign, precall, call, ffiret, ffi, ffihandler, handler, doret) \ HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t **loop, sign, vclosure *cb) { \ - UV_ALLOC_CHECK(req, uv_fs_t); \ - UV_REQ_DATA(Fs_val(req)) = (void *)cb; \ - hl_add_root(UV_REQ_DATA_A(Fs_val(req))); \ + UV_ALLOC_REQ(req, uv_fs_t, cb); \ precall \ - UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, handler), free(Fs_val(req))); \ + UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, handler), UV_FREE_REQ(Fs_val(req))); \ } \ DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi ffihandler); \ HL_PRIM ret HL_NAME(w_ ## name ## _sync)(uv_loop_t **loop, sign) { \ UV_ALLOC_CHECK(req, uv_fs_t); \ precall \ - UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), free(Fs_val(req))); \ + UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), UV_FREE_REQ(Fs_val(req))); \ doret handler ## _sync(req); \ } \ DEFINE_PRIM(ffiret, w_ ## name ## _sync, _LOOP ffi); @@ -620,8 +627,7 @@ static void handle_stream_cb(uv_req_t *req, int status) { hl_call1(void, cb, vdynamic *, construct_error(status)); else hl_call1(void, cb, vdynamic *, NULL); - hl_remove_root(UV_REQ_DATA_A(req)); - free(req); + UV_FREE_REQ(req); } static void handle_stream_cb_connection(uv_stream_t *stream, int status) { @@ -646,10 +652,8 @@ static void handle_stream_cb_read(uv_stream_t *stream, long int nread, const uv_ } HL_PRIM void HL_NAME(w_shutdown)(uv_stream_t **stream, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_shutdown_t); - UV_REQ_DATA(Shutdown_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Shutdown_val(req))); - UV_ERROR_CHECK_C(uv_shutdown(Shutdown_val(req), Stream_val(stream), (void (*)(uv_shutdown_t *, int))handle_stream_cb), free(Shutdown_val(req))); + UV_ALLOC_REQ(req, uv_shutdown_t, cb); + UV_ERROR_CHECK_C(uv_shutdown(Shutdown_val(req), Stream_val(stream), (void (*)(uv_shutdown_t *, int))handle_stream_cb), UV_FREE_REQ(Shutdown_val(req))); } DEFINE_PRIM(_VOID, w_shutdown, _STREAM _CB); @@ -660,11 +664,9 @@ HL_PRIM void HL_NAME(w_listen)(uv_stream_t **stream, int backlog, vclosure *cb) DEFINE_PRIM(_VOID, w_listen, _STREAM _I32 _CB); HL_PRIM void HL_NAME(w_write)(uv_stream_t **stream, const vbyte *data, int length, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_write_t); - UV_REQ_DATA(Write_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Write_val(req))); + UV_ALLOC_REQ(req, uv_write_t, cb); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_write(Write_val(req), Stream_val(stream), &buf, 1, (void (*)(uv_write_t *, int))handle_stream_cb), free(Write_val(req))); + UV_ERROR_CHECK_C(uv_write(Write_val(req), Stream_val(stream), &buf, 1, (void (*)(uv_write_t *, int))handle_stream_cb), UV_FREE_REQ(Write_val(req))); } DEFINE_PRIM(_VOID, w_write, _STREAM _BYTES _I32 _CB); @@ -736,19 +738,15 @@ DEFINE_PRIM(_VOID, w_tcp_bind_ipv6, _TCP _BYTES _I32 _BOOL); HL_PRIM void HL_NAME(w_tcp_connect_ipv4)(uv_tcp_t **handle, int host, int port, vclosure *cb) { UV_SOCKADDR_IPV4(addr, host, port); - UV_ALLOC_CHECK(req, uv_connect_t); - UV_REQ_DATA(Connect_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Connect_val(req))); - UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(Connect_val(req))); + UV_ALLOC_REQ(req, uv_connect_t, cb); + UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), UV_FREE_REQ(Connect_val(req))); } DEFINE_PRIM(_VOID, w_tcp_connect_ipv4, _TCP _I32 _I32 _CB); HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t **handle, vbyte *host, int port, vclosure *cb) { UV_SOCKADDR_IPV6(addr, host, port); - UV_ALLOC_CHECK(req, uv_connect_t); - UV_REQ_DATA(Connect_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Connect_val(req))); - UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), free(Connect_val(req))); + UV_ALLOC_REQ(req, uv_connect_t, cb); + UV_ERROR_CHECK_C(uv_tcp_connect(Connect_val(req), Tcp_val(handle), (const struct sockaddr *)&addr, (void (*)(uv_connect_t *, int))handle_stream_cb), UV_FREE_REQ(Connect_val(req))); } DEFINE_PRIM(_VOID, w_tcp_connect_ipv6, _TCP _BYTES _I32 _CB); @@ -846,21 +844,17 @@ DEFINE_PRIM(_VOID, w_udp_bind_ipv6, _UDP _BYTES _I32 _BOOL); HL_PRIM void HL_NAME(w_udp_send_ipv4)(uv_udp_t **handle, vbyte *data, int length, int host, int port, vclosure *cb) { UV_SOCKADDR_IPV4(addr, host, port); - UV_ALLOC_CHECK(req, uv_udp_send_t); - UV_REQ_DATA(UdpSend_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(UdpSend_val(req))); + UV_ALLOC_REQ(req, uv_udp_send_t, cb); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(UdpSend_val(req))); + UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), UV_FREE_REQ(UdpSend_val(req))); } DEFINE_PRIM(_VOID, w_udp_send_ipv4, _UDP _BYTES _I32 _I32 _I32 _CB); HL_PRIM void HL_NAME(w_udp_send_ipv6)(uv_udp_t **handle, vbyte *data, int length, vbyte *host, int port, vclosure *cb) { UV_SOCKADDR_IPV6(addr, host, port); - UV_ALLOC_CHECK(req, uv_udp_send_t); - UV_REQ_DATA(UdpSend_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(UdpSend_val(req))); + UV_ALLOC_REQ(req, uv_udp_send_t, cb); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), free(UdpSend_val(req))); + UV_ERROR_CHECK_C(uv_udp_send(UdpSend_val(req), Udp_val(handle), &buf, 1, (const struct sockaddr *)&addr, (void (*)(uv_udp_send_t *, int))handle_stream_cb), UV_FREE_REQ(UdpSend_val(req))); } DEFINE_PRIM(_VOID, w_udp_send_ipv6, _UDP _BYTES _I32 _BYTES _I32 _CB); @@ -967,14 +961,11 @@ static void handle_dns_gai_cb(uv_getaddrinfo_t *req, int status, struct addrinfo uv_freeaddrinfo(res); hl_call2(void, cb, vdynamic *, NULL, varray *, arr); } - hl_remove_root(UV_REQ_DATA_A(req)); - free(req); + UV_FREE_REQ(req); } HL_PRIM void HL_NAME(w_dns_getaddrinfo)(uv_loop_t **loop, vbyte *node, bool flag_addrconfig, bool flag_v4mapped, int hint_family, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_getaddrinfo_t); - UV_REQ_DATA(GetAddrInfo_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(GetAddrInfo_val(req))); + UV_ALLOC_REQ(req, uv_getaddrinfo_t, cb); int hint_flags_u = 0; if (flag_addrconfig) hint_flags_u |= AI_ADDRCONFIG; @@ -995,7 +986,7 @@ HL_PRIM void HL_NAME(w_dns_getaddrinfo)(uv_loop_t **loop, vbyte *node, bool flag .ai_canonname = NULL, .ai_next = NULL }; - UV_ERROR_CHECK_C(uv_getaddrinfo(Loop_val(loop), GetAddrInfo_val(req), handle_dns_gai_cb, (char *)node, NULL, &hints), free(GetAddrInfo_val(req))); + UV_ERROR_CHECK_C(uv_getaddrinfo(Loop_val(loop), GetAddrInfo_val(req), handle_dns_gai_cb, (char *)node, NULL, &hints), UV_FREE_REQ(GetAddrInfo_val(req))); } DEFINE_PRIM(_VOID, w_dns_getaddrinfo, _LOOP _BYTES _BOOL _BOOL _I32 _CB_GAI); @@ -1006,24 +997,19 @@ static void handle_dns_gni(uv_getnameinfo_t *req, int status, const char *hostna hl_call3(void, cb, vdynamic *, construct_error(status), vbyte *, NULL, vbyte *, NULL); else hl_call3(void, cb, vdynamic *, NULL, vbyte *, (vbyte *)hostname, vbyte *, (vbyte *)service); - hl_remove_root(UV_REQ_DATA_A(req)); - free(req); + UV_FREE_REQ(req); } HL_PRIM void HL_NAME(w_getnameinfo_ipv4)(uv_loop_t *loop, int ip, int flags, vclosure *cb) { UV_SOCKADDR_IPV4(addr, ip, 0); - UV_ALLOC_CHECK(req, uv_getnameinfo_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); - hl_add_root(UV_REQ_DATA_A(req)); + UV_ALLOC_REQ(req, uv_getnameinfo_t, cb); + UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), UV_FREE_REQ(GetNameInfo_val(req))); } HL_PRIM void HL_NAME(w_getnameinfo_ipv6)(uv_loop_t *loop, vbyte *ip, int flags, vclosure *cb) { UV_SOCKADDR_IPV6(addr, ip, 0); - UV_ALLOC_CHECK(req, uv_getnameinfo_t); - UV_REQ_DATA(req) = (void *)cb; - UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), free(req)); - hl_add_root(UV_REQ_DATA_A(req)); + UV_ALLOC_REQ(req, uv_getnameinfo_t, cb); + UV_ERROR_CHECK_C(uv_getnameinfo(loop, req, handle_dns_gni, (const struct sockaddr *)&addr, flags), UV_FREE_REQ(GetNameInfo_val(req))); } DEFINE_PRIM(_VOID, w_getnameinfo_ipv4, _LOOP _I32 _I32 _CB_GNI); @@ -1190,9 +1176,7 @@ HL_PRIM void HL_NAME(w_pipe_bind_ipc)(uv_pipe_t **handle, const char *path) { DEFINE_PRIM(_VOID, w_pipe_bind_ipc, _PIPE _BYTES); HL_PRIM void HL_NAME(w_pipe_connect_ipc)(uv_pipe_t **handle, const char *path, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_connect_t); - UV_REQ_DATA(Connect_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Connect_val(req))); + UV_ALLOC_REQ(req, uv_connect_t, cb); uv_pipe_connect(Connect_val(req), Pipe_val(handle), path, (void (*)(uv_connect_t *, int))handle_stream_cb); } DEFINE_PRIM(_VOID, w_pipe_connect_ipc, _PIPE _BYTES _CB); @@ -1249,11 +1233,9 @@ HL_PRIM vbyte *HL_NAME(w_pipe_getpeername)(uv_pipe_t **handle) { DEFINE_PRIM(_BYTES, w_pipe_getpeername, _PIPE); HL_PRIM void HL_NAME(w_pipe_write_handle)(uv_pipe_t **handle, vbyte *data, int length, uv_stream_t **send_handle, vclosure *cb) { - UV_ALLOC_CHECK(req, uv_write_t); - UV_REQ_DATA(Write_val(req)) = (void *)cb; - hl_add_root(UV_REQ_DATA_A(Write_val(req))); + UV_ALLOC_REQ(req, uv_write_t, cb); uv_buf_t buf = uv_buf_init((char *)data, length); - UV_ERROR_CHECK_C(uv_write2(Write_val(req), Stream_val(handle), &buf, 1, Stream_val(send_handle), (void (*)(uv_write_t *, int))handle_stream_cb), free(Write_val(req))); + UV_ERROR_CHECK_C(uv_write2(Write_val(req), Stream_val(handle), &buf, 1, Stream_val(send_handle), (void (*)(uv_write_t *, int))handle_stream_cb), UV_FREE_REQ(Write_val(req))); } DEFINE_PRIM(_VOID, w_pipe_write_handle, _PIPE _BYTES _I32 _STREAM _CB); From 7933938475675e1aabdd45ff6f5241705a05259d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 20:02:01 +0100 Subject: [PATCH 15/22] minor changes --- libs/uv/uv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 7f5bce457..5fc0ef2a3 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -363,7 +363,7 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { HL_PRIM ret HL_NAME(w_ ## name ## _sync)(uv_loop_t **loop, sign) { \ UV_ALLOC_CHECK(req, uv_fs_t); \ precall \ - UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), UV_FREE_REQ(Fs_val(req))); \ + UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), free(Fs_val(req))); \ doret handler ## _sync(req); \ } \ DEFINE_PRIM(ffiret, w_ ## name ## _sync, _LOOP ffi); @@ -751,12 +751,11 @@ HL_PRIM void HL_NAME(w_tcp_connect_ipv6)(uv_tcp_t **handle, vbyte *host, int por DEFINE_PRIM(_VOID, w_tcp_connect_ipv6, _TCP _BYTES _I32 _CB); static vdynamic *w_getname(struct sockaddr_storage *addr) { - vdynamic *w_addr; if (addr->ss_family == AF_INET) { - w_addr = construct_addrinfo_ipv4(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); + vdynamic *w_addr = construct_addrinfo_ipv4(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); return construct_addrport(w_addr, ntohs(((struct sockaddr_in *)addr)->sin_port)); } else if (addr->ss_family == AF_INET6) { - w_addr = construct_addrinfo_ipv6(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr); + vdynamic *w_addr = construct_addrinfo_ipv6(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr); return construct_addrport(w_addr, ntohs(((struct sockaddr_in6 *)addr)->sin6_port)); } UV_ERROR(0); @@ -943,6 +942,7 @@ static void handle_dns_gai_cb(uv_getaddrinfo_t *req, int status, struct addrinfo if (status < 0) hl_call2(void, cb, vdynamic *, construct_error(status), varray *, NULL); else { + // TODO: use linked list int count = 0; struct addrinfo *cur; for (cur = res; cur != NULL; cur = cur->ai_next) { @@ -1187,7 +1187,6 @@ HL_PRIM int HL_NAME(w_pipe_pending_count)(uv_pipe_t **handle) { DEFINE_PRIM(_I32, w_pipe_pending_count, _PIPE); HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **handle) { - switch (uv_pipe_pending_type(Pipe_val(handle))) { case UV_NAMED_PIPE: { UV_ALLOC_CHECK(client, uv_pipe_t); @@ -1197,7 +1196,7 @@ HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **h UV_ERROR(0); UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Pipe_val(client))); return construct_pipe_accept_pipe(client); - }; break; + } break; case UV_TCP: { UV_ALLOC_CHECK(client, uv_tcp_t); UV_ERROR_CHECK_C(uv_tcp_init(Loop_val(loop), Tcp_val(client)), free(Tcp_val(client))); @@ -1206,7 +1205,7 @@ HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **h UV_ERROR(0); UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Tcp_val(client))); return construct_pipe_accept_socket(client); - }; break; + } break; default: UV_ERROR(0); break; From 232a872584842e0c11ee0d8cc9ebb9d3d7b6fb3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 20:17:34 +0100 Subject: [PATCH 16/22] remove old UV sample --- other/uvsample/UVSample.hx | 128 --------------------------------- other/uvsample/uvsample.hxml | 3 - other/uvsample/uvsample.hxproj | 53 -------------- 3 files changed, 184 deletions(-) delete mode 100644 other/uvsample/UVSample.hx delete mode 100644 other/uvsample/uvsample.hxml delete mode 100644 other/uvsample/uvsample.hxproj diff --git a/other/uvsample/UVSample.hx b/other/uvsample/UVSample.hx deleted file mode 100644 index 9587177dc..000000000 --- a/other/uvsample/UVSample.hx +++ /dev/null @@ -1,128 +0,0 @@ -import hl.uv.*; - -class UVSample { - - static var T0 = haxe.Timer.stamp(); - - static function log( msg : String ) { - Sys.println("["+Std.int((haxe.Timer.stamp() - T0) * 100)+"] "+msg); - } - - static function main() { - var loop = Loop.getDefault(); - var tcp = new Tcp(loop); - - /* - tcp.connect(new sys.net.Host("google.com"), 80, function(b) { - - log("Connected=" + b); - var bytes = haxe.io.Bytes.ofString("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n"); - tcp.write(bytes, function(b) trace("Sent=" + b)); - var buf = new haxe.io.BytesBuffer(); - tcp.readStart(function(bytes:hl.Bytes, len) { - if( len < 0 ) { - var str = buf.getBytes().toString(); - if( str.length > 1000 ) - str = str.substr(0, 500) + "\n...\n" + str.substr(str.length - 500); - log("#" + str + "#"); - tcp.readStop(); - return; - } - log("Read="+len); - var bytes = bytes.toBytes(len); - buf.addBytes(bytes, 0, len); - }); - - }); - */ - - var host = new sys.net.Host("localhost"); - var port = 6001; - - var totR = 0, totW = 0, totRB = 0; - - log("Starting server"); - tcp.bind(host, port); - tcp.listen(5, function() { - - log("Client connected"); - var s = tcp.accept(); - s.readStart(function(bytes) { - if( bytes == null ) { - s.close(); - return; - } - totR += bytes.length; - // write back - s.write(bytes, function(b) if( !b ) throw "Write failure"); - }); - - }); - - - function startClient() { - - var numbers = []; - var client = new Tcp(loop); - //log("Connecting..."); - client.connect(host, port, function(b) { - //log("Connected to server"); - - - function send() { - var b = haxe.io.Bytes.alloc(1); - var k = Std.random(255); - numbers.push(k); - totW++; - b.set(0, k); - client.write(b, function(b) if( !b ) log("Write failure")); - } - - function sendBatch() { - for( i in 0...1+Std.random(10) ) - send(); - } - sendBatch(); - - client.readStart(function(b) { - totRB += b.length; - for( i in 0...b.length ) { - var k = b.get(i); - if( !numbers.remove(k) ) - throw "!"; - } - if( numbers.length == 0 ) { - if( Std.random(10000) == 0 ) { - startClient(); - client.close(); - } else - sendBatch(); - } - }); - - }); - - } - - for( i in 0...4 ) - startClient(); - - - log("Enter Loop"); - - var K = 0; - var maxRead = 1000000; - while( loop.run(NoWait) != 0 ) { - if( K++ % 10000 == 0 ) log("Read=" + totR); - - if( totR > maxRead ) { - log("Total Read > " + maxRead); - break; - } - } - - log("Done"); - Sys.exit(0); - } - -} \ No newline at end of file diff --git a/other/uvsample/uvsample.hxml b/other/uvsample/uvsample.hxml deleted file mode 100644 index 4d621c415..000000000 --- a/other/uvsample/uvsample.hxml +++ /dev/null @@ -1,3 +0,0 @@ --hl uvsample.hl --main UVSample --dce no \ No newline at end of file diff --git a/other/uvsample/uvsample.hxproj b/other/uvsample/uvsample.hxproj deleted file mode 100644 index 2fa011830..000000000 --- a/other/uvsample/uvsample.hxproj +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - haxe -hl uvsample.hl -main UVSample -dce no - - - - - - - - \ No newline at end of file From 92c3d919a5fe23f44c3143aa8af2c213049e3987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 20:19:21 +0100 Subject: [PATCH 17/22] install libuv 1.31 on linux CI --- other/azure-pipelines/build-linux.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/other/azure-pipelines/build-linux.yml b/other/azure-pipelines/build-linux.yml index 87aad8a8a..6c7b4bd1d 100644 --- a/other/azure-pipelines/build-linux.yml +++ b/other/azure-pipelines/build-linux.yml @@ -42,7 +42,6 @@ jobs: libalut-dev \ libmbedtls-dev \ libturbojpeg0-dev \ - libuv1-dev \ libopenal-dev \ neko \ curl \ @@ -65,12 +64,22 @@ jobs: libalut-dev:${{ parameters.arch }} \ libmbedtls-dev:${{ parameters.arch }} \ libturbojpeg0-dev:i386 \ - libuv1-dev:${{ parameters.arch }} \ libopenal-dev:${{ parameters.arch }} \ neko \ curl \ ca-certificates displayName: Install dependencies + - script: | + set -ex + curl -sSL -o "$(Agent.TempDirectory)/libuv-1.31.0.tar.gz" --retry 3 https://github.com/libuv/libuv/archive/v1.31.0.tar.gz + tar -xf $(Agent.TempDirectory)/libuv-1.31.0.tar.gz -C $(Agent.TempDirectory) + pushd $(Agent.TempDirectory)/libuv-1.31.0 + sh autogen.sh + ./configure + make + sudo make install + popd + displayName: Install libuv 1.31.0 - template: install-haxe-snapshot.yml parameters: platform: linux64 From aa40d9a1b1e1aac8c457a62fe1f98484285db95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 21:44:07 +0100 Subject: [PATCH 18/22] cleanup and upstream (eval) changes - functions to report the values of UV_ constants - unify alloc_data_* - copyfile, lchown --- libs/uv/uv.c | 207 +++++++++++++++++++-------------------------------- 1 file changed, 75 insertions(+), 132 deletions(-) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index 5fc0ef2a3..d594e8ec5 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -8,8 +8,8 @@ # include #endif -#if (UV_VERSION_MAJOR <= 0) -# error "libuv1-dev required, uv version 0.x found" +#if (UV_VERSION_HEX < (1 << 16 | 31 << 8)) +# error "Compiling HashLink requires libuv version 1.31.0+" #endif // ------------- TYPES ---------------------------------------------- @@ -184,6 +184,26 @@ DEFINE_PRIM( _FUN(_DYN, _PIPE) ); +HL_PRIM varray *HL_NAME(glue_file_open_flags)(void) { + int values[] = {UV_FS_O_APPEND, UV_FS_O_CREAT, UV_FS_O_DIRECT, UV_FS_O_DIRECTORY, UV_FS_O_DSYNC, UV_FS_O_EXCL, UV_FS_O_NOATIME, UV_FS_O_NOCTTY, UV_FS_O_NOFOLLOW, UV_FS_O_NONBLOCK, UV_FS_O_RDONLY, UV_FS_O_RDWR, UV_FS_O_SYNC, UV_FS_O_TRUNC, UV_FS_O_WRONLY}; + varray *ret = hl_alloc_array(&hlt_i32, sizeof(values) / sizeof(values[0])); + for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) { + hl_aptr(ret, int)[i] = values[i]; + } + return ret; +} +DEFINE_PRIM(_ARR, glue_file_open_flags, _NO_ARG); + +HL_PRIM varray *HL_NAME(glue_error_codes)(void) { + int values[] = {UV_E2BIG, UV_EACCES, UV_EADDRINUSE, UV_EADDRNOTAVAIL, UV_EAFNOSUPPORT, UV_EAGAIN, UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS, UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL, UV_EAI_FAMILY, UV_EAI_MEMORY, UV_EAI_NODATA, UV_EAI_NONAME, UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE, UV_EAI_SOCKTYPE, UV_EALREADY, UV_EBADF, UV_EBUSY, UV_ECANCELED, UV_ECHARSET, UV_ECONNABORTED, UV_ECONNREFUSED, UV_ECONNRESET, UV_EDESTADDRREQ, UV_EEXIST, UV_EFAULT, UV_EFBIG, UV_EHOSTUNREACH, UV_EINTR, UV_EINVAL, UV_EIO, UV_EISCONN, UV_EISDIR, UV_ELOOP, UV_EMFILE, UV_EMSGSIZE, UV_ENAMETOOLONG, UV_ENETDOWN, UV_ENETUNREACH, UV_ENFILE, UV_ENOBUFS, UV_ENODEV, UV_ENOENT, UV_ENOMEM, UV_ENONET, UV_ENOPROTOOPT, UV_ENOSPC, UV_ENOSYS, UV_ENOTCONN, UV_ENOTDIR, UV_ENOTEMPTY, UV_ENOTSOCK, UV_ENOTSUP, UV_EPERM, UV_EPIPE, UV_EPROTO, UV_EPROTONOSUPPORT, UV_EPROTOTYPE, UV_ERANGE, UV_EROFS, UV_ESHUTDOWN, UV_ESPIPE, UV_ESRCH, UV_ETIMEDOUT, UV_ETXTBSY, UV_EXDEV, UV_UNKNOWN, UV_EOF, UV_ENXIO, UV_EMLINK, UV_EHOSTDOWN, 0}; + varray *ret = hl_alloc_array(&hlt_i32, sizeof(values) / sizeof(values[0])); + for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) { + hl_aptr(ret, int)[i] = values[i]; + } + return ret; +} +DEFINE_PRIM(_ARR, glue_error_codes, _NO_ARG); + // ------------- ERROR HANDLING ------------------------------------- /** @@ -354,19 +374,19 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { **/ #define FS_WRAP(name, ret, sign, precall, call, ffiret, ffi, ffihandler, handler, doret) \ - HL_PRIM void HL_NAME(w_ ## name)(uv_loop_t **loop, sign, vclosure *cb) { \ + HL_PRIM void HL_NAME(w_fs_ ## name)(uv_loop_t **loop, sign, vclosure *cb) { \ UV_ALLOC_REQ(req, uv_fs_t, cb); \ precall \ - UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, handler), UV_FREE_REQ(Fs_val(req))); \ + UV_ERROR_CHECK_C(uv_fs_ ## name(Loop_val(loop), Fs_val(req), call, handler), UV_FREE_REQ(Fs_val(req))); \ } \ - DEFINE_PRIM(_VOID, w_ ## name, _LOOP ffi ffihandler); \ - HL_PRIM ret HL_NAME(w_ ## name ## _sync)(uv_loop_t **loop, sign) { \ + DEFINE_PRIM(_VOID, w_fs_ ## name, _LOOP ffi ffihandler); \ + HL_PRIM ret HL_NAME(w_fs_ ## name ## _sync)(uv_loop_t **loop, sign) { \ UV_ALLOC_CHECK(req, uv_fs_t); \ precall \ - UV_ERROR_CHECK_C(uv_ ## name(Loop_val(loop), Fs_val(req), call, NULL), free(Fs_val(req))); \ + UV_ERROR_CHECK_C(uv_fs_ ## name(Loop_val(loop), Fs_val(req), call, NULL), free(Fs_val(req))); \ doret handler ## _sync(req); \ } \ - DEFINE_PRIM(ffiret, w_ ## name ## _sync, _LOOP ffi); + DEFINE_PRIM(ffiret, w_fs_ ## name ## _sync, _LOOP ffi); #define COMMA , #define FS_WRAP1(name, ret, arg1, ffiret, ffi, ffihandler, handler, doret) \ @@ -378,32 +398,34 @@ UV_FS_HANDLER(handle_fs_cb_scandir, varray *, { #define FS_WRAP4(name, ret, arg1, arg2, arg3, arg4, ffiret, ffi, ffihandler, handler, doret) \ FS_WRAP(name, ret, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, , _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffiret, ffi, ffihandler, handler, doret); -FS_WRAP1(fs_close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP3(fs_open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); -FS_WRAP1(fs_unlink, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); -FS_WRAP2(fs_mkdir, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP1(fs_mkdtemp, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_path, return); -FS_WRAP1(fs_rmdir, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); -FS_WRAP2(fs_scandir, varray *, const char *, int, _ARR, _BYTES _I32, _CB_SCANDIR, handle_fs_cb_scandir, return); -FS_WRAP1(fs_stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP1(fs_fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP1(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); -FS_WRAP2(fs_rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); -FS_WRAP1(fs_fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP1(fs_fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); -FS_WRAP2(fs_ftruncate, void, uv_file, int64_t, _VOID, _FILE _I32, _CB, 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, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP2(fs_chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP2(fs_fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); -FS_WRAP3(fs_utime, void, const char*, double, double, _VOID, _BYTES _F64 _F64, _CB, handle_fs_cb, ); -FS_WRAP3(fs_futime, void, uv_file, double, double, _VOID, _FILE _F64 _F64, _CB, handle_fs_cb, ); -FS_WRAP2(fs_link, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); -FS_WRAP3(fs_symlink, void, const char*, const char*, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); -FS_WRAP1(fs_readlink, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); -FS_WRAP1(fs_realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); -FS_WRAP3(fs_chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); -FS_WRAP3(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP1(close, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP3(open, uv_file, const char*, int, int, _FILE, _BYTES _I32 _I32, _CB_FILE, handle_fs_cb_file, return); +FS_WRAP1(unlink, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2(mkdir, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1(mkdtemp, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_path, return); +FS_WRAP1(rmdir, void, const char*, _VOID, _BYTES, _CB, handle_fs_cb, ); +FS_WRAP2(scandir, varray *, const char *, int, _ARR, _BYTES _I32, _CB_SCANDIR, handle_fs_cb_scandir, return); +FS_WRAP1(stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1(fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP1(lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return); +FS_WRAP2(rename, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP1(fsync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP1(fdatasync, void, uv_file, _VOID, _FILE, _CB, handle_fs_cb, ); +FS_WRAP2(ftruncate, void, uv_file, int64_t, _VOID, _FILE _I32, _CB, handle_fs_cb, ); +FS_WRAP3(copyfile, void, const char *, const char *, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP4(sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP2(access, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2(chmod, void, const char*, int, _VOID, _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP2(fchmod, void, uv_file, int, _VOID, _FILE _I32, _CB, handle_fs_cb, ); +FS_WRAP3(utime, void, const char*, double, double, _VOID, _BYTES _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP3(futime, void, uv_file, double, double, _VOID, _FILE _F64 _F64, _CB, handle_fs_cb, ); +FS_WRAP2(link, void, const char*, const char*, _VOID, _BYTES _BYTES, _CB, handle_fs_cb, ); +FS_WRAP3(symlink, void, const char*, const char*, int, _VOID, _BYTES _BYTES _I32, _CB, handle_fs_cb, ); +FS_WRAP1(readlink, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP1(realpath, vbyte *, const char*, _BYTES, _BYTES, _CB_STR, handle_fs_cb_bytes, return); +FS_WRAP3(chown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP3(fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _CB, handle_fs_cb, ); +FS_WRAP3(lchown, void, const char*, uv_uid_t, uv_gid_t, _VOID, _BYTES _I32 _I32, _CB, handle_fs_cb, ); /** `fs_read` and `fs_write` require a tiny bit of setup just before the libuv @@ -414,7 +436,7 @@ FS_WRAP3(fs_fchown, void, uv_file, uv_uid_t, uv_gid_t, _VOID, _FILE _I32 _I32, _ mirrored in the Haxe API, so only a single-buffer call is used. **/ -FS_WRAP(fs_read, +FS_WRAP(read, int, uv_file file COMMA vbyte *data COMMA int offset COMMA int length COMMA int position, uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length);, @@ -425,7 +447,7 @@ FS_WRAP(fs_read, handle_fs_cb_int, return); -FS_WRAP(fs_write, +FS_WRAP(write, int, uv_file file COMMA vbyte *data COMMA int offset COMMA int length COMMA int position, uv_buf_t buf = uv_buf_init((char *)(&data[offset]), length);, @@ -489,68 +511,15 @@ typedef struct { } u; } uv_w_handle_t; -static uv_w_handle_t *alloc_data_fs_event(vclosure *cb_fs_event) { - uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); - if (data != NULL) { - data->cb_close = NULL; - hl_add_root(&(data->cb_close)); - data->u.fs_event.cb_fs_event = cb_fs_event; - hl_add_root(&(data->u.fs_event.cb_fs_event)); - } - return data; -} - -static uv_w_handle_t *alloc_data_tcp(vclosure *cb_read, vclosure *cb_connection) { - uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); - if (data != NULL) { - data->cb_close = NULL; - hl_add_root(&(data->cb_close)); - data->u.tcp.cb_read = cb_read; - hl_add_root(&(data->u.tcp.cb_read)); - data->u.tcp.cb_connection = cb_connection; - hl_add_root(&(data->u.tcp.cb_connection)); - } - return data; -} - -static uv_w_handle_t *alloc_data_udp(vclosure *cb_read) { - uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); - if (data != NULL) { - data->cb_close = NULL; - hl_add_root(&(data->cb_close)); - data->u.udp.cb_read = cb_read; - hl_add_root(&(data->u.udp.cb_read)); - } - return data; -} - -static uv_w_handle_t *alloc_data_timer(vclosure *cb_timer) { - uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); - if (data != NULL) { - data->cb_close = NULL; - hl_add_root(&(data->cb_close)); - data->u.timer.cb_timer = cb_timer; - hl_add_root(&(data->u.timer.cb_timer)); - } - return data; -} - -static uv_w_handle_t *alloc_data_process(vclosure *cb_exit) { - uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); - if (data != NULL) { - data->cb_close = NULL; - hl_add_root(&(data->cb_close)); - data->u.process.cb_exit = cb_exit; - hl_add_root(&(data->u.process.cb_exit)); - } - return data; -} - -static uv_w_handle_t *alloc_data_pipe(void) { +static uv_w_handle_t *alloc_data(void) { uv_w_handle_t *data = calloc(1, sizeof(uv_w_handle_t)); if (data != NULL) { data->cb_close = NULL; hl_add_root(&(data->cb_close)); + data->u.all.cb1 = NULL; + hl_add_root(&(data->u.all.cb1)); + data->u.all.cb2 = NULL; + hl_add_root(&(data->u.all.cb2)); } return data; } @@ -598,9 +567,9 @@ static void handle_fs_event_cb(uv_fs_event_t *handle, const char *filename, int HL_PRIM uv_fs_event_t **HL_NAME(w_fs_event_start)(uv_loop_t **loop, const char *path, bool recursive, vclosure *cb) { UV_ALLOC_CHECK(handle, uv_fs_event_t); UV_ERROR_CHECK_C(uv_fs_event_init(Loop_val(loop), FsEvent_val(handle)), free(FsEvent_val(handle))); - UV_HANDLE_DATA(FsEvent_val(handle)) = alloc_data_fs_event(cb); - if (UV_HANDLE_DATA(FsEvent_val(handle)) == NULL) + if ((UV_HANDLE_DATA(FsEvent_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); + UV_HANDLE_DATA_SUB(FsEvent_val(handle), fs_event).cb_fs_event = cb; UV_ERROR_CHECK_C( uv_fs_event_start(FsEvent_val(handle), handle_fs_event_cb, path, recursive ? UV_FS_EVENT_RECURSIVE : 0), { unalloc_data(UV_HANDLE_DATA(FsEvent_val(handle))); free(FsEvent_val(handle)); } @@ -700,8 +669,7 @@ DEFINE_PRIM(_VOID, w_read_stop, _STREAM); HL_PRIM uv_tcp_t **HL_NAME(w_tcp_init)(uv_loop_t **loop) { UV_ALLOC_CHECK(handle, uv_tcp_t); UV_ERROR_CHECK_C(uv_tcp_init(Loop_val(loop), Tcp_val(handle)), free(Tcp_val(handle))); - UV_HANDLE_DATA(Tcp_val(handle)) = alloc_data_tcp(NULL, NULL); - if (UV_HANDLE_DATA(Tcp_val(handle)) == NULL) + if ((UV_HANDLE_DATA(Tcp_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); return handle; } @@ -777,26 +745,6 @@ HL_PRIM vdynamic *HL_NAME(w_tcp_getpeername)(uv_tcp_t **handle) { } DEFINE_PRIM(_DYN, w_tcp_getpeername, _TCP); -/* -HL_PRIM void HL_NAME(w_tcp_read_stop)(uv_tcp_t *stream) { - uv_read_stop((uv_stream_t *)stream); -} - -DEFINE_PRIM(_VOID, w_tcp_read_stop, _TCP); - -#define UV_TCP_CAST(name, basename, basetype, sign, call, ffi) \ - HL_PRIM void HL_NAME(name)(uv_tcp_t *stream, sign) { \ - basename((basetype *)stream, call); \ - } \ - DEFINE_PRIM(_VOID, name, _TCP ffi); - -UV_TCP_CAST(w_tcp_listen, w_listen, uv_stream_t, int backlog COMMA vclosure *cb, backlog COMMA cb, _I32 _CB); -//UV_TCP_CAST(w_tcp_write, w_write, uv_stream_t, uv_buf_t *buf COMMA vclosure *cb, buf COMMA cb, _BUF _CB); -UV_TCP_CAST(w_tcp_shutdown, HL_NAME(w_shutdown), uv_stream_t, vclosure *cb, cb, _CB); -UV_TCP_CAST(w_tcp_close, w_close, uv_handle_t, vclosure *cb, cb, _CB); -UV_TCP_CAST(w_tcp_read_start, w_read_start, uv_stream_t, vclosure *cb, cb, _CB_BYTES); -*/ - // ------------- UDP ------------------------------------------------ static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned int flags) { @@ -822,8 +770,7 @@ static void handle_udp_cb_recv(uv_udp_t *handle, long int nread, const uv_buf_t HL_PRIM uv_udp_t **HL_NAME(w_udp_init)(uv_loop_t **loop) { UV_ALLOC_CHECK(handle, uv_udp_t); UV_ERROR_CHECK_C(uv_udp_init(Loop_val(loop), Udp_val(handle)), free(Udp_val(handle))); - UV_HANDLE_DATA(Udp_val(handle)) = alloc_data_udp(NULL); - if (UV_HANDLE_DATA(Udp_val(handle)) == NULL) + if ((UV_HANDLE_DATA(Udp_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); return handle; } @@ -1026,9 +973,9 @@ static void handle_timer_cb(uv_timer_t *handle) { HL_PRIM uv_timer_t **HL_NAME(w_timer_start)(uv_loop_t **loop, int timeout, vclosure *cb) { UV_ALLOC_CHECK(handle, uv_timer_t); UV_ERROR_CHECK_C(uv_timer_init(Loop_val(loop), Timer_val(handle)), free(Timer_val(handle))); - UV_HANDLE_DATA(Timer_val(handle)) = alloc_data_timer(cb); - if (UV_HANDLE_DATA(Timer_val(handle)) == NULL) + if ((UV_HANDLE_DATA(Timer_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); + UV_HANDLE_DATA_SUB(Timer_val(handle), timer).cb_timer = cb; UV_ERROR_CHECK_C( uv_timer_start(Timer_val(handle), handle_timer_cb, timeout, timeout), { unalloc_data(UV_HANDLE_DATA(Timer_val(handle))); free(Timer_val(handle)); } @@ -1073,9 +1020,9 @@ typedef struct { HL_PRIM uv_process_t **HL_NAME(w_spawn)(uv_loop_t **loop, vclosure *cb, const char *file, varray *args, varray *env, const char *cwd, int flags, varray *stdio, int uid, int gid) { UV_ALLOC_CHECK(handle, uv_process_t); - UV_HANDLE_DATA(Process_val(handle)) = alloc_data_process(cb); - if (UV_HANDLE_DATA(Process_val(handle)) == NULL) + if ((UV_HANDLE_DATA(Process_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); + UV_HANDLE_DATA_SUB(Process_val(handle), process).cb_exit = cb; char **args_u = malloc(sizeof(char *) * (args->size + 1)); for (int i = 0; i < args->size; i++) args_u[i] = strdup(hl_aptr(args, char *)[i]); @@ -1147,8 +1094,7 @@ DEFINE_PRIM(_I32, w_process_get_pid, _PROCESS); HL_PRIM uv_pipe_t **HL_NAME(w_pipe_init)(uv_loop_t **loop, bool ipc) { UV_ALLOC_CHECK(handle, uv_pipe_t); UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(handle), ipc ? 1 : 0), free(Pipe_val(handle))); - UV_HANDLE_DATA(Pipe_val(handle)) = alloc_data_pipe(); - if (UV_HANDLE_DATA(Pipe_val(handle)) == NULL) + if ((UV_HANDLE_DATA(Pipe_val(handle)) = alloc_data()) == NULL) UV_ERROR(0); return handle; } @@ -1162,8 +1108,7 @@ DEFINE_PRIM(_VOID, w_pipe_open, _PIPE _I32); HL_PRIM uv_pipe_t **HL_NAME(w_pipe_accept)(uv_loop_t **loop, uv_pipe_t **server) { UV_ALLOC_CHECK(client, uv_pipe_t); UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(client), 0), free(Pipe_val(client))); - UV_HANDLE_DATA(Pipe_val(client)) = alloc_data_pipe(); - if (UV_HANDLE_DATA(Pipe_val(client)) == NULL) + if ((UV_HANDLE_DATA(Pipe_val(client)) = alloc_data()) == NULL) UV_ERROR(0); UV_ERROR_CHECK_C(uv_accept(Stream_val(server), Stream_val(client)), free(Pipe_val(client))); return client; @@ -1191,8 +1136,7 @@ HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **h case UV_NAMED_PIPE: { UV_ALLOC_CHECK(client, uv_pipe_t); UV_ERROR_CHECK_C(uv_pipe_init(Loop_val(loop), Pipe_val(client), 0), free(Pipe_val(client))); - UV_HANDLE_DATA(Pipe_val(client)) = alloc_data_pipe(); - if (UV_HANDLE_DATA(Pipe_val(client)) == NULL) + if ((UV_HANDLE_DATA(Pipe_val(client)) = alloc_data()) == NULL) UV_ERROR(0); UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Pipe_val(client))); return construct_pipe_accept_pipe(client); @@ -1200,8 +1144,7 @@ HL_PRIM vdynamic *HL_NAME(w_pipe_accept_pending)(uv_loop_t **loop, uv_pipe_t **h case UV_TCP: { UV_ALLOC_CHECK(client, uv_tcp_t); UV_ERROR_CHECK_C(uv_tcp_init(Loop_val(loop), Tcp_val(client)), free(Tcp_val(client))); - UV_HANDLE_DATA(Tcp_val(client)) = alloc_data_tcp(NULL,NULL); - if (UV_HANDLE_DATA(Tcp_val(client)) == NULL) + if ((UV_HANDLE_DATA(Tcp_val(client)) = alloc_data()) == NULL) UV_ERROR(0); UV_ERROR_CHECK_C(uv_accept(Stream_val(handle), Stream_val(client)), free(Tcp_val(client))); return construct_pipe_accept_socket(client); From bcbe54a507e97aadd005c4743a762f415cdb7408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 21:51:06 +0100 Subject: [PATCH 19/22] install autotools on linux --- other/azure-pipelines/build-linux.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/other/azure-pipelines/build-linux.yml b/other/azure-pipelines/build-linux.yml index 6c7b4bd1d..8e2a58262 100644 --- a/other/azure-pipelines/build-linux.yml +++ b/other/azure-pipelines/build-linux.yml @@ -34,6 +34,8 @@ jobs: cmake \ make \ gcc \ + autotools-dev \ + autoconf \ libz-dev \ zlib1g-dev \ libpng-dev \ @@ -56,6 +58,8 @@ jobs: cmake \ make \ gcc-multilib \ + autotools-dev \ + autoconf \ libz-dev:${{ parameters.arch }} \ zlib1g-dev:${{ parameters.arch }} \ libpng-dev:${{ parameters.arch }} \ From 02502e13359999d990c7928d87911be51e896279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 23:00:18 +0100 Subject: [PATCH 20/22] threads and mutexes --- libs/uv/uv.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/libs/uv/uv.c b/libs/uv/uv.c index d594e8ec5..45bd411e7 100644 --- a/libs/uv/uv.c +++ b/libs/uv/uv.c @@ -41,6 +41,7 @@ #define _FS_EVENT _UV(uv_fs_event_t) #define _FS_POLL _UV(uv_fs_poll_t) #define _SIGNAL _UV(uv_signal_t) +#define _MUTEX _UV(uv_mutex_t) // Request types @@ -125,6 +126,7 @@ #define GetAddrInfo_val(v) UV_UNWRAP(v, uv_getaddrinfo_t) #define Handle_val(v) UV_UNWRAP(v, uv_handle_t) #define Loop_val(v) UV_UNWRAP(v, uv_loop_t) +#define Mutex_val(v) UV_UNWRAP(v, uv_mutex_t) #define Pipe_val(v) UV_UNWRAP(v, uv_pipe_t) #define Process_val(v) UV_UNWRAP(v, uv_process_t) #define Shutdown_val(v) UV_UNWRAP(v, uv_shutdown_t) @@ -133,6 +135,7 @@ #define Timer_val(v) UV_UNWRAP(v, uv_timer_t) #define Udp_val(v) UV_UNWRAP(v, uv_udp_t) #define UdpSend_val(v) UV_UNWRAP(v, uv_udp_send_t) +#define Work_val(v) UV_UNWRAP(v, uv_work_t) #define Write_val(v) UV_UNWRAP(v, uv_write_t) // ------------- HAXE CONSTRUCTORS ---------------------------------- @@ -1181,6 +1184,54 @@ HL_PRIM void HL_NAME(w_pipe_write_handle)(uv_pipe_t **handle, vbyte *data, int l } DEFINE_PRIM(_VOID, w_pipe_write_handle, _PIPE _BYTES _I32 _STREAM _CB); +// ------------- THREADS -------------------------------------------- + +static void handle_thread_cb(uv_work_t *req) { + vclosure *cb = UV_REQ_DATA(req); + hl_call0(void, cb); +} + +static void handle_thread_done_cb(uv_work_t *req, int status) { + // TODO: what to do with status? throw in main thread if <0 ? + UV_FREE_REQ(req); +} + +HL_PRIM uv_work_t **HL_NAME(w_thread_create)(uv_loop_t **loop, vclosure *cb) { + UV_ALLOC_REQ(req, uv_work_t, cb); + UV_ERROR_CHECK_C(uv_queue_work(Loop_val(loop), Work_val(req), handle_thread_cb, handle_thread_done_cb), UV_FREE_REQ(Work_val(req))); + return req; +} +DEFINE_PRIM(_WORK, w_thread_create, _CB); + +HL_PRIM void HL_NAME(w_thread_kill)(uv_work_t **thread) { + uv_cancel((uv_req_t *)Work_val(thread)); +} +DEFINE_PRIM(_VOID, w_thread_kill, _WORK); + +// ------------- MUTEX ---------------------------------------------- + +HL_PRIM uv_mutex_t **HL_NAME(w_mutex_init)(void) { + UV_ALLOC_CHECK(handle, uv_mutex_t); + UV_ERROR_CHECK_C(uv_mutex_init(Mutex_val(handle)), free(Mutex_val(handle))); + return handle; +} +DEFINE_PRIM(_MUTEX, w_mutex_init, _NO_ARG); + +HL_PRIM void HL_NAME(w_mutex_lock)(uv_mutex_t **handle) { + uv_mutex_lock(Mutex_val(handle)); +} +DEFINE_PRIM(_VOID, w_mutex_lock, _MUTEX); + +HL_PRIM void HL_NAME(w_mutex_trylock)(uv_mutex_t **handle) { + UV_ERROR_CHECK(uv_mutex_trylock(Mutex_val(handle))); +} +DEFINE_PRIM(_VOID, w_mutex_trylock, _MUTEX); + +HL_PRIM void HL_NAME(w_mutex_unlock)(uv_mutex_t **handle) { + uv_mutex_unlock(Mutex_val(handle)); +} +DEFINE_PRIM(_VOID, w_mutex_unlock, _MUTEX); + // ------------- CASTS ---------------------------------------------- /** From d7b0c6507e71886ecb6fdaa46e9d09a108881a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Tue, 24 Sep 2019 23:02:20 +0100 Subject: [PATCH 21/22] also install libtool on linux --- other/azure-pipelines/build-linux.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/other/azure-pipelines/build-linux.yml b/other/azure-pipelines/build-linux.yml index 8e2a58262..ae67f6ba6 100644 --- a/other/azure-pipelines/build-linux.yml +++ b/other/azure-pipelines/build-linux.yml @@ -36,6 +36,7 @@ jobs: gcc \ autotools-dev \ autoconf \ + libtool \ libz-dev \ zlib1g-dev \ libpng-dev \ @@ -60,6 +61,7 @@ jobs: gcc-multilib \ autotools-dev \ autoconf \ + libtool \ libz-dev:${{ parameters.arch }} \ zlib1g-dev:${{ parameters.arch }} \ libpng-dev:${{ parameters.arch }} \ From cfe558a87aede868d4adf104c2f8bab53e90a919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurel=20Bi=CC=81ly=CC=81?= Date: Fri, 27 Sep 2019 14:05:50 +0100 Subject: [PATCH 22/22] remove more of old UV sample --- CMakeLists.txt | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2eeb769e2..07ba343a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,18 +175,6 @@ if(BUILD_TESTING) DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/threads.hl ) - ##################### - # uvsample.hl - - add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample.hl - COMMAND ${HAXE_COMPILER} - -hl ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample.hl - -cp ${CMAKE_SOURCE_DIR}/other/uvsample -main UVSample - ) - add_custom_target(uvsample.hl ALL - DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample.hl - ) - ##################### # hello.c @@ -231,29 +219,6 @@ if(BUILD_TESTING) libhl ) - ##################### - # uvsample.c - - add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample/uvsample.c - COMMAND ${HAXE_COMPILER} - -hl ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample/uvsample.c - -cp ${CMAKE_SOURCE_DIR}/other/uvsample -main UVSample - ) - add_executable(uvsample - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample/uvsample.c - ) - set_target_properties(uvsample - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample - ) - target_include_directories(uvsample - PRIVATE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample - ) - target_link_libraries(uvsample - libhl - uv.hdll - ) - ##################### # Tests @@ -263,18 +228,12 @@ if(BUILD_TESTING) add_test(NAME threads.hl COMMAND hl ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/threads.hl ) - add_test(NAME uvsample.hl - COMMAND hl ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test/uvsample.hl - ) add_test(NAME hello COMMAND hello ) add_test(NAME threads COMMAND threads ) - add_test(NAME uvsample - COMMAND uvsample - ) add_test(NAME version COMMAND hl --version )