1 /* $NetBSD: regress_iocp.c,v 1.4 2016/01/08 21:35:41 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdlib.h> 30 #include <string.h> 31 #include "event2/event.h" 32 #include "event2/thread.h" 33 #include "event2/buffer.h" 34 #include "event2/buffer_compat.h" 35 #include "event2/bufferevent.h" 36 37 #include <winsock2.h> 38 #include <ws2tcpip.h> 39 40 #include "regress.h" 41 #include "tinytest.h" 42 #include "tinytest_macros.h" 43 44 #define WIN32_LEAN_AND_MEAN 45 #include <windows.h> 46 #include <winsock2.h> 47 #undef WIN32_LEAN_AND_MEAN 48 49 #include "iocp-internal.h" 50 #include "evbuffer-internal.h" 51 #include "evthread-internal.h" 52 53 /* FIXME remove these ones */ 54 #include <sys/queue.h> 55 #include "event2/event_struct.h" 56 #include "event-internal.h" 57 58 #define MAX_CALLS 16 59 60 static void *count_lock = NULL, *count_cond = NULL; 61 static int count = 0; 62 63 static void 64 count_init(void) 65 { 66 EVTHREAD_ALLOC_LOCK(count_lock, 0); 67 EVTHREAD_ALLOC_COND(count_cond); 68 69 tt_assert(count_lock); 70 tt_assert(count_cond); 71 72 end: 73 ; 74 } 75 76 static void 77 count_free(void) 78 { 79 EVTHREAD_FREE_LOCK(count_lock, 0); 80 EVTHREAD_FREE_COND(count_cond); 81 } 82 83 static void 84 count_incr(void) 85 { 86 EVLOCK_LOCK(count_lock, 0); 87 count++; 88 EVTHREAD_COND_BROADCAST(count_cond); 89 EVLOCK_UNLOCK(count_lock, 0); 90 } 91 92 static int 93 count_wait_for(int i, int ms) 94 { 95 struct timeval tv; 96 DWORD elapsed; 97 int rv = -1; 98 99 EVLOCK_LOCK(count_lock, 0); 100 while (ms > 0 && count != i) { 101 tv.tv_sec = 0; 102 tv.tv_usec = ms * 1000; 103 elapsed = GetTickCount(); 104 EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv); 105 elapsed = GetTickCount() - elapsed; 106 ms -= elapsed; 107 } 108 if (count == i) 109 rv = 0; 110 EVLOCK_UNLOCK(count_lock, 0); 111 112 return rv; 113 } 114 115 struct dummy_overlapped { 116 struct event_overlapped eo; 117 void *lock; 118 int call_count; 119 uintptr_t keys[MAX_CALLS]; 120 ev_ssize_t sizes[MAX_CALLS]; 121 }; 122 123 static void 124 dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok) 125 { 126 struct dummy_overlapped *d_o = 127 EVUTIL_UPCAST(o, struct dummy_overlapped, eo); 128 129 EVLOCK_LOCK(d_o->lock, 0); 130 if (d_o->call_count < MAX_CALLS) { 131 d_o->keys[d_o->call_count] = key; 132 d_o->sizes[d_o->call_count] = n; 133 } 134 d_o->call_count++; 135 EVLOCK_UNLOCK(d_o->lock, 0); 136 137 count_incr(); 138 } 139 140 static int 141 pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n) 142 { 143 int i; 144 int result = 0; 145 EVLOCK_LOCK(o->lock, 0); 146 for (i=0; i < o->call_count; ++i) { 147 if (o->keys[i] == key && o->sizes[i] == n) { 148 result = 1; 149 break; 150 } 151 } 152 EVLOCK_UNLOCK(o->lock, 0); 153 return result; 154 } 155 156 static void 157 test_iocp_port(void *ptr) 158 { 159 struct event_iocp_port *port = NULL; 160 struct dummy_overlapped o1, o2; 161 162 memset(&o1, 0, sizeof(o1)); 163 memset(&o2, 0, sizeof(o2)); 164 165 count_init(); 166 EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 167 EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 168 169 tt_assert(o1.lock); 170 tt_assert(o2.lock); 171 172 event_overlapped_init_(&o1.eo, dummy_cb); 173 event_overlapped_init_(&o2.eo, dummy_cb); 174 175 port = event_iocp_port_launch_(0); 176 tt_assert(port); 177 178 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 10, 100)); 179 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 20, 200)); 180 181 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 11, 101)); 182 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 21, 201)); 183 184 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 12, 102)); 185 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 22, 202)); 186 187 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 13, 103)); 188 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 23, 203)); 189 190 tt_int_op(count_wait_for(8, 2000), ==, 0); 191 192 tt_want(!event_iocp_shutdown_(port, 2000)); 193 194 tt_int_op(o1.call_count, ==, 4); 195 tt_int_op(o2.call_count, ==, 4); 196 197 tt_want(pair_is_in(&o1, 10, 100)); 198 tt_want(pair_is_in(&o1, 11, 101)); 199 tt_want(pair_is_in(&o1, 12, 102)); 200 tt_want(pair_is_in(&o1, 13, 103)); 201 202 tt_want(pair_is_in(&o2, 20, 200)); 203 tt_want(pair_is_in(&o2, 21, 201)); 204 tt_want(pair_is_in(&o2, 22, 202)); 205 tt_want(pair_is_in(&o2, 23, 203)); 206 207 end: 208 EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 209 EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 210 count_free(); 211 } 212 213 static struct evbuffer *rbuf = NULL, *wbuf = NULL; 214 215 static void 216 read_complete(struct event_overlapped *eo, uintptr_t key, 217 ev_ssize_t nbytes, int ok) 218 { 219 tt_assert(ok); 220 evbuffer_commit_read_(rbuf, nbytes); 221 count_incr(); 222 end: 223 ; 224 } 225 226 static void 227 write_complete(struct event_overlapped *eo, uintptr_t key, 228 ev_ssize_t nbytes, int ok) 229 { 230 tt_assert(ok); 231 evbuffer_commit_write_(wbuf, nbytes); 232 count_incr(); 233 end: 234 ; 235 } 236 237 static void 238 test_iocp_evbuffer(void *ptr) 239 { 240 struct event_overlapped rol, wol; 241 struct basic_test_data *data = ptr; 242 struct event_iocp_port *port = NULL; 243 struct evbuffer *buf=NULL; 244 struct evbuffer_chain *chain; 245 char junk[1024]; 246 int i; 247 248 count_init(); 249 event_overlapped_init_(&rol, read_complete); 250 event_overlapped_init_(&wol, write_complete); 251 252 for (i = 0; i < (int)sizeof(junk); ++i) 253 junk[i] = (char)(i); 254 255 rbuf = evbuffer_overlapped_new_(data->pair[0]); 256 wbuf = evbuffer_overlapped_new_(data->pair[1]); 257 evbuffer_enable_locking(rbuf, NULL); 258 evbuffer_enable_locking(wbuf, NULL); 259 260 port = event_iocp_port_launch_(0); 261 tt_assert(port); 262 tt_assert(rbuf); 263 tt_assert(wbuf); 264 265 tt_assert(!event_iocp_port_associate_(port, data->pair[0], 100)); 266 tt_assert(!event_iocp_port_associate_(port, data->pair[1], 100)); 267 268 for (i=0;i<10;++i) 269 evbuffer_add(wbuf, junk, sizeof(junk)); 270 271 buf = evbuffer_new(); 272 tt_assert(buf != NULL); 273 evbuffer_add(rbuf, junk, sizeof(junk)); 274 tt_assert(!evbuffer_launch_read_(rbuf, 2048, &rol)); 275 evbuffer_add_buffer(buf, rbuf); 276 tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk)); 277 for (chain = buf->first; chain; chain = chain->next) 278 tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0); 279 tt_assert(!evbuffer_get_length(rbuf)); 280 tt_assert(!evbuffer_launch_write_(wbuf, 512, &wol)); 281 282 tt_int_op(count_wait_for(2, 2000), ==, 0); 283 284 tt_int_op(evbuffer_get_length(rbuf),==,512); 285 286 /* FIXME Actually test some stuff here. */ 287 288 tt_want(!event_iocp_shutdown_(port, 2000)); 289 end: 290 count_free(); 291 evbuffer_free(rbuf); 292 evbuffer_free(wbuf); 293 if (buf) evbuffer_free(buf); 294 } 295 296 static int got_readcb = 0; 297 298 static void 299 async_readcb(struct bufferevent *bev, void *arg) 300 { 301 /* Disabling read should cause the loop to quit */ 302 bufferevent_disable(bev, EV_READ); 303 got_readcb++; 304 } 305 306 static void 307 test_iocp_bufferevent_async(void *ptr) 308 { 309 struct basic_test_data *data = ptr; 310 struct event_iocp_port *port = NULL; 311 struct bufferevent *bea1=NULL, *bea2=NULL; 312 char buf[128]; 313 size_t n; 314 315 event_base_start_iocp_(data->base, 0); 316 port = event_base_get_iocp_(data->base); 317 tt_assert(port); 318 319 bea1 = bufferevent_async_new_(data->base, data->pair[0], 320 BEV_OPT_DEFER_CALLBACKS); 321 bea2 = bufferevent_async_new_(data->base, data->pair[1], 322 BEV_OPT_DEFER_CALLBACKS); 323 tt_assert(bea1); 324 tt_assert(bea2); 325 326 bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL); 327 bufferevent_enable(bea1, EV_WRITE); 328 bufferevent_enable(bea2, EV_READ); 329 330 bufferevent_write(bea1, "Hello world", strlen("Hello world")+1); 331 332 event_base_dispatch(data->base); 333 334 tt_int_op(got_readcb, ==, 1); 335 n = bufferevent_read(bea2, buf, sizeof(buf)-1); 336 buf[n]='\0'; 337 tt_str_op(buf, ==, "Hello world"); 338 339 end: 340 bufferevent_free(bea1); 341 bufferevent_free(bea2); 342 } 343 344 345 struct testcase_t iocp_testcases[] = { 346 { "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL }, 347 { "evbuffer", test_iocp_evbuffer, 348 TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS, 349 &basic_setup, NULL }, 350 { "bufferevent_async", test_iocp_bufferevent_async, 351 TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE, 352 &basic_setup, NULL }, 353 END_OF_TESTCASES 354 }; 355