1/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl> 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16#include "uv.h" 17#include "task.h" 18 19#include <string.h> /* memset */ 20#ifndef _WIN32 21#include <unistd.h> /* close */ 22#endif 23 24struct thread_ctx { 25 uv_barrier_t barrier; 26 uv_file fd; 27}; 28 29static void thread_main(void* arg) { 30 struct thread_ctx* ctx; 31 uv_fs_t req; 32 uv_buf_t bufs[1]; 33 char buf[4096]; 34 ssize_t n; 35 int uv_errno; 36 37 bufs[0] = uv_buf_init(buf, sizeof(buf)); 38 39 ctx = arg; 40 uv_barrier_wait(&ctx->barrier); 41 42 uv_sleep(100); /* make sure we are forcing the writer to block a bit */ 43 do { 44 uv_errno = uv_fs_read(NULL, &req, ctx->fd, bufs, 1, -1, NULL); 45 n = req.result; 46 uv_fs_req_cleanup(&req); 47 } while (n > 0 || (n == -1 && uv_errno == UV_EINTR)); 48 49 ASSERT_OK(n); 50} 51 52 53#ifdef _WIN32 54static void write_cb(uv_write_t* req, int status) { 55 ASSERT_OK(status); 56 req->handle = NULL; /* signal completion of write_cb */ 57} 58#endif 59 60#ifdef _WIN32 61#define NWRITES (10 << 16) 62#else 63#define NWRITES (10 << 20) 64#endif 65 66 67TEST_IMPL(pipe_set_non_blocking) { 68 struct thread_ctx ctx; 69 uv_pipe_t pipe_handle; 70 uv_thread_t thread; 71 size_t nwritten; 72 char data[4096]; 73 uv_buf_t buf; 74 uv_file fd[2]; 75 int n; 76#ifdef _WIN32 77 uv_write_t write_req; 78#endif 79 80 ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); 81 ASSERT_OK(uv_pipe(fd, 0, 0)); 82 ASSERT_OK(uv_pipe_open(&pipe_handle, fd[1])); 83 ASSERT_OK(uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1)); 84 fd[1] = -1; /* fd[1] is owned by pipe_handle now. */ 85 86 ctx.fd = fd[0]; 87 ASSERT_OK(uv_barrier_init(&ctx.barrier, 2)); 88 ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx)); 89 uv_barrier_wait(&ctx.barrier); 90 91 buf.len = sizeof(data); 92 buf.base = data; 93 memset(data, '.', sizeof(data)); 94 95 nwritten = 0; 96 while (nwritten < NWRITES) { 97 /* The stream is in blocking mode so uv_try_write() should always succeed 98 * with the exact number of bytes that we wanted written. 99 */ 100 n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1); 101#ifdef _WIN32 102 ASSERT_EQ(n, UV_EAGAIN); /* E_NOTIMPL */ 103 ASSERT_OK(uv_write(&write_req, 104 (uv_stream_t*) &pipe_handle, 105 &buf, 106 1, 107 write_cb)); 108 ASSERT_NOT_NULL(write_req.handle); 109 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); 110 ASSERT_NULL(write_req.handle); /* check for signaled completion of write_cb */ 111 n = buf.len; 112#endif 113 ASSERT_EQ(n, sizeof(data)); 114 nwritten += n; 115 } 116 117 uv_close((uv_handle_t*) &pipe_handle, NULL); 118 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); 119 120 ASSERT_OK(uv_thread_join(&thread)); 121#ifdef _WIN32 122 ASSERT_OK(_close(fd[0])); /* fd[1] is closed by uv_close(). */ 123#else 124 ASSERT_OK(close(fd[0])); /* fd[1] is closed by uv_close(). */ 125#endif 126 fd[0] = -1; 127 uv_barrier_destroy(&ctx.barrier); 128 129 MAKE_VALGRIND_HAPPY(uv_default_loop()); 130 return 0; 131} 132