LCOV - code coverage report
Current view: top level - src - jl_uv.c (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 445 499 89.2 %
Date: 2022-07-16 23:42:53 Functions: 80 84 95.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 123 180 68.3 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #include "platform.h"
       4                 :            : 
       5                 :            : #include <stdio.h>
       6                 :            : #include <stddef.h>
       7                 :            : #include <stdint.h>
       8                 :            : #include <stdlib.h>
       9                 :            : #include <string.h>
      10                 :            : 
      11                 :            : #ifdef _OS_WINDOWS_
      12                 :            : #include <ws2tcpip.h>
      13                 :            : #include <malloc.h>
      14                 :            : #else
      15                 :            : #include "errno.h"
      16                 :            : #include <unistd.h>
      17                 :            : #include <sys/socket.h>
      18                 :            : #endif
      19                 :            : 
      20                 :            : #include "julia.h"
      21                 :            : #include "julia_internal.h"
      22                 :            : #include "support/ios.h"
      23                 :            : #include "uv.h"
      24                 :            : 
      25                 :            : #include "julia_assert.h"
      26                 :            : 
      27                 :            : #ifdef __cplusplus
      28                 :            : #include <cstring>
      29                 :            : extern "C" {
      30                 :            : #endif
      31                 :            : 
      32                 :            : static uv_async_t signal_async;
      33                 :            : 
      34                 :      29830 : static void jl_signal_async_cb(uv_async_t *hdl)
      35                 :            : {
      36                 :            :     // This should abort the current loop and the julia code it returns to
      37                 :            :     // or the safepoint in the callers of `uv_run` should throw the exception.
      38                 :            :     (void)hdl;
      39                 :      29830 :     uv_stop(jl_io_loop);
      40                 :      29830 : }
      41                 :            : 
      42                 :      30214 : void jl_wake_libuv(void)
      43                 :            : {
      44                 :      30214 :     uv_async_send(&signal_async);
      45                 :      30214 : }
      46                 :            : 
      47                 :            : jl_mutex_t jl_uv_mutex;
      48                 :            : 
      49                 :        573 : void jl_init_uv(void)
      50                 :            : {
      51                 :        573 :     uv_async_init(jl_io_loop, &signal_async, jl_signal_async_cb);
      52                 :        573 :     JL_MUTEX_INIT(&jl_uv_mutex); // a file-scope initializer can be used instead
      53                 :        573 : }
      54                 :            : 
      55                 :            : _Atomic(int) jl_uv_n_waiters = 0;
      56                 :            : 
      57                 :    7353060 : void JL_UV_LOCK(void)
      58                 :            : {
      59         [ +  + ]:    7353060 :     if (jl_mutex_trylock(&jl_uv_mutex)) {
      60                 :            :     }
      61                 :            :     else {
      62                 :      29626 :         jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, 1);
      63                 :      29626 :         jl_fence(); // [^store_buffering_2]
      64                 :      29626 :         jl_wake_libuv();
      65                 :      29626 :         JL_LOCK(&jl_uv_mutex);
      66                 :      29626 :         jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, -1);
      67                 :            :     }
      68                 :    7353060 : }
      69                 :            : 
      70                 :    6539980 : JL_DLLEXPORT void jl_iolock_begin(void)
      71                 :            : {
      72                 :    6539980 :     JL_UV_LOCK();
      73                 :    6539980 : }
      74                 :            : 
      75                 :    6539760 : JL_DLLEXPORT void jl_iolock_end(void)
      76                 :            : {
      77                 :    6539760 :     JL_UV_UNLOCK();
      78                 :    6539760 : }
      79                 :            : 
      80                 :            : 
      81                 :      90705 : static void jl_uv_call_close_callback(jl_value_t *val)
      82                 :            : {
      83                 :            :     jl_value_t **args;
      84                 :      90705 :     JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now
      85                 :      90705 :     args[0] = jl_get_global(jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module),
      86                 :            :             jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close
      87                 :      90705 :     args[1] = val;
      88         [ -  + ]:      90705 :     assert(args[0]);
      89                 :      90705 :     jl_apply(args, 2); // TODO: wrap in try-catch?
      90                 :      90705 :     JL_GC_POP();
      91                 :      90705 : }
      92                 :            : 
      93                 :      95883 : static void jl_uv_closeHandle(uv_handle_t *handle)
      94                 :            : {
      95                 :            :     // if the user killed a stdio handle,
      96                 :            :     // revert back to direct stdio FILE* writes
      97                 :            :     // so that errors can still be reported
      98         [ +  + ]:      95883 :     if (handle == (uv_handle_t*)JL_STDIN)
      99                 :        297 :         JL_STDIN = (JL_STREAM*)STDIN_FILENO;
     100         [ +  + ]:      95883 :     if (handle == (uv_handle_t*)JL_STDOUT)
     101                 :          1 :         JL_STDOUT = (JL_STREAM*)STDOUT_FILENO;
     102         [ +  + ]:      95883 :     if (handle == (uv_handle_t*)JL_STDERR)
     103                 :          1 :         JL_STDERR = (JL_STREAM*)STDERR_FILENO;
     104                 :            :     // also let the client app do its own cleanup
     105   [ +  -  +  + ]:      95883 :     if (handle->type != UV_FILE && handle->data) {
     106                 :      90705 :         jl_task_t *ct = jl_current_task;
     107                 :      90705 :         size_t last_age = ct->world_age;
     108                 :      90705 :         ct->world_age = jl_atomic_load_acquire(&jl_world_counter);
     109                 :      90705 :         jl_uv_call_close_callback((jl_value_t*)handle->data);
     110                 :      90705 :         ct->world_age = last_age;
     111                 :      90705 :         return;
     112                 :            :     }
     113         [ +  + ]:       5178 :     if (handle == (uv_handle_t*)&signal_async)
     114                 :        571 :         return;
     115                 :       4607 :     free(handle);
     116                 :            : }
     117                 :            : 
     118                 :       5990 : static void jl_uv_flush_close_callback(uv_write_t *req, int status)
     119                 :            : {
     120                 :       5990 :     uv_stream_t *stream = req->handle;
     121                 :       5990 :     req->handle = NULL;
     122                 :            :     // ignore attempts to close the stream while attempting a graceful shutdown
     123                 :            : #ifdef _OS_WINDOWS_
     124                 :            :     if (stream->stream.conn.shutdown_req)
     125                 :            : #else
     126         [ -  + ]:       5990 :     if (stream->shutdown_req)
     127                 :            : #endif
     128                 :            :     {
     129                 :          0 :         free(req);
     130                 :          0 :         return;
     131                 :            :     }
     132         [ -  + ]:       5990 :     if (uv_is_closing((uv_handle_t*)stream)) { // avoid double-close on the stream
     133                 :          0 :         free(req);
     134                 :          0 :         return;
     135                 :            :     }
     136   [ +  -  +  +  :       5990 :     if (status == 0 && uv_is_writable(stream) && stream->write_queue_size != 0) {
                   +  + ]
     137                 :            :         // new data was written, wait for it to flush too
     138                 :            :         uv_buf_t buf;
     139                 :          1 :         buf.base = (char*)(req + 1);
     140                 :          1 :         buf.len = 0;
     141                 :          1 :         req->data = NULL;
     142         [ +  - ]:          1 :         if (uv_write(req, stream, &buf, 1, (uv_write_cb)jl_uv_flush_close_callback) == 0)
     143                 :          1 :             return; // success
     144                 :            :     }
     145                 :       5989 :     free(req);
     146         [ +  + ]:       5989 :     if (stream->type == UV_TTY)
     147                 :        454 :         uv_tty_set_mode((uv_tty_t*)stream, UV_TTY_MODE_NORMAL);
     148                 :       5989 :     uv_close((uv_handle_t*)stream, &jl_uv_closeHandle);
     149                 :            : }
     150                 :            : 
     151                 :          0 : static void uv_flush_callback(uv_write_t *req, int status)
     152                 :            : {
     153                 :          0 :     *(int*)(req->data) = 1;
     154                 :          0 :     uv_stop(req->handle->loop);
     155                 :          0 :     free(req);
     156                 :          0 : }
     157                 :            : 
     158                 :            : // Turn a normal write into a blocking write (primarily for use from C and gdb).
     159                 :            : // Warning: This calls uv_run, so it can have unbounded side-effects.
     160                 :            : // Be care where you call it from! - the libuv loop is also not reentrant.
     161                 :        179 : JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream)
     162                 :            : {
     163   [ +  -  +  - ]:        179 :     if (stream == (void*)STDIN_FILENO ||
     164         [ -  + ]:        179 :         stream == (void*)STDOUT_FILENO ||
     165                 :            :         stream == (void*)STDERR_FILENO)
     166                 :          0 :         return;
     167         [ +  + ]:        179 :     if (stream->type != UV_TTY &&
     168         [ +  - ]:          8 :         stream->type != UV_TCP &&
     169         [ +  + ]:          8 :         stream->type != UV_NAMED_PIPE)
     170                 :          2 :         return;
     171                 :        177 :     JL_UV_LOCK();
     172   [ +  -  -  + ]:        177 :     while (uv_is_writable(stream) && stream->write_queue_size != 0) {
     173                 :          0 :         int fired = 0;
     174                 :            :         uv_buf_t buf;
     175                 :          0 :         buf.base = (char*)(&buf + 1);
     176                 :          0 :         buf.len = 0;
     177                 :          0 :         uv_write_t *write_req = (uv_write_t*)malloc_s(sizeof(uv_write_t));
     178                 :          0 :         write_req->data = (void*)&fired;
     179         [ #  # ]:          0 :         if (uv_write(write_req, stream, &buf, 1, uv_flush_callback) != 0) {
     180                 :          0 :             JL_UV_UNLOCK();
     181                 :          0 :             return;
     182                 :            :         }
     183         [ #  # ]:          0 :         while (!fired) {
     184                 :          0 :             uv_run(uv_default_loop(), UV_RUN_DEFAULT);
     185                 :            :         }
     186                 :            :     }
     187                 :        177 :     JL_UV_UNLOCK();
     188                 :            : }
     189                 :            : 
     190                 :            : // getters and setters
     191                 :            : // TODO: check if whoever calls these is thread-safe
     192                 :          2 : JL_DLLEXPORT int jl_uv_process_pid(uv_process_t *p) { return p->pid; }
     193                 :       1647 : JL_DLLEXPORT void *jl_uv_process_data(uv_process_t *p) { return p->data; }
     194                 :         69 : JL_DLLEXPORT void *jl_uv_buf_base(const uv_buf_t *buf) { return buf->base; }
     195                 :     142762 : JL_DLLEXPORT size_t jl_uv_buf_len(const uv_buf_t *buf) { return buf->len; }
     196                 :     142580 : JL_DLLEXPORT void jl_uv_buf_set_base(uv_buf_t *buf, char *b) { buf->base = b; }
     197                 :     142580 : JL_DLLEXPORT void jl_uv_buf_set_len(uv_buf_t *buf, size_t n) { buf->len = n; }
     198                 :       1023 : JL_DLLEXPORT void *jl_uv_connect_handle(uv_connect_t *connect) { return connect->handle; }
     199                 :        512 : JL_DLLEXPORT uv_os_fd_t jl_uv_file_handle(jl_uv_file_t *f) { return f->file; }
     200                 :     543370 : JL_DLLEXPORT void *jl_uv_req_data(uv_req_t *req) { return req->data; }
     201                 :     815486 : JL_DLLEXPORT void jl_uv_req_set_data(uv_req_t *req, void *data) { req->data = data; }
     202                 :     376022 : JL_DLLEXPORT void *jl_uv_handle_data(uv_handle_t *handle) { return handle->data; }
     203                 :          0 : JL_DLLEXPORT void *jl_uv_write_handle(uv_write_t *req) { return req->handle; }
     204                 :            : 
     205                 :            : extern _Atomic(unsigned) _threadedregion;
     206                 :            : 
     207                 :    2102580 : JL_DLLEXPORT int jl_process_events(void)
     208                 :            : {
     209                 :    2102580 :     jl_task_t *ct = jl_current_task;
     210                 :    2102580 :     uv_loop_t *loop = jl_io_loop;
     211                 :    2102580 :     jl_gc_safepoint_(ct->ptls);
     212   [ +  +  +  +  :    2102580 :     if (loop && (jl_atomic_load_relaxed(&_threadedregion) || jl_atomic_load_relaxed(&ct->tid) == 0)) {
                   +  + ]
     213   [ +  #  +  + ]:    1589580 :         if (jl_atomic_load_relaxed(&jl_uv_n_waiters) == 0 && jl_mutex_trylock(&jl_uv_mutex)) {
     214                 :            :             JL_PROBE_RT_START_PROCESS_EVENTS(ct);
     215                 :    1482600 :             loop->stop_flag = 0;
     216                 :    1482600 :             int r = uv_run(loop, UV_RUN_NOWAIT);
     217                 :            :             JL_PROBE_RT_FINISH_PROCESS_EVENTS(ct);
     218                 :    1485220 :             JL_UV_UNLOCK();
     219                 :    1485220 :             return r;
     220                 :            :         }
     221                 :     107047 :         jl_gc_safepoint_(ct->ptls);
     222                 :            :     }
     223                 :     620050 :     return 0;
     224                 :            : }
     225                 :            : 
     226                 :          2 : static void jl_proc_exit_cleanup_cb(uv_process_t *process, int64_t exit_status, int term_signal)
     227                 :            : {
     228                 :          2 :     uv_close((uv_handle_t*)process, (uv_close_cb)&free);
     229                 :          2 : }
     230                 :            : 
     231                 :      95837 : JL_DLLEXPORT void jl_close_uv(uv_handle_t *handle)
     232                 :            : {
     233                 :      95837 :     JL_UV_LOCK();
     234   [ +  +  +  + ]:      95837 :     if (handle->type == UV_PROCESS && ((uv_process_t*)handle)->pid != 0) {
     235                 :            :         // take ownership of this handle,
     236                 :            :         // so we can waitpid for the resource to exit and avoid leaving zombies
     237         [ -  + ]:         27 :         assert(handle->data == NULL); // make sure Julia has forgotten about it already
     238                 :         27 :         ((uv_process_t*)handle)->exit_cb = jl_proc_exit_cleanup_cb;
     239                 :         27 :         uv_unref(handle);
     240                 :            :     }
     241         [ -  + ]:      95810 :     else if (handle->type == UV_FILE) {
     242                 :            :         uv_fs_t req;
     243                 :          0 :         jl_uv_file_t *fd = (jl_uv_file_t*)handle;
     244         [ #  # ]:          0 :         if ((ssize_t)fd->file != -1) {
     245                 :          0 :             uv_fs_close(handle->loop, &req, fd->file, NULL);
     246                 :          0 :             fd->file = (uv_os_fd_t)(ssize_t)-1;
     247                 :            :         }
     248                 :          0 :         jl_uv_closeHandle(handle); // synchronous (ok since the callback is known to not interact with any global state)
     249                 :            :     }
     250         [ +  + ]:      95810 :     else if (!uv_is_closing(handle)) { // avoid double-closing the stream
     251   [ +  +  +  +  :     101770 :         if (handle->type == UV_NAMED_PIPE || handle->type == UV_TCP || handle->type == UV_TTY) {
                   +  + ]
     252                 :            :             // flush the stream write-queue first
     253                 :       5989 :             uv_write_t *req = (uv_write_t*)malloc_s(sizeof(uv_write_t));
     254                 :       5989 :             req->handle = (uv_stream_t*)handle;
     255                 :       5989 :             jl_uv_flush_close_callback(req, 0);
     256                 :            :         }
     257                 :            :         else {
     258                 :      89792 :             uv_close(handle, &jl_uv_closeHandle);
     259                 :            :         }
     260                 :            :     }
     261                 :      95837 :     JL_UV_UNLOCK();
     262                 :      95837 : }
     263                 :            : 
     264                 :        102 : JL_DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle)
     265                 :            : {
     266         [ +  - ]:        102 :     if (!uv_is_closing(handle)) { // avoid double-closing the stream
     267                 :        102 :         JL_UV_LOCK();
     268         [ +  - ]:        102 :         if (!uv_is_closing(handle)) { // double-check
     269                 :        102 :             uv_close(handle, &jl_uv_closeHandle);
     270                 :            :         }
     271                 :        102 :         JL_UV_UNLOCK();
     272                 :            :     }
     273                 :        102 : }
     274                 :            : 
     275                 :      95306 : JL_DLLEXPORT void jl_uv_associate_julia_struct(uv_handle_t *handle,
     276                 :            :                                                jl_value_t *data)
     277                 :            : {
     278                 :      95306 :     handle->data = data;
     279                 :      95306 : }
     280                 :            : 
     281                 :      10695 : JL_DLLEXPORT void jl_uv_disassociate_julia_struct(uv_handle_t *handle)
     282                 :            : {
     283                 :      10695 :     handle->data = NULL;
     284                 :      10695 : }
     285                 :            : 
     286                 :            : #define UV_HANDLE_CLOSED 0x02
     287                 :            : 
     288                 :       1675 : JL_DLLEXPORT int jl_spawn(char *name, char **argv,
     289                 :            :                           uv_loop_t *loop, uv_process_t *proc,
     290                 :            :                           uv_stdio_container_t *stdio, int nstdio,
     291                 :            :                           uint32_t flags, char **env, char *cwd, char* cpumask,
     292                 :            :                           size_t cpumask_size, uv_exit_cb cb)
     293                 :            : {
     294                 :       1675 :     uv_process_options_t opts = {0};
     295                 :       1675 :     opts.stdio = stdio;
     296                 :       1675 :     opts.file = name;
     297                 :       1675 :     opts.env = env;
     298                 :       1675 :     opts.flags = flags;
     299                 :            :     // unused fields:
     300                 :            :     //opts.uid = 0;
     301                 :            :     //opts.gid = 0;
     302                 :       1675 :     opts.cpumask = cpumask;
     303                 :       1675 :     opts.cpumask_size = cpumask_size;
     304                 :       1675 :     opts.cwd = cwd;
     305                 :       1675 :     opts.args = argv;
     306                 :       1675 :     opts.stdio_count = nstdio;
     307         [ +  + ]:       6512 :     while (nstdio--) {
     308                 :       4837 :         int flags = opts.stdio[nstdio].flags;
     309   [ +  +  +  +  :       4837 :         if (!(flags == UV_INHERIT_FD || flags == UV_INHERIT_STREAM || flags == UV_IGNORE)) {
                   -  + ]
     310                 :          0 :             proc->type = UV_PROCESS;
     311                 :          0 :             proc->loop = loop;
     312                 :          0 :             proc->flags = UV_HANDLE_CLOSED;
     313                 :          0 :             return UV_EINVAL;
     314                 :            :         }
     315                 :            :     }
     316                 :       1675 :     opts.exit_cb = cb;
     317                 :       1675 :     JL_UV_LOCK();
     318                 :       1675 :     int r = uv_spawn(loop, proc, &opts);
     319                 :       1675 :     JL_UV_UNLOCK();
     320                 :       1675 :     return r;
     321                 :            : }
     322                 :            : 
     323                 :            : #ifdef _OS_WINDOWS_
     324                 :            : #include <time.h>
     325                 :            : JL_DLLEXPORT struct tm *localtime_r(const time_t *t, struct tm *tm)
     326                 :            : {
     327                 :            :     struct tm *tmp = localtime(t); //localtime is reentrant on windows
     328                 :            :     if (tmp)
     329                 :            :         *tm = *tmp;
     330                 :            :     return tmp;
     331                 :            : }
     332                 :            : #endif
     333                 :            : 
     334                 :     766092 : JL_DLLEXPORT uv_loop_t *jl_global_event_loop(void)
     335                 :            : {
     336                 :     766092 :     return jl_io_loop;
     337                 :            : }
     338                 :            : 
     339                 :      16571 : JL_DLLEXPORT int jl_fs_unlink(char *path)
     340                 :            : {
     341                 :            :     uv_fs_t req;
     342                 :      16571 :     JL_SIGATOMIC_BEGIN();
     343                 :      16571 :     int ret = uv_fs_unlink(unused_uv_loop_arg, &req, path, NULL);
     344                 :      16571 :     uv_fs_req_cleanup(&req);
     345         [ +  - ]:      16571 :     JL_SIGATOMIC_END();
     346                 :      16571 :     return ret;
     347                 :            : }
     348                 :            : 
     349                 :        126 : JL_DLLEXPORT int jl_fs_rename(const char *src_path, const char *dst_path)
     350                 :            : {
     351                 :            :     uv_fs_t req;
     352                 :        126 :     JL_SIGATOMIC_BEGIN();
     353                 :        126 :     int ret = uv_fs_rename(unused_uv_loop_arg, &req, src_path, dst_path, NULL);
     354                 :        126 :     uv_fs_req_cleanup(&req);
     355         [ +  - ]:        126 :     JL_SIGATOMIC_END();
     356                 :        126 :     return ret;
     357                 :            : }
     358                 :            : 
     359                 :       3907 : JL_DLLEXPORT int jl_fs_sendfile(uv_os_fd_t src_fd, uv_os_fd_t dst_fd,
     360                 :            :                                 int64_t in_offset, size_t len)
     361                 :            : {
     362                 :            :     uv_fs_t req;
     363                 :       3907 :     JL_SIGATOMIC_BEGIN();
     364                 :       3907 :     int ret = uv_fs_sendfile(unused_uv_loop_arg, &req, dst_fd, src_fd,
     365                 :            :                              in_offset, len, NULL);
     366                 :       3907 :     uv_fs_req_cleanup(&req);
     367         [ +  - ]:       3907 :     JL_SIGATOMIC_END();
     368                 :       3907 :     return ret;
     369                 :            : }
     370                 :            : 
     371                 :          3 : JL_DLLEXPORT int jl_fs_hardlink(char *path, char *new_path)
     372                 :            : {
     373                 :            :     uv_fs_t req;
     374                 :          3 :     int ret = uv_fs_link(unused_uv_loop_arg, &req, path, new_path, NULL);
     375                 :          3 :     uv_fs_req_cleanup(&req);
     376                 :          3 :     return ret;
     377                 :            : }
     378                 :            : 
     379                 :       2173 : JL_DLLEXPORT int jl_fs_symlink(char *path, char *new_path, int flags)
     380                 :            : {
     381                 :            :     uv_fs_t req;
     382                 :       2173 :     int ret = uv_fs_symlink(unused_uv_loop_arg, &req, path, new_path, flags, NULL);
     383                 :       2173 :     uv_fs_req_cleanup(&req);
     384                 :       2173 :     return ret;
     385                 :            : }
     386                 :            : 
     387                 :       9125 : JL_DLLEXPORT int jl_fs_chmod(char *path, int mode)
     388                 :            : {
     389                 :            :     uv_fs_t req;
     390                 :       9125 :     int ret = uv_fs_chmod(unused_uv_loop_arg, &req, path, mode, NULL);
     391                 :       9125 :     uv_fs_req_cleanup(&req);
     392                 :       9125 :     return ret;
     393                 :            : }
     394                 :            : 
     395                 :          2 : JL_DLLEXPORT int jl_fs_chown(char *path, int uid, int gid)
     396                 :            : {
     397                 :            :     uv_fs_t req;
     398                 :          2 :     int ret = uv_fs_chown(unused_uv_loop_arg, &req, path, uid, gid, NULL);
     399                 :          2 :     uv_fs_req_cleanup(&req);
     400                 :          2 :     return ret;
     401                 :            : }
     402                 :            : 
     403                 :        111 : JL_DLLEXPORT int jl_fs_access(char *path, int mode)
     404                 :            : {
     405                 :            :     uv_fs_t req;
     406                 :        111 :     int ret = uv_fs_access(unused_uv_loop_arg, &req, path, mode, NULL);
     407                 :        111 :     uv_fs_req_cleanup(&req);
     408                 :        111 :     return ret;
     409                 :            : }
     410                 :            : 
     411                 :        304 : JL_DLLEXPORT int jl_fs_write(uv_os_fd_t handle, const char *data, size_t len,
     412                 :            :                              int64_t offset) JL_NOTSAFEPOINT
     413                 :            : {
     414                 :        304 :     jl_task_t *ct = jl_get_current_task();
     415                 :            :     // TODO: fix this cheating
     416   [ +  -  +  +  :        304 :     if (jl_get_safe_restore() || ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0)
                   -  + ]
     417                 :            : #ifdef _OS_WINDOWS_
     418                 :            :         return WriteFile(handle, data, len, NULL, NULL);
     419                 :            : #else
     420                 :         77 :         return write(handle, data, len);
     421                 :            : #endif
     422                 :            :     uv_fs_t req;
     423                 :            :     uv_buf_t buf[1];
     424                 :        227 :     buf[0].base = (char*)data;
     425                 :        227 :     buf[0].len = len;
     426         [ -  + ]:        227 :     if (!jl_io_loop)
     427                 :          0 :         jl_io_loop = uv_default_loop();
     428                 :        227 :     int ret = uv_fs_write(unused_uv_loop_arg, &req, handle, buf, 1, offset, NULL);
     429                 :        227 :     uv_fs_req_cleanup(&req);
     430                 :        227 :     return ret;
     431                 :            : }
     432                 :            : 
     433                 :        121 : JL_DLLEXPORT int jl_fs_read(uv_os_fd_t handle, char *data, size_t len)
     434                 :            : {
     435                 :            :     uv_fs_t req;
     436                 :            :     uv_buf_t buf[1];
     437                 :        121 :     buf[0].base = data;
     438                 :        121 :     buf[0].len = len;
     439                 :        121 :     int ret = uv_fs_read(unused_uv_loop_arg, &req, handle, buf, 1, -1, NULL);
     440                 :        121 :     uv_fs_req_cleanup(&req);
     441                 :        121 :     return ret;
     442                 :            : }
     443                 :            : 
     444                 :    8718230 : JL_DLLEXPORT int jl_fs_read_byte(uv_os_fd_t handle)
     445                 :            : {
     446                 :            :     uv_fs_t req;
     447                 :            :     unsigned char c;
     448                 :            :     uv_buf_t buf[1];
     449                 :    8718230 :     buf[0].base = (char*)&c;
     450                 :    8718230 :     buf[0].len = 1;
     451                 :    8718230 :     int ret = uv_fs_read(unused_uv_loop_arg, &req, handle, buf, 1, -1, NULL);
     452                 :    8718230 :     uv_fs_req_cleanup(&req);
     453   [ -  +  +  - ]:    8718230 :     switch (ret) {
     454                 :          0 :     case -1: return ret;
     455                 :          2 :     case  0: jl_eof_error();
     456                 :    8718230 :     case  1: return (int)c;
     457                 :          0 :     default:
     458                 :          0 :         assert(0 && "jl_fs_read_byte: Invalid return value from uv_fs_read");
     459                 :            :         return -1;
     460                 :            :     }
     461                 :            : }
     462                 :            : 
     463                 :       8811 : JL_DLLEXPORT int jl_fs_close(uv_os_fd_t handle)
     464                 :            : {
     465                 :            :     uv_fs_t req;
     466                 :       8811 :     int ret = uv_fs_close(unused_uv_loop_arg, &req, handle, NULL);
     467                 :       8811 :     uv_fs_req_cleanup(&req);
     468                 :       8811 :     return ret;
     469                 :            : }
     470                 :            : 
     471                 :     271609 : JL_DLLEXPORT int jl_uv_write(uv_stream_t *stream, const char *data, size_t n,
     472                 :            :                              uv_write_t *uvw, uv_write_cb writecb)
     473                 :            : {
     474                 :            :     uv_buf_t buf[1];
     475                 :     271609 :     buf[0].base = (char*)data;
     476                 :     271609 :     buf[0].len = n;
     477                 :     271609 :     JL_UV_LOCK();
     478                 :     271609 :     JL_SIGATOMIC_BEGIN();
     479                 :     271609 :     int err = uv_write(uvw, stream, buf, 1, writecb);
     480                 :     271609 :     JL_UV_UNLOCK();
     481         [ -  + ]:     271609 :     JL_SIGATOMIC_END();
     482                 :     271609 :     return err;
     483                 :            : }
     484                 :            : 
     485                 :        903 : static void jl_uv_writecb(uv_write_t *req, int status) JL_NOTSAFEPOINT
     486                 :            : {
     487                 :        903 :     free(req);
     488         [ -  + ]:        903 :     if (status < 0) {
     489                 :          0 :         jl_safe_printf("jl_uv_writecb() ERROR: %s %s\n",
     490                 :            :                        uv_strerror(status), uv_err_name(status));
     491                 :            :     }
     492                 :        903 : }
     493                 :            : 
     494                 :      60046 : JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n)
     495                 :            : {
     496         [ -  + ]:      60046 :     assert(stream);
     497                 :            :     static_assert(offsetof(uv_stream_t,type) == offsetof(ios_t,bm) &&
     498                 :            :         sizeof(((uv_stream_t*)0)->type) == sizeof(((ios_t*)0)->bm),
     499                 :            :             "UV and ios layout mismatch");
     500                 :            : 
     501                 :      60046 :     uv_os_fd_t fd = (uv_os_fd_t)(ssize_t)-1;
     502                 :            : 
     503                 :            :     // Fallback for output during early initialisation...
     504         [ +  + ]:      60046 :     if (stream == (void*)STDOUT_FILENO) {
     505                 :         27 :         fd = UV_STDOUT_FD;
     506                 :            :     }
     507         [ +  + ]:      60019 :     else if (stream == (void*)STDERR_FILENO) {
     508                 :        141 :         fd = UV_STDERR_FD;
     509                 :            :     }
     510         [ +  + ]:      59878 :     else if (stream->type == UV_FILE) {
     511                 :          6 :         fd = ((jl_uv_file_t*)stream)->file;
     512                 :            :     }
     513                 :            : 
     514                 :            :     // TODO: Hack to make CoreIO thread-safer
     515                 :      60046 :     jl_task_t *ct = jl_get_current_task();
     516   [ +  +  -  + ]:      60046 :     if (ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0) {
     517         [ +  + ]:         77 :         if (stream == JL_STDOUT) {
     518                 :          5 :             fd = UV_STDOUT_FD;
     519                 :            :         }
     520         [ +  - ]:         72 :         else if (stream == JL_STDERR) {
     521                 :         72 :             fd = UV_STDERR_FD;
     522                 :            :         }
     523                 :            :     }
     524                 :            : 
     525         [ +  + ]:      60046 :     if ((ssize_t)fd != -1) {
     526                 :            :         // Write to file descriptor...
     527                 :        174 :         jl_fs_write(fd, str, n, -1);
     528                 :            :     }
     529         [ +  + ]:      59872 :     else if (stream->type > UV_HANDLE_TYPE_MAX) {
     530                 :            :         // Write to ios.c stream...
     531                 :            :         // This is needed because caller jl_static_show() in builtins.c can be
     532                 :            :         // called from fl_print in flisp/print.c (via cvalue_printdata()),
     533                 :            :         // and cvalue_printdata() passes ios_t* to jl_static_show().
     534                 :      58969 :         ios_write((ios_t*)stream, str, n);
     535                 :            :     }
     536                 :            :     else {
     537                 :            :         // Write to libuv stream...
     538                 :        903 :         uv_write_t *req = (uv_write_t*)malloc_s(sizeof(uv_write_t) + n);
     539                 :        903 :         char *data = (char*)(req + 1);
     540                 :        903 :         memcpy(data, str, n);
     541                 :            :         uv_buf_t buf[1];
     542                 :        903 :         buf[0].base = data;
     543                 :        903 :         buf[0].len = n;
     544                 :        903 :         req->data = NULL;
     545                 :        903 :         JL_UV_LOCK();
     546                 :        903 :         JL_SIGATOMIC_BEGIN();
     547                 :        903 :         int status = uv_write(req, stream, buf, 1, (uv_write_cb)jl_uv_writecb);
     548                 :        903 :         JL_UV_UNLOCK();
     549         [ +  + ]:        903 :         JL_SIGATOMIC_END();
     550         [ -  + ]:        903 :         if (status < 0) {
     551                 :          0 :             jl_uv_writecb(req, status);
     552                 :            :         }
     553                 :            :     }
     554                 :      60046 : }
     555                 :            : 
     556                 :        230 : JL_DLLEXPORT void jl_uv_putb(uv_stream_t *stream, uint8_t b)
     557                 :            : {
     558                 :        230 :     jl_uv_puts(stream, (char*)&b, 1);
     559                 :        230 : }
     560                 :            : 
     561                 :          2 : JL_DLLEXPORT void jl_uv_putc(uv_stream_t *stream, uint32_t c)
     562                 :            : {
     563                 :            :     char s[4];
     564                 :          2 :     int n = 1;
     565                 :          2 :     s[0] = c >> 24;
     566         [ +  - ]:          2 :     if ((s[1] = c >> 16)) {
     567                 :          2 :         n++;
     568         [ -  + ]:          2 :         if ((s[2] = c >> 8)) {
     569                 :          0 :             n++;
     570         [ #  # ]:          0 :             if ((s[3] = c)) {
     571                 :          0 :                 n++;
     572                 :            :             }
     573                 :            :         }
     574                 :            :     }
     575                 :          2 :     jl_uv_puts(stream, s, n);
     576                 :          2 : }
     577                 :            : 
     578                 :            : extern int vasprintf(char **str, const char *fmt, va_list ap);
     579                 :            : 
     580                 :      59485 : JL_DLLEXPORT int jl_vprintf(uv_stream_t *s, const char *format, va_list args)
     581                 :            : {
     582                 :      59485 :     char *str = NULL;
     583                 :            :     int c;
     584                 :            :     va_list al;
     585                 :            : #if defined(_OS_WINDOWS_) && !defined(_COMPILER_GCC_)
     586                 :            :     al = args;
     587                 :            : #else
     588                 :      59485 :     va_copy(al, args);
     589                 :            : #endif
     590                 :            : 
     591                 :      59485 :     c = vasprintf(&str, format, al);
     592                 :            : 
     593         [ +  - ]:      59485 :     if (c >= 0) {
     594                 :      59485 :         jl_uv_puts(s, str, c);
     595                 :      59485 :         free(str);
     596                 :            :     }
     597                 :      59485 :     va_end(al);
     598                 :      59485 :     return c;
     599                 :            : }
     600                 :            : 
     601                 :      59459 : JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...)
     602                 :            : {
     603                 :            :     va_list args;
     604                 :            :     int c;
     605                 :            : 
     606                 :      59459 :     va_start(args, format);
     607                 :      59459 :     c = jl_vprintf(s, format, args);
     608                 :      59459 :     va_end(args);
     609                 :      59459 :     return c;
     610                 :            : }
     611                 :            : 
     612                 :        664 : JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...)
     613                 :            : {
     614                 :            :     static char buf[1000];
     615                 :        664 :     buf[0] = '\0';
     616                 :        664 :     int last_errno = errno;
     617                 :            : #ifdef _OS_WINDOWS_
     618                 :            :     DWORD last_error = GetLastError();
     619                 :            : #endif
     620                 :            : 
     621                 :            :     va_list args;
     622                 :        664 :     va_start(args, fmt);
     623                 :            :     // Not async signal safe on some platforms?
     624                 :        664 :     vsnprintf(buf, sizeof(buf), fmt, args);
     625                 :        664 :     va_end(args);
     626                 :            : 
     627                 :        664 :     buf[999] = '\0';
     628                 :        664 :     if (write(STDERR_FILENO, buf, strlen(buf)) < 0) {
     629                 :            :         // nothing we can do; ignore the failure
     630                 :            :     }
     631                 :            : #ifdef _OS_WINDOWS_
     632                 :            :     SetLastError(last_error);
     633                 :            : #endif
     634                 :        664 :     errno = last_errno;
     635                 :        664 : }
     636                 :            : 
     637                 :        278 : JL_DLLEXPORT void jl_exit(int exitcode)
     638                 :            : {
     639                 :        278 :     uv_tty_reset_mode();
     640                 :        278 :     jl_atexit_hook(exitcode);
     641                 :        214 :     exit(exitcode);
     642                 :            : }
     643                 :            : 
     644                 :            : typedef union {
     645                 :            :     struct sockaddr in;
     646                 :            :     struct sockaddr_in v4;
     647                 :            :     struct sockaddr_in6 v6;
     648                 :            : } uv_sockaddr_in;
     649                 :            : 
     650                 :       1341 : static void jl_sockaddr_fill(uv_sockaddr_in *addr, uint16_t port, void *host, int ipv6)
     651                 :            : {
     652                 :       1341 :     memset(addr, 0, sizeof(*addr));
     653         [ +  + ]:       1341 :     if (ipv6) {
     654                 :         20 :         addr->v6.sin6_family = AF_INET6;
     655                 :         20 :         memcpy(&addr->v6.sin6_addr, host, 16);
     656                 :         20 :         addr->v6.sin6_port = port;
     657                 :            :     }
     658                 :            :     else {
     659                 :       1321 :         addr->v4.sin_family = AF_INET;
     660                 :       1321 :         addr->v4.sin_addr.s_addr = *(uint32_t*)host;
     661                 :       1321 :         addr->v4.sin_port = port;
     662                 :            :     }
     663                 :       1341 : }
     664                 :            : 
     665                 :            : //NOTE: These function expects port/host to be in network byte-order (Big Endian)
     666                 :        674 : JL_DLLEXPORT int jl_tcp_bind(uv_tcp_t *handle, uint16_t port, void *host,
     667                 :            :                              unsigned int flags, int ipv6)
     668                 :            : {
     669                 :            :     uv_sockaddr_in addr;
     670                 :        674 :     jl_sockaddr_fill(&addr, port, host, ipv6);
     671                 :        674 :     return uv_tcp_bind(handle, (struct sockaddr*)&addr, flags);
     672                 :            : }
     673                 :            : 
     674                 :        192 : JL_DLLEXPORT int jl_tcp_getsockname(uv_tcp_t *handle, uint16_t *port,
     675                 :            :                                     void *host, uint32_t *family)
     676                 :            : {
     677                 :            :     int namelen;
     678                 :            :     struct sockaddr_storage addr;
     679                 :        192 :     memset(&addr, 0, sizeof(struct sockaddr_storage));
     680                 :        192 :     namelen = sizeof addr;
     681                 :        192 :     int res = uv_tcp_getsockname(handle, (struct sockaddr*)&addr, &namelen);
     682         [ +  + ]:        192 :     if (res)
     683                 :          2 :         return res;
     684                 :        190 :     *family = addr.ss_family;
     685         [ +  + ]:        190 :     if (addr.ss_family == AF_INET) {
     686                 :        187 :         struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr;
     687                 :        187 :         *port = addr4->sin_port;
     688                 :        187 :         memcpy(host, &(addr4->sin_addr), 4);
     689                 :            :     }
     690         [ +  - ]:          3 :     else if (addr.ss_family == AF_INET6) {
     691                 :          3 :         struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&addr;
     692                 :          3 :         *port = addr6->sin6_port;
     693                 :          3 :         memcpy(host, &(addr6->sin6_addr), 16);
     694                 :            :     }
     695                 :        190 :     return res;
     696                 :            : }
     697                 :            : 
     698                 :         19 : JL_DLLEXPORT int jl_tcp_getpeername(uv_tcp_t *handle, uint16_t *port,
     699                 :            :                                     void *host, uint32_t *family)
     700                 :            : {
     701                 :            :     int namelen;
     702                 :            :     struct sockaddr_storage addr;
     703                 :         19 :     memset(&addr, 0, sizeof(struct sockaddr_storage));
     704                 :         19 :     namelen = sizeof addr;
     705                 :         19 :     int res = uv_tcp_getpeername(handle, (struct sockaddr*)&addr, &namelen);
     706         [ +  + ]:         19 :     if (res)
     707                 :          1 :         return res;
     708                 :         18 :     *family = addr.ss_family;
     709         [ +  + ]:         18 :     if (addr.ss_family == AF_INET) {
     710                 :         16 :         struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr;
     711                 :         16 :         *port = addr4->sin_port;
     712                 :         16 :         memcpy(host, &(addr4->sin_addr), 4);
     713                 :            :     }
     714         [ +  - ]:          2 :     else if (addr.ss_family == AF_INET6) {
     715                 :          2 :         struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&addr;
     716                 :          2 :         *port = addr6->sin6_port;
     717                 :          2 :         memcpy(host, &(addr6->sin6_addr), 16);
     718                 :            :     }
     719                 :         18 :     return res;
     720                 :            : }
     721                 :            : 
     722                 :         10 : JL_DLLEXPORT int jl_udp_bind(uv_udp_t *handle, uint16_t port, void *host,
     723                 :            :                              uint32_t flags, int ipv6)
     724                 :            : {
     725                 :            :     uv_sockaddr_in addr;
     726                 :         10 :     jl_sockaddr_fill(&addr, port, host, ipv6);
     727                 :         10 :     return uv_udp_bind(handle, (struct sockaddr*)&addr, flags);
     728                 :            : }
     729                 :            : 
     730                 :         40 : JL_DLLEXPORT int jl_udp_send(uv_udp_send_t *req, uv_udp_t *handle, uint16_t port, void *host,
     731                 :            :                              char *data, uint32_t size, uv_udp_send_cb cb, int ipv6)
     732                 :            : {
     733                 :            :     uv_sockaddr_in addr;
     734                 :         40 :     jl_sockaddr_fill(&addr, port, host, ipv6);
     735                 :            :     uv_buf_t buf[1];
     736                 :         40 :     buf[0].base = data;
     737                 :         40 :     buf[0].len = size;
     738                 :         40 :     int r = uv_udp_send(req, handle, buf, 1, (struct sockaddr*)&addr, cb);
     739                 :         40 :     return r;
     740                 :            : }
     741                 :            : 
     742                 :          1 : JL_DLLEXPORT int jl_uv_sizeof_interface_address(void)
     743                 :            : {
     744                 :          1 :     return sizeof(uv_interface_address_t);
     745                 :            : }
     746                 :            : 
     747                 :         26 : JL_DLLEXPORT int jl_uv_interface_addresses(uv_interface_address_t **ifAddrStruct,
     748                 :            :                                            int *count)
     749                 :            : {
     750                 :         26 :     return uv_interface_addresses(ifAddrStruct, count);
     751                 :            : }
     752                 :            : 
     753                 :        104 : JL_DLLEXPORT int jl_uv_interface_address_is_internal(uv_interface_address_t *addr)
     754                 :            : {
     755                 :        104 :     return addr->is_internal;
     756                 :            : }
     757                 :            : 
     758                 :         56 : JL_DLLEXPORT struct sockaddr_in *jl_uv_interface_address_sockaddr(uv_interface_address_t *ifa)
     759                 :            : {
     760                 :         56 :     return &ifa->address.address4;
     761                 :            : }
     762                 :            : 
     763                 :         10 : JL_DLLEXPORT int jl_getaddrinfo(uv_loop_t *loop, uv_getaddrinfo_t *req,
     764                 :            :         const char *host, const char *service, uv_getaddrinfo_cb uvcb)
     765                 :            : {
     766                 :            :     struct addrinfo hints;
     767                 :         10 :     memset(&hints, 0, sizeof(hints));
     768                 :         10 :     hints.ai_family = PF_UNSPEC;
     769                 :         10 :     hints.ai_socktype = SOCK_STREAM;
     770                 :         10 :     hints.ai_flags |= AI_CANONNAME;
     771                 :            : 
     772                 :         10 :     req->data = NULL;
     773                 :         10 :     return uv_getaddrinfo(loop, req, uvcb, host, service, &hints);
     774                 :            : }
     775                 :            : 
     776                 :         24 : JL_DLLEXPORT int jl_getnameinfo(uv_loop_t *loop, uv_getnameinfo_t *req,
     777                 :            :         void *host, uint16_t port, int flags, uv_getnameinfo_cb uvcb, int ipv6)
     778                 :            : {
     779                 :            :     uv_sockaddr_in addr;
     780                 :         24 :     jl_sockaddr_fill(&addr, port, host, ipv6);
     781                 :         24 :     return uv_getnameinfo(loop, req, uvcb, (struct sockaddr*)&addr, flags);
     782                 :            : }
     783                 :            : 
     784                 :         15 : JL_DLLEXPORT struct sockaddr *jl_sockaddr_from_addrinfo(struct addrinfo *addrinfo)
     785                 :            : {
     786                 :         15 :     return addrinfo->ai_addr;
     787                 :            : }
     788                 :            : 
     789                 :         15 : JL_DLLEXPORT struct addrinfo *jl_next_from_addrinfo(struct addrinfo *addrinfo)
     790                 :            : {
     791                 :         15 :     return addrinfo->ai_next;
     792                 :            : }
     793                 :            : 
     794                 :        101 : JL_DLLEXPORT int jl_sockaddr_is_ip4(struct sockaddr *addr)
     795                 :            : {
     796                 :        101 :     return (addr->sa_family == AF_INET);
     797                 :            : }
     798                 :            : 
     799                 :         24 : JL_DLLEXPORT int jl_sockaddr_is_ip6(struct sockaddr *addr)
     800                 :            : {
     801                 :         24 :     return (addr->sa_family == AF_INET6);
     802                 :            : }
     803                 :            : 
     804                 :         68 : JL_DLLEXPORT uint32_t jl_sockaddr_host4(struct sockaddr_in *addr)
     805                 :            : {
     806                 :         68 :     return addr->sin_addr.s_addr;
     807                 :            : }
     808                 :            : 
     809                 :         19 : JL_DLLEXPORT unsigned jl_sockaddr_host6(struct sockaddr_in6 *addr, char *host)
     810                 :            : {
     811                 :         19 :     memcpy(host, &addr->sin6_addr, 16);
     812                 :         19 :     return addr->sin6_scope_id;
     813                 :            : }
     814                 :            : 
     815                 :         35 : JL_DLLEXPORT uint16_t jl_sockaddr_port4(struct sockaddr_in *addr)
     816                 :            : {
     817                 :         35 :     return addr->sin_port;
     818                 :            : }
     819                 :            : 
     820                 :          5 : JL_DLLEXPORT uint16_t jl_sockaddr_port6(struct sockaddr_in6 *addr)
     821                 :            : {
     822                 :          5 :     return addr->sin6_port;
     823                 :            : }
     824                 :            : 
     825                 :            : 
     826                 :          0 : JL_DLLEXPORT void jl_sockaddr_set_port(uv_sockaddr_in *addr, uint16_t port)
     827                 :            : {
     828         [ #  # ]:          0 :     if (addr->in.sa_family == AF_INET)
     829                 :          0 :         addr->v4.sin_port = port;
     830                 :            :     else
     831                 :          0 :         addr->v6.sin6_port = port;
     832                 :          0 : }
     833                 :            : 
     834                 :        593 : JL_DLLEXPORT int jl_tcp_connect(uv_tcp_t *handle, void *host, uint16_t port,
     835                 :            :                                 uv_connect_cb cb, int ipv6)
     836                 :            : {
     837                 :            :     uv_sockaddr_in addr;
     838                 :        593 :     jl_sockaddr_fill(&addr, port, host, ipv6);
     839                 :        593 :     uv_connect_t *req = (uv_connect_t*)malloc_s(sizeof(uv_connect_t));
     840                 :        593 :     req->data = NULL;
     841                 :        593 :     int r = uv_tcp_connect(req, handle, &addr.in, cb);
     842         [ -  + ]:        593 :     if (r)
     843                 :          0 :         free(req);
     844                 :        593 :     return r;
     845                 :            : }
     846                 :            : 
     847                 :            : #ifdef _OS_LINUX_
     848                 :        375 : JL_DLLEXPORT int jl_tcp_quickack(uv_tcp_t *handle, int on)
     849                 :            : {
     850                 :        375 :     int fd = (handle)->io_watcher.fd;
     851         [ +  - ]:        375 :     if (fd != -1) {
     852         [ -  + ]:        375 :         if (setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &on, sizeof(on))) {
     853                 :          0 :             return -1;
     854                 :            :         }
     855                 :            :     }
     856                 :        375 :     return 0;
     857                 :            : }
     858                 :            : 
     859                 :            : #endif
     860                 :            : 
     861                 :        148 : JL_DLLEXPORT int jl_has_so_reuseport(void)
     862                 :            : {
     863                 :            : #if defined(SO_REUSEPORT) && !defined(_OS_DARWIN_)
     864                 :        148 :     return 1;
     865                 :            : #else
     866                 :            :     return 0;
     867                 :            : #endif
     868                 :            : }
     869                 :            : 
     870                 :        147 : JL_DLLEXPORT int jl_tcp_reuseport(uv_tcp_t *handle)
     871                 :            : {
     872                 :            : #if defined(SO_REUSEPORT)
     873                 :        147 :     int fd = (handle)->io_watcher.fd;
     874                 :        147 :     int yes = 1;
     875         [ -  + ]:        147 :     if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) {
     876                 :          0 :         return -1;
     877                 :            :     }
     878                 :        147 :     return 0;
     879                 :            : #else
     880                 :            :     return -1;
     881                 :            : #endif
     882                 :            : }
     883                 :            : 
     884                 :            : #ifndef _OS_WINDOWS_
     885                 :            : 
     886                 :        570 : JL_DLLEXPORT int jl_uv_unix_fd_is_watched(int fd, uv_poll_t *handle,
     887                 :            :                                           uv_loop_t *loop)
     888                 :            : {
     889                 :        570 :     JL_UV_LOCK();
     890         [ +  + ]:        570 :     if (fd >= loop->nwatchers) {
     891                 :         73 :         JL_UV_UNLOCK();
     892                 :         73 :         return 0;
     893                 :            :     }
     894         [ +  - ]:        497 :     if (loop->watchers[fd] == NULL) {
     895                 :        497 :         JL_UV_UNLOCK();
     896                 :        497 :         return 0;
     897                 :            :     }
     898   [ #  #  #  # ]:          0 :     if (handle && loop->watchers[fd] == &handle->io_watcher) {
     899                 :          0 :         JL_UV_UNLOCK();
     900                 :          0 :         return 0;
     901                 :            :     }
     902                 :          0 :     JL_UV_UNLOCK();
     903                 :          0 :     return 1;
     904                 :            : }
     905                 :            : 
     906                 :            : #endif
     907                 :            : 
     908                 :            : #ifdef _OS_WINDOWS_
     909                 :            : static inline int ishexchar(char c)
     910                 :            : {
     911                 :            :    if (c >= '0' && c <= '9') return 1;
     912                 :            :    if (c >= 'a' && c <= 'z') return 1;
     913                 :            :    return 0;
     914                 :            : }
     915                 :            : 
     916                 :            : JL_DLLEXPORT int jl_ispty(uv_pipe_t *pipe)
     917                 :            : {
     918                 :            :     if (pipe->type != UV_NAMED_PIPE) return 0;
     919                 :            :     size_t len = 0;
     920                 :            :     if (uv_pipe_getpeername(pipe, NULL, &len) != UV_ENOBUFS) return 0;
     921                 :            :     char *name = (char*)alloca(len + 1);
     922                 :            :     if (uv_pipe_getpeername(pipe, name, &len)) return 0;
     923                 :            :     name[len] = '\0';
     924                 :            :     // return true if name matches regex:
     925                 :            :     // ^\\\\?\\pipe\\(msys|cygwin)-[0-9a-z]{16}-[pt]ty[1-9][0-9]*-
     926                 :            :     //jl_printf(JL_STDERR,"pipe_name: %s\n", name);
     927                 :            :     int n = 0;
     928                 :            :     if (!strncmp(name,"\\\\?\\pipe\\msys-",14))
     929                 :            :         n = 14;
     930                 :            :     else if (!strncmp(name,"\\\\?\\pipe\\cygwin-",16))
     931                 :            :         n = 16;
     932                 :            :     else
     933                 :            :         return 0;
     934                 :            :     //jl_printf(JL_STDERR,"prefix pass\n");
     935                 :            :     name += n;
     936                 :            :     for (int n = 0; n < 16; n++)
     937                 :            :         if (!ishexchar(*name++)) return 0;
     938                 :            :     //jl_printf(JL_STDERR,"hex pass\n");
     939                 :            :     if ((*name++)!='-') return 0;
     940                 :            :     if (*name != 'p' && *name != 't') return 0;
     941                 :            :     name++;
     942                 :            :     if (*name++ != 't' || *name++ != 'y') return 0;
     943                 :            :     //jl_printf(JL_STDERR,"tty pass\n");
     944                 :            :     return 1;
     945                 :            : }
     946                 :            : #endif
     947                 :            : 
     948                 :       1692 : JL_DLLEXPORT uv_handle_type jl_uv_handle_type(uv_handle_t *handle)
     949                 :            : {
     950                 :            : #ifdef _OS_WINDOWS_
     951                 :            :     if (jl_ispty((uv_pipe_t*)handle))
     952                 :            :         return UV_TTY;
     953                 :            : #endif
     954                 :       1692 :     return handle->type;
     955                 :            : }
     956                 :            : 
     957                 :        114 : JL_DLLEXPORT int jl_tty_set_mode(uv_tty_t *handle, int mode)
     958                 :            : {
     959         [ -  + ]:        114 :     if (handle->type != UV_TTY) return 0;
     960                 :        114 :     uv_tty_mode_t mode_enum = UV_TTY_MODE_NORMAL;
     961         [ +  + ]:        114 :     if (mode)
     962                 :         42 :         mode_enum = UV_TTY_MODE_RAW;
     963                 :            :     // TODO: do we need lock?
     964                 :        114 :     return uv_tty_set_mode(handle, mode_enum);
     965                 :            : }
     966                 :            : 
     967                 :            : typedef int (*work_cb_t)(void *, void *, void *);
     968                 :            : typedef void (*notify_cb_t)(int);
     969                 :            : 
     970                 :            : struct work_baton {
     971                 :            :     uv_work_t req;
     972                 :            :     work_cb_t work_func;
     973                 :            :     void      *ccall_fptr;
     974                 :            :     void      *work_args;
     975                 :            :     void      *work_retval;
     976                 :            :     notify_cb_t notify_func;
     977                 :            :     int       notify_idx;
     978                 :            : };
     979                 :            : 
     980                 :            : #ifdef _OS_LINUX_
     981                 :            : #include <sys/syscall.h>
     982                 :            : #endif
     983                 :            : 
     984                 :       1028 : void jl_work_wrapper(uv_work_t *req)
     985                 :            : {
     986                 :       1028 :     struct work_baton *baton = (struct work_baton*) req->data;
     987                 :       1028 :     baton->work_func(baton->ccall_fptr, baton->work_args, baton->work_retval);
     988                 :       1028 : }
     989                 :            : 
     990                 :       1028 : void jl_work_notifier(uv_work_t *req, int status)
     991                 :            : {
     992                 :       1028 :     struct work_baton *baton = (struct work_baton*) req->data;
     993                 :       1028 :     baton->notify_func(baton->notify_idx);
     994                 :       1028 :     free(baton);
     995                 :       1028 : }
     996                 :            : 
     997                 :       1028 : JL_DLLEXPORT int jl_queue_work(work_cb_t work_func, void *ccall_fptr, void *work_args, void *work_retval,
     998                 :            :                                notify_cb_t notify_func, int notify_idx)
     999                 :            : {
    1000                 :       1028 :     struct work_baton *baton = (struct work_baton*)malloc_s(sizeof(struct work_baton));
    1001                 :       1028 :     baton->req.data = (void*) baton;
    1002                 :       1028 :     baton->work_func = work_func;
    1003                 :       1028 :     baton->ccall_fptr = ccall_fptr;
    1004                 :       1028 :     baton->work_args = work_args;
    1005                 :       1028 :     baton->work_retval = work_retval;
    1006                 :       1028 :     baton->notify_func = notify_func;
    1007                 :       1028 :     baton->notify_idx = notify_idx;
    1008                 :            : 
    1009                 :       1028 :     JL_UV_LOCK();
    1010                 :       1028 :     uv_queue_work(jl_io_loop, &baton->req, jl_work_wrapper, jl_work_notifier);
    1011                 :       1028 :     JL_UV_UNLOCK();
    1012                 :            : 
    1013                 :       1028 :     return 0;
    1014                 :            : }
    1015                 :            : 
    1016                 :            : #ifndef _OS_WINDOWS_
    1017                 :            : #if defined(__APPLE__)
    1018                 :            : int uv___stream_fd(uv_stream_t *handle);
    1019                 :            : #define uv__stream_fd(handle) (uv___stream_fd((uv_stream_t*)(handle)))
    1020                 :            : #else
    1021                 :            : #define uv__stream_fd(handle) ((handle)->io_watcher.fd)
    1022                 :            : #endif /* defined(__APPLE__) */
    1023                 :          0 : JL_DLLEXPORT int jl_uv_handle(uv_stream_t *handle)
    1024                 :            : {
    1025                 :          0 :     return uv__stream_fd(handle);
    1026                 :            : }
    1027                 :            : #else
    1028                 :            : JL_DLLEXPORT HANDLE jl_uv_handle(uv_stream_t *handle)
    1029                 :            : {
    1030                 :            :     switch (handle->type) {
    1031                 :            :     case UV_TTY:
    1032                 :            :         return ((uv_tty_t*)handle)->handle;
    1033                 :            :     case UV_NAMED_PIPE:
    1034                 :            :         return ((uv_pipe_t*)handle)->handle;
    1035                 :            :     default:
    1036                 :            :         return INVALID_HANDLE_VALUE;
    1037                 :            :     }
    1038                 :            : }
    1039                 :            : #endif
    1040                 :            : 
    1041                 :            : #ifdef __cplusplus
    1042                 :            : }
    1043                 :            : #endif

Generated by: LCOV version 1.14