11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 21cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 31cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 41cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the 51cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 61cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 71cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions: 81cb0ef41Sopenharmony_ci * 91cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 101cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software. 111cb0ef41Sopenharmony_ci * 121cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 131cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 141cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 151cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 161cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 171cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 181cb0ef41Sopenharmony_ci * IN THE SOFTWARE. 191cb0ef41Sopenharmony_ci */ 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci/* This file contains both the uv__async internal infrastructure and the 221cb0ef41Sopenharmony_ci * user-facing uv_async_t functions. 231cb0ef41Sopenharmony_ci */ 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci#include "uv.h" 261cb0ef41Sopenharmony_ci#include "internal.h" 271cb0ef41Sopenharmony_ci#include "atomic-ops.h" 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci#include <errno.h> 301cb0ef41Sopenharmony_ci#include <stdio.h> /* snprintf() */ 311cb0ef41Sopenharmony_ci#include <assert.h> 321cb0ef41Sopenharmony_ci#include <stdlib.h> 331cb0ef41Sopenharmony_ci#include <string.h> 341cb0ef41Sopenharmony_ci#include <unistd.h> 351cb0ef41Sopenharmony_ci#include <sched.h> /* sched_yield() */ 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci#ifdef __linux__ 381cb0ef41Sopenharmony_ci#include <sys/eventfd.h> 391cb0ef41Sopenharmony_ci#endif 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_cistatic void uv__async_send(uv_loop_t* loop); 421cb0ef41Sopenharmony_cistatic int uv__async_start(uv_loop_t* loop); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciint uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { 461cb0ef41Sopenharmony_ci int err; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci err = uv__async_start(loop); 491cb0ef41Sopenharmony_ci if (err) 501cb0ef41Sopenharmony_ci return err; 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); 531cb0ef41Sopenharmony_ci handle->async_cb = async_cb; 541cb0ef41Sopenharmony_ci handle->pending = 0; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); 571cb0ef41Sopenharmony_ci uv__handle_start(handle); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci return 0; 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ciint uv_async_send(uv_async_t* handle) { 641cb0ef41Sopenharmony_ci /* Do a cheap read first. */ 651cb0ef41Sopenharmony_ci if (ACCESS_ONCE(int, handle->pending) != 0) 661cb0ef41Sopenharmony_ci return 0; 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci /* Tell the other thread we're busy with the handle. */ 691cb0ef41Sopenharmony_ci if (cmpxchgi(&handle->pending, 0, 1) != 0) 701cb0ef41Sopenharmony_ci return 0; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci /* Wake up the other thread's event loop. */ 731cb0ef41Sopenharmony_ci uv__async_send(handle->loop); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci /* Tell the other thread we're done. */ 761cb0ef41Sopenharmony_ci if (cmpxchgi(&handle->pending, 1, 2) != 1) 771cb0ef41Sopenharmony_ci abort(); 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci return 0; 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci/* Only call this from the event loop thread. */ 841cb0ef41Sopenharmony_cistatic int uv__async_spin(uv_async_t* handle) { 851cb0ef41Sopenharmony_ci int i; 861cb0ef41Sopenharmony_ci int rc; 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci for (;;) { 891cb0ef41Sopenharmony_ci /* 997 is not completely chosen at random. It's a prime number, acyclical 901cb0ef41Sopenharmony_ci * by nature, and should therefore hopefully dampen sympathetic resonance. 911cb0ef41Sopenharmony_ci */ 921cb0ef41Sopenharmony_ci for (i = 0; i < 997; i++) { 931cb0ef41Sopenharmony_ci /* rc=0 -- handle is not pending. 941cb0ef41Sopenharmony_ci * rc=1 -- handle is pending, other thread is still working with it. 951cb0ef41Sopenharmony_ci * rc=2 -- handle is pending, other thread is done. 961cb0ef41Sopenharmony_ci */ 971cb0ef41Sopenharmony_ci rc = cmpxchgi(&handle->pending, 2, 0); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci if (rc != 1) 1001cb0ef41Sopenharmony_ci return rc; 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci /* Other thread is busy with this handle, spin until it's done. */ 1031cb0ef41Sopenharmony_ci cpu_relax(); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci /* Yield the CPU. We may have preempted the other thread while it's 1071cb0ef41Sopenharmony_ci * inside the critical section and if it's running on the same CPU 1081cb0ef41Sopenharmony_ci * as us, we'll just burn CPU cycles until the end of our time slice. 1091cb0ef41Sopenharmony_ci */ 1101cb0ef41Sopenharmony_ci sched_yield(); 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_civoid uv__async_close(uv_async_t* handle) { 1161cb0ef41Sopenharmony_ci uv__async_spin(handle); 1171cb0ef41Sopenharmony_ci QUEUE_REMOVE(&handle->queue); 1181cb0ef41Sopenharmony_ci uv__handle_stop(handle); 1191cb0ef41Sopenharmony_ci} 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_cistatic void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { 1231cb0ef41Sopenharmony_ci char buf[1024]; 1241cb0ef41Sopenharmony_ci ssize_t r; 1251cb0ef41Sopenharmony_ci QUEUE queue; 1261cb0ef41Sopenharmony_ci QUEUE* q; 1271cb0ef41Sopenharmony_ci uv_async_t* h; 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci assert(w == &loop->async_io_watcher); 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci for (;;) { 1321cb0ef41Sopenharmony_ci r = read(w->fd, buf, sizeof(buf)); 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci if (r == sizeof(buf)) 1351cb0ef41Sopenharmony_ci continue; 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci if (r != -1) 1381cb0ef41Sopenharmony_ci break; 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci if (errno == EAGAIN || errno == EWOULDBLOCK) 1411cb0ef41Sopenharmony_ci break; 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci if (errno == EINTR) 1441cb0ef41Sopenharmony_ci continue; 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci abort(); 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci QUEUE_MOVE(&loop->async_handles, &queue); 1501cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&queue)) { 1511cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&queue); 1521cb0ef41Sopenharmony_ci h = QUEUE_DATA(q, uv_async_t, queue); 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci QUEUE_REMOVE(q); 1551cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&loop->async_handles, q); 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci if (0 == uv__async_spin(h)) 1581cb0ef41Sopenharmony_ci continue; /* Not pending. */ 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci if (h->async_cb == NULL) 1611cb0ef41Sopenharmony_ci continue; 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci h->async_cb(h); 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci} 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_cistatic void uv__async_send(uv_loop_t* loop) { 1691cb0ef41Sopenharmony_ci const void* buf; 1701cb0ef41Sopenharmony_ci ssize_t len; 1711cb0ef41Sopenharmony_ci int fd; 1721cb0ef41Sopenharmony_ci int r; 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci buf = ""; 1751cb0ef41Sopenharmony_ci len = 1; 1761cb0ef41Sopenharmony_ci fd = loop->async_wfd; 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci#if defined(__linux__) 1791cb0ef41Sopenharmony_ci if (fd == -1) { 1801cb0ef41Sopenharmony_ci static const uint64_t val = 1; 1811cb0ef41Sopenharmony_ci buf = &val; 1821cb0ef41Sopenharmony_ci len = sizeof(val); 1831cb0ef41Sopenharmony_ci fd = loop->async_io_watcher.fd; /* eventfd */ 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci#endif 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci do 1881cb0ef41Sopenharmony_ci r = write(fd, buf, len); 1891cb0ef41Sopenharmony_ci while (r == -1 && errno == EINTR); 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci if (r == len) 1921cb0ef41Sopenharmony_ci return; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci if (r == -1) 1951cb0ef41Sopenharmony_ci if (errno == EAGAIN || errno == EWOULDBLOCK) 1961cb0ef41Sopenharmony_ci return; 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci abort(); 1991cb0ef41Sopenharmony_ci} 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_cistatic int uv__async_start(uv_loop_t* loop) { 2031cb0ef41Sopenharmony_ci int pipefd[2]; 2041cb0ef41Sopenharmony_ci int err; 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci if (loop->async_io_watcher.fd != -1) 2071cb0ef41Sopenharmony_ci return 0; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci#ifdef __linux__ 2101cb0ef41Sopenharmony_ci err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 2111cb0ef41Sopenharmony_ci if (err < 0) 2121cb0ef41Sopenharmony_ci return UV__ERR(errno); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci pipefd[0] = err; 2151cb0ef41Sopenharmony_ci pipefd[1] = -1; 2161cb0ef41Sopenharmony_ci#else 2171cb0ef41Sopenharmony_ci err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); 2181cb0ef41Sopenharmony_ci if (err < 0) 2191cb0ef41Sopenharmony_ci return err; 2201cb0ef41Sopenharmony_ci#endif 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); 2231cb0ef41Sopenharmony_ci uv__io_start(loop, &loop->async_io_watcher, POLLIN); 2241cb0ef41Sopenharmony_ci loop->async_wfd = pipefd[1]; 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci return 0; 2271cb0ef41Sopenharmony_ci} 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ciint uv__async_fork(uv_loop_t* loop) { 2311cb0ef41Sopenharmony_ci if (loop->async_io_watcher.fd == -1) /* never started */ 2321cb0ef41Sopenharmony_ci return 0; 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci uv__async_stop(loop); 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci return uv__async_start(loop); 2371cb0ef41Sopenharmony_ci} 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_civoid uv__async_stop(uv_loop_t* loop) { 2411cb0ef41Sopenharmony_ci if (loop->async_io_watcher.fd == -1) 2421cb0ef41Sopenharmony_ci return; 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci if (loop->async_wfd != -1) { 2451cb0ef41Sopenharmony_ci if (loop->async_wfd != loop->async_io_watcher.fd) 2461cb0ef41Sopenharmony_ci uv__close(loop->async_wfd); 2471cb0ef41Sopenharmony_ci loop->async_wfd = -1; 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci uv__io_stop(loop, &loop->async_io_watcher, POLLIN); 2511cb0ef41Sopenharmony_ci uv__close(loop->async_io_watcher.fd); 2521cb0ef41Sopenharmony_ci loop->async_io_watcher.fd = -1; 2531cb0ef41Sopenharmony_ci} 254