1 /* Copyright libuv project contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "task.h"
23 #include "uv.h"
24 
25 #include <string.h>
26 
27 /* See test-ipc.c */
28 void spawn_helper(uv_pipe_t* channel,
29                   uv_process_t* process,
30                   const char* helper);
31 
32 #define NUM_WRITES 256
33 #define BUFFERS_PER_WRITE 3
34 #define BUFFER_SIZE 0x2000 /* 8 kb. */
35 #define BUFFER_CONTENT 42
36 
37 #define XFER_SIZE (NUM_WRITES * BUFFERS_PER_WRITE * BUFFER_SIZE)
38 
39 struct write_info {
40   uv_write_t write_req;
41   char buffers[BUFFER_SIZE][BUFFERS_PER_WRITE];
42 };
43 
44 static uv_shutdown_t shutdown_req;
45 
46 static size_t bytes_written;
47 static size_t bytes_read;
48 
write_cb(uv_write_t * req,int status)49 static void write_cb(uv_write_t* req, int status) {
50   struct write_info* write_info =
51       container_of(req, struct write_info, write_req);
52   ASSERT_OK(status);
53   bytes_written += BUFFERS_PER_WRITE * BUFFER_SIZE;
54   free(write_info);
55 }
56 
shutdown_cb(uv_shutdown_t * req,int status)57 static void shutdown_cb(uv_shutdown_t* req, int status) {
58   ASSERT(status == 0 || status == UV_ENOTCONN);
59   uv_close((uv_handle_t*) req->handle, NULL);
60 }
61 
do_write(uv_stream_t * handle)62 static void do_write(uv_stream_t* handle) {
63   struct write_info* write_info;
64   uv_buf_t bufs[BUFFERS_PER_WRITE];
65   size_t i;
66   int r;
67 
68   write_info = malloc(sizeof *write_info);
69   ASSERT_NOT_NULL(write_info);
70 
71   for (i = 0; i < BUFFERS_PER_WRITE; i++) {
72     memset(&write_info->buffers[i], BUFFER_CONTENT, BUFFER_SIZE);
73     bufs[i] = uv_buf_init(write_info->buffers[i], BUFFER_SIZE);
74   }
75 
76   r = uv_write(
77       &write_info->write_req, handle, bufs, BUFFERS_PER_WRITE, write_cb);
78   ASSERT_OK(r);
79 }
80 
alloc_cb(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)81 static void alloc_cb(uv_handle_t* handle,
82                      size_t suggested_size,
83                      uv_buf_t* buf) {
84   buf->base = malloc(suggested_size);
85   buf->len = (int) suggested_size;
86 }
87 
88 #ifndef _WIN32
89 #include <sys/types.h>
90 #include <unistd.h>
91 #endif
92 
read_cb(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)93 static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
94   ssize_t i;
95   int r;
96 
97   ASSERT_GE(nread, 0);
98   bytes_read += nread;
99 
100   for (i = 0; i < nread; i++)
101     ASSERT_EQ(buf->base[i], BUFFER_CONTENT);
102   free(buf->base);
103 
104   if (bytes_read >= XFER_SIZE) {
105     r = uv_read_stop(handle);
106     ASSERT_OK(r);
107     r = uv_shutdown(&shutdown_req, handle, shutdown_cb);
108     ASSERT_OK(r);
109   }
110 }
111 
do_writes_and_reads(uv_stream_t * handle)112 static void do_writes_and_reads(uv_stream_t* handle) {
113   size_t i;
114   int r;
115 
116   bytes_written = 0;
117   bytes_read = 0;
118 
119   for (i = 0; i < NUM_WRITES; i++) {
120     do_write(handle);
121   }
122 
123   r = uv_read_start(handle, alloc_cb, read_cb);
124   ASSERT_OK(r);
125 
126   r = uv_run(handle->loop, UV_RUN_DEFAULT);
127   ASSERT_OK(r);
128 
129   ASSERT_EQ(bytes_written, XFER_SIZE);
130   ASSERT_EQ(bytes_read, XFER_SIZE);
131 }
132 
TEST_IMPL(ipc_heavy_traffic_deadlock_bug)133 TEST_IMPL(ipc_heavy_traffic_deadlock_bug) {
134   uv_pipe_t pipe;
135   uv_process_t process;
136 
137   spawn_helper(&pipe, &process, "ipc_helper_heavy_traffic_deadlock_bug");
138   do_writes_and_reads((uv_stream_t*) &pipe);
139 
140   MAKE_VALGRIND_HAPPY(pipe.loop);
141   return 0;
142 }
143 
ipc_helper_heavy_traffic_deadlock_bug(void)144 int ipc_helper_heavy_traffic_deadlock_bug(void) {
145   uv_pipe_t pipe;
146   int r;
147 
148   r = uv_pipe_init(uv_default_loop(), &pipe, 1);
149   ASSERT_OK(r);
150   r = uv_pipe_open(&pipe, 0);
151   ASSERT_OK(r);
152 
153   notify_parent_process();
154   do_writes_and_reads((uv_stream_t*) &pipe);
155   uv_sleep(100);
156 
157   MAKE_VALGRIND_HAPPY(uv_default_loop());
158   return 0;
159 }
160