11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 21cb0ef41Sopenharmony_ci * 31cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 41cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 51cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the 61cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 71cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 81cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions: 91cb0ef41Sopenharmony_ci * 101cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 111cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software. 121cb0ef41Sopenharmony_ci * 131cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 141cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 151cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 161cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 171cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 181cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 191cb0ef41Sopenharmony_ci * IN THE SOFTWARE. 201cb0ef41Sopenharmony_ci */ 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#include "uv.h" 231cb0ef41Sopenharmony_ci#include "uv-common.h" 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci#ifdef _WIN32 261cb0ef41Sopenharmony_ci#include "win/internal.h" 271cb0ef41Sopenharmony_ci#include "win/handle-inl.h" 281cb0ef41Sopenharmony_ci#define uv__make_close_pending(h) uv__want_endgame((h)->loop, (h)) 291cb0ef41Sopenharmony_ci#else 301cb0ef41Sopenharmony_ci#include "unix/internal.h" 311cb0ef41Sopenharmony_ci#endif 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci#include <assert.h> 341cb0ef41Sopenharmony_ci#include <stdlib.h> 351cb0ef41Sopenharmony_ci#include <string.h> 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_cistruct poll_ctx { 381cb0ef41Sopenharmony_ci uv_fs_poll_t* parent_handle; 391cb0ef41Sopenharmony_ci int busy_polling; 401cb0ef41Sopenharmony_ci unsigned int interval; 411cb0ef41Sopenharmony_ci uint64_t start_time; 421cb0ef41Sopenharmony_ci uv_loop_t* loop; 431cb0ef41Sopenharmony_ci uv_fs_poll_cb poll_cb; 441cb0ef41Sopenharmony_ci uv_timer_t timer_handle; 451cb0ef41Sopenharmony_ci uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ 461cb0ef41Sopenharmony_ci uv_stat_t statbuf; 471cb0ef41Sopenharmony_ci struct poll_ctx* previous; /* context from previous start()..stop() period */ 481cb0ef41Sopenharmony_ci char path[1]; /* variable length */ 491cb0ef41Sopenharmony_ci}; 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_cistatic int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); 521cb0ef41Sopenharmony_cistatic void poll_cb(uv_fs_t* req); 531cb0ef41Sopenharmony_cistatic void timer_cb(uv_timer_t* timer); 541cb0ef41Sopenharmony_cistatic void timer_close_cb(uv_handle_t* handle); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_cistatic uv_stat_t zero_statbuf; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciint uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { 601cb0ef41Sopenharmony_ci uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); 611cb0ef41Sopenharmony_ci handle->poll_ctx = NULL; 621cb0ef41Sopenharmony_ci return 0; 631cb0ef41Sopenharmony_ci} 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ciint uv_fs_poll_start(uv_fs_poll_t* handle, 671cb0ef41Sopenharmony_ci uv_fs_poll_cb cb, 681cb0ef41Sopenharmony_ci const char* path, 691cb0ef41Sopenharmony_ci unsigned int interval) { 701cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 711cb0ef41Sopenharmony_ci uv_loop_t* loop; 721cb0ef41Sopenharmony_ci size_t len; 731cb0ef41Sopenharmony_ci int err; 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci if (uv_is_active((uv_handle_t*)handle)) 761cb0ef41Sopenharmony_ci return 0; 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci loop = handle->loop; 791cb0ef41Sopenharmony_ci len = strlen(path); 801cb0ef41Sopenharmony_ci ctx = uv__calloc(1, sizeof(*ctx) + len); 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci if (ctx == NULL) 831cb0ef41Sopenharmony_ci return UV_ENOMEM; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci ctx->loop = loop; 861cb0ef41Sopenharmony_ci ctx->poll_cb = cb; 871cb0ef41Sopenharmony_ci ctx->interval = interval ? interval : 1; 881cb0ef41Sopenharmony_ci ctx->start_time = uv_now(loop); 891cb0ef41Sopenharmony_ci ctx->parent_handle = handle; 901cb0ef41Sopenharmony_ci memcpy(ctx->path, path, len + 1); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci err = uv_timer_init(loop, &ctx->timer_handle); 931cb0ef41Sopenharmony_ci if (err < 0) 941cb0ef41Sopenharmony_ci goto error; 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci ctx->timer_handle.flags |= UV_HANDLE_INTERNAL; 971cb0ef41Sopenharmony_ci uv__handle_unref(&ctx->timer_handle); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); 1001cb0ef41Sopenharmony_ci if (err < 0) 1011cb0ef41Sopenharmony_ci goto error; 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci if (handle->poll_ctx != NULL) 1041cb0ef41Sopenharmony_ci ctx->previous = handle->poll_ctx; 1051cb0ef41Sopenharmony_ci handle->poll_ctx = ctx; 1061cb0ef41Sopenharmony_ci uv__handle_start(handle); 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci return 0; 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_cierror: 1111cb0ef41Sopenharmony_ci uv__free(ctx); 1121cb0ef41Sopenharmony_ci return err; 1131cb0ef41Sopenharmony_ci} 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ciint uv_fs_poll_stop(uv_fs_poll_t* handle) { 1171cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci if (!uv_is_active((uv_handle_t*)handle)) 1201cb0ef41Sopenharmony_ci return 0; 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci ctx = handle->poll_ctx; 1231cb0ef41Sopenharmony_ci assert(ctx != NULL); 1241cb0ef41Sopenharmony_ci assert(ctx->parent_handle == handle); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci /* Close the timer if it's active. If it's inactive, there's a stat request 1271cb0ef41Sopenharmony_ci * in progress and poll_cb will take care of the cleanup. 1281cb0ef41Sopenharmony_ci */ 1291cb0ef41Sopenharmony_ci if (uv_is_active((uv_handle_t*)&ctx->timer_handle)) 1301cb0ef41Sopenharmony_ci uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci uv__handle_stop(handle); 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci return 0; 1351cb0ef41Sopenharmony_ci} 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ciint uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { 1391cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 1401cb0ef41Sopenharmony_ci size_t required_len; 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci if (!uv_is_active((uv_handle_t*)handle)) { 1431cb0ef41Sopenharmony_ci *size = 0; 1441cb0ef41Sopenharmony_ci return UV_EINVAL; 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci ctx = handle->poll_ctx; 1481cb0ef41Sopenharmony_ci assert(ctx != NULL); 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci required_len = strlen(ctx->path); 1511cb0ef41Sopenharmony_ci if (required_len >= *size) { 1521cb0ef41Sopenharmony_ci *size = required_len + 1; 1531cb0ef41Sopenharmony_ci return UV_ENOBUFS; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci memcpy(buffer, ctx->path, required_len); 1571cb0ef41Sopenharmony_ci *size = required_len; 1581cb0ef41Sopenharmony_ci buffer[required_len] = '\0'; 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci return 0; 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_civoid uv__fs_poll_close(uv_fs_poll_t* handle) { 1651cb0ef41Sopenharmony_ci uv_fs_poll_stop(handle); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci if (handle->poll_ctx == NULL) 1681cb0ef41Sopenharmony_ci uv__make_close_pending((uv_handle_t*)handle); 1691cb0ef41Sopenharmony_ci} 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_cistatic void timer_cb(uv_timer_t* timer) { 1731cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci ctx = container_of(timer, struct poll_ctx, timer_handle); 1761cb0ef41Sopenharmony_ci assert(ctx->parent_handle != NULL); 1771cb0ef41Sopenharmony_ci assert(ctx->parent_handle->poll_ctx == ctx); 1781cb0ef41Sopenharmony_ci ctx->start_time = uv_now(ctx->loop); 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb)) 1811cb0ef41Sopenharmony_ci abort(); 1821cb0ef41Sopenharmony_ci} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_cistatic void poll_cb(uv_fs_t* req) { 1861cb0ef41Sopenharmony_ci uv_stat_t* statbuf; 1871cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 1881cb0ef41Sopenharmony_ci uint64_t interval; 1891cb0ef41Sopenharmony_ci uv_fs_poll_t* handle; 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci ctx = container_of(req, struct poll_ctx, fs_req); 1921cb0ef41Sopenharmony_ci handle = ctx->parent_handle; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) 1951cb0ef41Sopenharmony_ci goto out; 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci if (req->result != 0) { 1981cb0ef41Sopenharmony_ci if (ctx->busy_polling != req->result) { 1991cb0ef41Sopenharmony_ci ctx->poll_cb(ctx->parent_handle, 2001cb0ef41Sopenharmony_ci req->result, 2011cb0ef41Sopenharmony_ci &ctx->statbuf, 2021cb0ef41Sopenharmony_ci &zero_statbuf); 2031cb0ef41Sopenharmony_ci ctx->busy_polling = req->result; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci goto out; 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci statbuf = &req->statbuf; 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci if (ctx->busy_polling != 0) 2111cb0ef41Sopenharmony_ci if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf)) 2121cb0ef41Sopenharmony_ci ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci ctx->statbuf = *statbuf; 2151cb0ef41Sopenharmony_ci ctx->busy_polling = 1; 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ciout: 2181cb0ef41Sopenharmony_ci uv_fs_req_cleanup(req); 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) { 2211cb0ef41Sopenharmony_ci uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); 2221cb0ef41Sopenharmony_ci return; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci /* Reschedule timer, subtract the delay from doing the stat(). */ 2261cb0ef41Sopenharmony_ci interval = ctx->interval; 2271cb0ef41Sopenharmony_ci interval -= (uv_now(ctx->loop) - ctx->start_time) % interval; 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0)) 2301cb0ef41Sopenharmony_ci abort(); 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_cistatic void timer_close_cb(uv_handle_t* timer) { 2351cb0ef41Sopenharmony_ci struct poll_ctx* ctx; 2361cb0ef41Sopenharmony_ci struct poll_ctx* it; 2371cb0ef41Sopenharmony_ci struct poll_ctx* last; 2381cb0ef41Sopenharmony_ci uv_fs_poll_t* handle; 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci ctx = container_of(timer, struct poll_ctx, timer_handle); 2411cb0ef41Sopenharmony_ci handle = ctx->parent_handle; 2421cb0ef41Sopenharmony_ci if (ctx == handle->poll_ctx) { 2431cb0ef41Sopenharmony_ci handle->poll_ctx = ctx->previous; 2441cb0ef41Sopenharmony_ci if (handle->poll_ctx == NULL && uv__is_closing(handle)) 2451cb0ef41Sopenharmony_ci uv__make_close_pending((uv_handle_t*)handle); 2461cb0ef41Sopenharmony_ci } else { 2471cb0ef41Sopenharmony_ci for (last = handle->poll_ctx, it = last->previous; 2481cb0ef41Sopenharmony_ci it != ctx; 2491cb0ef41Sopenharmony_ci last = it, it = it->previous) { 2501cb0ef41Sopenharmony_ci assert(last->previous != NULL); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci last->previous = ctx->previous; 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci uv__free(ctx); 2551cb0ef41Sopenharmony_ci} 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_cistatic int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { 2591cb0ef41Sopenharmony_ci return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec 2601cb0ef41Sopenharmony_ci && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec 2611cb0ef41Sopenharmony_ci && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec 2621cb0ef41Sopenharmony_ci && a->st_ctim.tv_sec == b->st_ctim.tv_sec 2631cb0ef41Sopenharmony_ci && a->st_mtim.tv_sec == b->st_mtim.tv_sec 2641cb0ef41Sopenharmony_ci && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec 2651cb0ef41Sopenharmony_ci && a->st_size == b->st_size 2661cb0ef41Sopenharmony_ci && a->st_mode == b->st_mode 2671cb0ef41Sopenharmony_ci && a->st_uid == b->st_uid 2681cb0ef41Sopenharmony_ci && a->st_gid == b->st_gid 2691cb0ef41Sopenharmony_ci && a->st_ino == b->st_ino 2701cb0ef41Sopenharmony_ci && a->st_dev == b->st_dev 2711cb0ef41Sopenharmony_ci && a->st_flags == b->st_flags 2721cb0ef41Sopenharmony_ci && a->st_gen == b->st_gen; 2731cb0ef41Sopenharmony_ci} 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci#if defined(_WIN32) 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci#include "win/internal.h" 2791cb0ef41Sopenharmony_ci#include "win/handle-inl.h" 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_civoid uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { 2821cb0ef41Sopenharmony_ci assert(handle->flags & UV_HANDLE_CLOSING); 2831cb0ef41Sopenharmony_ci assert(!(handle->flags & UV_HANDLE_CLOSED)); 2841cb0ef41Sopenharmony_ci uv__handle_close(handle); 2851cb0ef41Sopenharmony_ci} 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci#endif /* _WIN32 */ 288