libuv-svace-build
221 строка · 5.1 Кб
1/* Copyright Joyent, Inc. and other Node 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 "uv.h"23#include "task.h"24
25#include <stdlib.h>26#include <stdio.h>27
28/* Run the benchmark for this many ms */
29#define TIME 500030
31
32typedef struct {33int pongs;34int state;35uv_tcp_t tcp;36uv_connect_t connect_req;37uv_shutdown_t shutdown_req;38} pinger_t;39
40typedef struct buf_s {41uv_buf_t uv_buf_t;42struct buf_s* next;43} buf_t;44
45
46static char PING[] = "PING\n";47
48static uv_loop_t* loop;49
50static buf_t* buf_freelist = NULL;51static int pinger_shutdown_cb_called;52static int completed_pingers = 0;53static int64_t start_time;54
55
56static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {57buf_t* ab;58
59ab = buf_freelist;60if (ab != NULL)61buf_freelist = ab->next;62else {63ab = malloc(size + sizeof(*ab));64ab->uv_buf_t.len = size;65ab->uv_buf_t.base = (char*) (ab + 1);66}67
68*buf = ab->uv_buf_t;69}
70
71
72static void buf_free(const uv_buf_t* buf) {73buf_t* ab = (buf_t*) buf->base - 1;74ab->next = buf_freelist;75buf_freelist = ab;76}
77
78
79static void pinger_close_cb(uv_handle_t* handle) {80pinger_t* pinger;81
82pinger = (pinger_t*)handle->data;83fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);84fflush(stderr);85
86free(pinger);87
88completed_pingers++;89}
90
91
92static void pinger_write_cb(uv_write_t* req, int status) {93ASSERT_OK(status);94
95free(req);96}
97
98
99static void pinger_write_ping(pinger_t* pinger) {100uv_write_t* req;101uv_buf_t buf;102
103buf = uv_buf_init(PING, sizeof(PING) - 1);104
105req = malloc(sizeof *req);106if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {107FATAL("uv_write failed");108}109}
110
111
112static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {113ASSERT_OK(status);114pinger_shutdown_cb_called++;115
116/*117* The close callback has not been triggered yet. We must wait for EOF
118* until we close the connection.
119*/
120ASSERT_OK(completed_pingers);121}
122
123
124static void pinger_read_cb(uv_stream_t* tcp,125ssize_t nread,126const uv_buf_t* buf) {127ssize_t i;128pinger_t* pinger;129
130pinger = (pinger_t*)tcp->data;131
132if (nread < 0) {133ASSERT_EQ(nread, UV_EOF);134
135if (buf->base) {136buf_free(buf);137}138
139ASSERT_EQ(1, pinger_shutdown_cb_called);140uv_close((uv_handle_t*)tcp, pinger_close_cb);141
142return;143}144
145/* Now we count the pings */146for (i = 0; i < nread; i++) {147ASSERT_EQ(buf->base[i], PING[pinger->state]);148pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);149if (pinger->state == 0) {150pinger->pongs++;151if (uv_now(loop) - start_time > TIME) {152uv_shutdown(&pinger->shutdown_req,153(uv_stream_t*) tcp,154pinger_shutdown_cb);155break;156} else {157pinger_write_ping(pinger);158}159}160}161
162buf_free(buf);163}
164
165
166static void pinger_connect_cb(uv_connect_t* req, int status) {167pinger_t *pinger = (pinger_t*)req->handle->data;168
169ASSERT_OK(status);170
171pinger_write_ping(pinger);172
173if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {174FATAL("uv_read_start failed");175}176}
177
178
179static void pinger_new(void) {180struct sockaddr_in client_addr;181struct sockaddr_in server_addr;182pinger_t *pinger;183int r;184
185ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &client_addr));186ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));187pinger = malloc(sizeof(*pinger));188pinger->state = 0;189pinger->pongs = 0;190
191/* Try to connect to the server and do NUM_PINGS ping-pongs. */192r = uv_tcp_init(loop, &pinger->tcp);193ASSERT(!r);194
195pinger->tcp.data = pinger;196
197ASSERT_OK(uv_tcp_bind(&pinger->tcp,198(const struct sockaddr*) &client_addr,1990));200
201r = uv_tcp_connect(&pinger->connect_req,202&pinger->tcp,203(const struct sockaddr*) &server_addr,204pinger_connect_cb);205ASSERT(!r);206}
207
208
209BENCHMARK_IMPL(ping_pongs) {210loop = uv_default_loop();211
212start_time = uv_now(loop);213
214pinger_new();215uv_run(loop, UV_RUN_DEFAULT);216
217ASSERT_EQ(1, completed_pingers);218
219MAKE_VALGRIND_HAPPY(loop);220return 0;221}
222