]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/util/winsock_event.c
38661a5e1a8b94ed96a42ce6c6fc9c125027e063
2 * util/winsock_event.c - implementation of the unbound winsock event handler.
4 * Copyright (c) 2008, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Implementation of the unbound WinSock2 API event notification handler
38 * for the Windows port.
48 #include "util/winsock_event.h"
49 #include "util/fptr_wlist.h"
51 int mini_ev_cmp(const void* a
, const void* b
)
53 const struct event
*e
= (const struct event
*)a
;
54 const struct event
*f
= (const struct event
*)b
;
55 if(e
->ev_timeout
.tv_sec
< f
->ev_timeout
.tv_sec
)
57 if(e
->ev_timeout
.tv_sec
> f
->ev_timeout
.tv_sec
)
59 if(e
->ev_timeout
.tv_usec
< f
->ev_timeout
.tv_usec
)
61 if(e
->ev_timeout
.tv_usec
> f
->ev_timeout
.tv_usec
)
72 settime(struct event_base
* base
)
74 if(gettimeofday(base
->time_tv
, NULL
) < 0) {
78 *base
->time_secs
= (time_t)base
->time_tv
->tv_sec
;
85 * Find a fd in the list of items.
86 * Note that not all items have a fd associated (those are -1).
87 * Signals are stored separately, and not searched.
88 * @param base: event base to look in.
89 * @param fd: what socket to look for.
90 * @return the index in the array, or -1 on failure.
93 find_fd(struct event_base
* base
, int fd
)
96 for(i
=0; i
<base
->max
; i
++) {
97 if(base
->items
[i
]->ev_fd
== fd
)
104 /** Find ptr in base array */
106 zero_waitfor(WSAEVENT waitfor
[], WSAEVENT x
)
109 for(i
=0; i
<WSK_MAX_ITEMS
; i
++) {
115 void *event_init(time_t* time_secs
, struct timeval
* time_tv
)
117 struct event_base
* base
= (struct event_base
*)malloc(
118 sizeof(struct event_base
));
121 memset(base
, 0, sizeof(*base
));
122 base
->time_secs
= time_secs
;
123 base
->time_tv
= time_tv
;
124 if(settime(base
) < 0) {
125 event_base_free(base
);
128 base
->items
= (struct event
**)calloc(WSK_MAX_ITEMS
,
129 sizeof(struct event
*));
131 event_base_free(base
);
134 base
->cap
= WSK_MAX_ITEMS
;
136 base
->times
= rbtree_create(mini_ev_cmp
);
138 event_base_free(base
);
141 base
->signals
= (struct event
**)calloc(MAX_SIG
, sizeof(struct event
*));
143 event_base_free(base
);
146 base
->tcp_stickies
= 0;
147 base
->tcp_reinvigorated
= 0;
148 verbose(VERB_CLIENT
, "winsock_event inited");
152 const char *event_get_version(void)
154 return "winsock-event-"PACKAGE_VERSION
;
157 const char *event_get_method(void)
159 return "WSAWaitForMultipleEvents";
162 /** call timeouts handlers, and return how long to wait for next one or -1 */
163 static void handle_timeouts(struct event_base
* base
, struct timeval
* now
,
164 struct timeval
* wait
)
168 wait
->tv_sec
= (time_t)-1;
170 verbose(VERB_CLIENT
, "winsock_event handle_timeouts");
172 while((rbnode_t
*)(p
= (struct event
*)rbtree_first(base
->times
))
175 if(p
->ev_timeout
.tv_sec
> now
->tv_sec
||
176 (p
->ev_timeout
.tv_sec
==now
->tv_sec
&&
177 p
->ev_timeout
.tv_usec
> now
->tv_usec
)) {
178 /* there is a next larger timeout. wait for it */
179 wait
->tv_sec
= p
->ev_timeout
.tv_sec
- now
->tv_sec
;
180 if(now
->tv_usec
> p
->ev_timeout
.tv_usec
) {
182 wait
->tv_usec
= 1000000 - (now
->tv_usec
-
183 p
->ev_timeout
.tv_usec
);
185 wait
->tv_usec
= p
->ev_timeout
.tv_usec
188 verbose(VERB_CLIENT
, "winsock_event wait=" ARG_LL
"d.%6.6d",
189 (long long)wait
->tv_sec
, (int)wait
->tv_usec
);
193 /* event times out, remove it */
194 (void)rbtree_delete(base
->times
, p
);
195 p
->ev_events
&= ~EV_TIMEOUT
;
196 fptr_ok(fptr_whitelist_event(p
->ev_callback
));
197 (*p
->ev_callback
)(p
->ev_fd
, EV_TIMEOUT
, p
->ev_arg
);
199 verbose(VERB_CLIENT
, "winsock_event wait=(-1)");
202 /** handle is_signal events and see if signalled */
203 static void handle_signal(struct event
* ev
)
206 log_assert(ev
->is_signal
&& ev
->hEvent
);
207 /* see if the event is signalled */
208 ret
= WSAWaitForMultipleEvents(1, &ev
->hEvent
, 0 /* any object */,
209 0 /* return immediately */, 0 /* not alertable for IOcomple*/);
210 if(ret
== WSA_WAIT_IO_COMPLETION
|| ret
== WSA_WAIT_FAILED
) {
211 log_err("WSAWaitForMultipleEvents(signal) failed: %s",
212 wsa_strerror(WSAGetLastError()));
215 if(ret
== WSA_WAIT_TIMEOUT
) {
220 /* reset the signal */
221 if(!WSAResetEvent(ev
->hEvent
))
222 log_err("WSAResetEvent failed: %s",
223 wsa_strerror(WSAGetLastError()));
224 /* do the callback (which may set the signal again) */
225 fptr_ok(fptr_whitelist_event(ev
->ev_callback
));
226 (*ev
->ev_callback
)(ev
->ev_fd
, ev
->ev_events
, ev
->ev_arg
);
229 /** call select and callbacks for that */
230 static int handle_select(struct event_base
* base
, struct timeval
* wait
)
232 DWORD timeout
= 0; /* in milliseconds */
234 struct event
* eventlist
[WSK_MAX_ITEMS
];
235 WSANETWORKEVENTS netev
;
236 int i
, numwait
= 0, startidx
= 0, was_timeout
= 0;
238 struct timeval nultm
;
240 verbose(VERB_CLIENT
, "winsock_event handle_select");
243 if(wait
->tv_sec
==(time_t)-1)
246 timeout
= wait
->tv_sec
*1000 + wait
->tv_usec
/1000;
247 if(base
->tcp_stickies
) {
251 timeout
= 0; /* no waiting, we have sticky events */
255 /* prepare event array */
256 for(i
=0; i
<base
->max
; i
++) {
257 if(base
->items
[i
]->ev_fd
== -1 && !base
->items
[i
]->is_signal
)
258 continue; /* skip timer only events */
259 eventlist
[numwait
] = base
->items
[i
];
260 base
->waitfor
[numwait
++] = base
->items
[i
]->hEvent
;
261 if(numwait
== WSK_MAX_ITEMS
)
262 break; /* sanity check */
264 log_assert(numwait
<= WSA_MAXIMUM_WAIT_EVENTS
);
265 verbose(VERB_CLIENT
, "winsock_event bmax=%d numwait=%d wait=%x "
266 "timeout=%d", base
->max
, numwait
, (int)wait
, (int)timeout
);
270 /* WSAWaitFor.. doesn't like 0 event objects */
276 ret
= WSAWaitForMultipleEvents(numwait
, base
->waitfor
,
277 0 /* do not wait for all, just one will do */,
278 wait
?timeout
:WSA_INFINITE
,
279 0); /* we are not alertable (IO completion events) */
280 if(ret
== WSA_WAIT_IO_COMPLETION
) {
281 log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
283 } else if(ret
== WSA_WAIT_FAILED
) {
284 log_err("WSAWaitForMultipleEvents failed: %s",
285 wsa_strerror(WSAGetLastError()));
287 } else if(ret
== WSA_WAIT_TIMEOUT
) {
290 startidx
= ret
- WSA_WAIT_EVENT_0
;
292 verbose(VERB_CLIENT
, "winsock_event wake was_timeout=%d startidx=%d",
293 was_timeout
, startidx
);
295 /* get new time after wait */
296 if(settime(base
) < 0)
300 if(base
->tcp_stickies
)
301 startidx
= 0; /* process all events, some are sticky */
302 for(i
=startidx
; i
<numwait
; i
++)
303 eventlist
[i
]->just_checked
= 1;
305 verbose(VERB_CLIENT
, "winsock_event signals");
306 for(i
=startidx
; i
<numwait
; i
++) {
307 if(!base
->waitfor
[i
])
308 continue; /* was deleted */
309 if(eventlist
[i
]->is_signal
) {
310 eventlist
[i
]->just_checked
= 0;
311 handle_signal(eventlist
[i
]);
314 /* early exit - do not process network, exit quickly */
315 if(base
->need_to_exit
)
318 verbose(VERB_CLIENT
, "winsock_event net");
319 for(i
=startidx
; i
<numwait
; i
++) {
321 /* eventlist[i] fired */
322 /* see if eventlist[i] is still valid and just checked from
323 * WSAWaitForEvents */
324 if(!base
->waitfor
[i
])
325 continue; /* was deleted */
326 if(!eventlist
[i
]->just_checked
)
327 continue; /* added by other callback */
328 if(eventlist
[i
]->is_signal
)
329 continue; /* not a network event at all */
330 eventlist
[i
]->just_checked
= 0;
332 if(WSAEnumNetworkEvents(eventlist
[i
]->ev_fd
,
333 base
->waitfor
[i
], /* reset the event handle */
334 /*NULL,*/ /* do not reset the event handle */
336 log_err("WSAEnumNetworkEvents failed: %s",
337 wsa_strerror(WSAGetLastError()));
340 if((netev
.lNetworkEvents
& FD_READ
)) {
341 if(netev
.iErrorCode
[FD_READ_BIT
] != 0)
342 verbose(VERB_ALGO
, "FD_READ_BIT error: %s",
343 wsa_strerror(netev
.iErrorCode
[FD_READ_BIT
]));
346 if((netev
.lNetworkEvents
& FD_WRITE
)) {
347 if(netev
.iErrorCode
[FD_WRITE_BIT
] != 0)
348 verbose(VERB_ALGO
, "FD_WRITE_BIT error: %s",
349 wsa_strerror(netev
.iErrorCode
[FD_WRITE_BIT
]));
352 if((netev
.lNetworkEvents
& FD_CONNECT
)) {
353 if(netev
.iErrorCode
[FD_CONNECT_BIT
] != 0)
354 verbose(VERB_ALGO
, "FD_CONNECT_BIT error: %s",
355 wsa_strerror(netev
.iErrorCode
[FD_CONNECT_BIT
]));
359 if((netev
.lNetworkEvents
& FD_ACCEPT
)) {
360 if(netev
.iErrorCode
[FD_ACCEPT_BIT
] != 0)
361 verbose(VERB_ALGO
, "FD_ACCEPT_BIT error: %s",
362 wsa_strerror(netev
.iErrorCode
[FD_ACCEPT_BIT
]));
365 if((netev
.lNetworkEvents
& FD_CLOSE
)) {
366 if(netev
.iErrorCode
[FD_CLOSE_BIT
] != 0)
367 verbose(VERB_ALGO
, "FD_CLOSE_BIT error: %s",
368 wsa_strerror(netev
.iErrorCode
[FD_CLOSE_BIT
]));
372 if(eventlist
[i
]->is_tcp
&& eventlist
[i
]->stick_events
) {
373 verbose(VERB_ALGO
, "winsock %d pass sticky %s%s",
375 (eventlist
[i
]->old_events
&EV_READ
)?"EV_READ":"",
376 (eventlist
[i
]->old_events
&EV_WRITE
)?"EV_WRITE":"");
377 bits
|= eventlist
[i
]->old_events
;
379 if(eventlist
[i
]->is_tcp
&& bits
) {
380 eventlist
[i
]->old_events
= bits
;
381 eventlist
[i
]->stick_events
= 1;
382 if((eventlist
[i
]->ev_events
& bits
)) {
385 verbose(VERB_ALGO
, "winsock %d store sticky %s%s",
387 (eventlist
[i
]->old_events
&EV_READ
)?"EV_READ":"",
388 (eventlist
[i
]->old_events
&EV_WRITE
)?"EV_WRITE":"");
390 if((bits
& eventlist
[i
]->ev_events
)) {
391 verbose(VERB_ALGO
, "winsock event callback %p fd=%d "
392 "%s%s%s%s%s ; %s%s%s",
393 eventlist
[i
], eventlist
[i
]->ev_fd
,
394 (netev
.lNetworkEvents
&FD_READ
)?" FD_READ":"",
395 (netev
.lNetworkEvents
&FD_WRITE
)?" FD_WRITE":"",
396 (netev
.lNetworkEvents
&FD_CONNECT
)?
398 (netev
.lNetworkEvents
&FD_ACCEPT
)?
400 (netev
.lNetworkEvents
&FD_CLOSE
)?" FD_CLOSE":"",
401 (bits
&EV_READ
)?" EV_READ":"",
402 (bits
&EV_WRITE
)?" EV_WRITE":"",
403 (bits
&EV_TIMEOUT
)?" EV_TIMEOUT":"");
405 fptr_ok(fptr_whitelist_event(
406 eventlist
[i
]->ev_callback
));
407 (*eventlist
[i
]->ev_callback
)(eventlist
[i
]->ev_fd
,
408 bits
& eventlist
[i
]->ev_events
,
409 eventlist
[i
]->ev_arg
);
411 if(eventlist
[i
]->is_tcp
&& bits
)
412 verbose(VERB_ALGO
, "winsock %d got sticky %s%s",
414 (eventlist
[i
]->old_events
&EV_READ
)?"EV_READ":"",
415 (eventlist
[i
]->old_events
&EV_WRITE
)?"EV_WRITE":"");
417 verbose(VERB_CLIENT
, "winsock_event net");
418 if(base
->tcp_reinvigorated
) {
419 verbose(VERB_CLIENT
, "winsock_event reinvigorated");
420 base
->tcp_reinvigorated
= 0;
423 base
->tcp_stickies
= newstickies
;
424 verbose(VERB_CLIENT
, "winsock_event handle_select end");
428 int event_base_dispatch(struct event_base
*base
)
431 if(settime(base
) < 0)
433 while(!base
->need_to_exit
)
435 /* see if timeouts need handling */
436 handle_timeouts(base
, base
->time_tv
, &wait
);
437 if(base
->need_to_exit
)
440 if(handle_select(base
, &wait
) < 0) {
441 if(base
->need_to_exit
)
449 int event_base_loopexit(struct event_base
*base
,
450 struct timeval
* ATTR_UNUSED(tv
))
452 verbose(VERB_CLIENT
, "winsock_event loopexit");
453 base
->need_to_exit
= 1;
457 void event_base_free(struct event_base
*base
)
459 verbose(VERB_CLIENT
, "winsock_event event_base_free");
471 void event_set(struct event
*ev
, int fd
, short bits
,
472 void (*cb
)(int, short, void *), void *arg
)
476 ev
->ev_events
= bits
;
477 ev
->ev_callback
= cb
;
478 fptr_ok(fptr_whitelist_event(ev
->ev_callback
));
480 ev
->just_checked
= 0;
484 int event_base_set(struct event_base
*base
, struct event
*ev
)
488 ev
->stick_events
= 0;
493 int event_add(struct event
*ev
, struct timeval
*tv
)
495 verbose(VERB_ALGO
, "event_add %p added=%d fd=%d tv=" ARG_LL
"d %s%s%s",
496 ev
, ev
->added
, ev
->ev_fd
,
497 (tv
?(long long)tv
->tv_sec
*1000+(long long)tv
->tv_usec
/1000:-1),
498 (ev
->ev_events
&EV_READ
)?" EV_READ":"",
499 (ev
->ev_events
&EV_WRITE
)?" EV_WRITE":"",
500 (ev
->ev_events
&EV_TIMEOUT
)?" EV_TIMEOUT":"");
503 log_assert(ev
->ev_fd
==-1 || find_fd(ev
->ev_base
, ev
->ev_fd
) == -1);
506 ev
->just_checked
= 0;
508 if((ev
->ev_events
&(EV_READ
|EV_WRITE
)) && ev
->ev_fd
!= -1) {
513 if(ev
->ev_base
->max
== ev
->ev_base
->cap
)
515 ev
->idx
= ev
->ev_base
->max
++;
516 ev
->ev_base
->items
[ev
->idx
] = ev
;
518 if( (ev
->ev_events
&EV_READ
) )
520 if( (ev
->ev_events
&EV_WRITE
) )
523 if(getsockopt(ev
->ev_fd
, SOL_SOCKET
, SO_TYPE
,
525 log_err("getsockopt(SO_TYPE) failed: %s",
526 wsa_strerror(WSAGetLastError()));
527 if(t
== SOCK_STREAM
) {
531 if( (ev
->ev_events
&EV_WRITE
) )
532 events
|= FD_CONNECT
;
534 if(getsockopt(ev
->ev_fd
, SOL_SOCKET
, SO_ACCEPTCONN
,
536 log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
537 wsa_strerror(WSAGetLastError()));
538 if(b
) /* TCP accept socket */
541 ev
->hEvent
= WSACreateEvent();
542 if(ev
->hEvent
== WSA_INVALID_EVENT
)
543 log_err("WSACreateEvent failed: %s",
544 wsa_strerror(WSAGetLastError()));
545 /* automatically sets fd to nonblocking mode.
546 * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
547 if(WSAEventSelect(ev
->ev_fd
, ev
->hEvent
, events
) != 0) {
548 log_err("WSAEventSelect failed: %s",
549 wsa_strerror(WSAGetLastError()));
551 if(ev
->is_tcp
&& ev
->stick_events
&&
552 (ev
->ev_events
& ev
->old_events
)) {
553 /* go to processing the sticky event right away */
554 ev
->ev_base
->tcp_reinvigorated
= 1;
558 if(tv
&& (ev
->ev_events
&EV_TIMEOUT
)) {
560 struct timeval
*now
= ev
->ev_base
->time_tv
;
561 ev
->ev_timeout
.tv_sec
= tv
->tv_sec
+ now
->tv_sec
;
562 ev
->ev_timeout
.tv_usec
= tv
->tv_usec
+ now
->tv_usec
;
563 while(ev
->ev_timeout
.tv_usec
> 1000000) {
564 ev
->ev_timeout
.tv_usec
-= 1000000;
565 ev
->ev_timeout
.tv_sec
++;
568 (void)rbtree_insert(ev
->ev_base
->times
, &ev
->node
);
574 int event_del(struct event
*ev
)
576 verbose(VERB_ALGO
, "event_del %p added=%d fd=%d tv=" ARG_LL
"d %s%s%s",
577 ev
, ev
->added
, ev
->ev_fd
,
578 (ev
->ev_events
&EV_TIMEOUT
)?(long long)ev
->ev_timeout
.tv_sec
*1000+
579 (long long)ev
->ev_timeout
.tv_usec
/1000:-1,
580 (ev
->ev_events
&EV_READ
)?" EV_READ":"",
581 (ev
->ev_events
&EV_WRITE
)?" EV_WRITE":"",
582 (ev
->ev_events
&EV_TIMEOUT
)?" EV_TIMEOUT":"");
585 log_assert(ev
->added
);
586 if((ev
->ev_events
&EV_TIMEOUT
))
587 (void)rbtree_delete(ev
->ev_base
->times
, &ev
->node
);
588 if((ev
->ev_events
&(EV_READ
|EV_WRITE
)) && ev
->ev_fd
!= -1) {
589 log_assert(ev
->ev_base
->max
> 0);
590 /* remove item and compact the list */
591 ev
->ev_base
->items
[ev
->idx
] =
592 ev
->ev_base
->items
[ev
->ev_base
->max
-1];
593 ev
->ev_base
->items
[ev
->ev_base
->max
-1] = NULL
;
595 if(ev
->idx
< ev
->ev_base
->max
)
596 ev
->ev_base
->items
[ev
->idx
]->idx
= ev
->idx
;
597 zero_waitfor(ev
->ev_base
->waitfor
, ev
->hEvent
);
599 if(WSAEventSelect(ev
->ev_fd
, ev
->hEvent
, 0) != 0)
600 log_err("WSAEventSelect(disable) failed: %s",
601 wsa_strerror(WSAGetLastError()));
602 if(!WSACloseEvent(ev
->hEvent
))
603 log_err("WSACloseEvent failed: %s",
604 wsa_strerror(WSAGetLastError()));
606 ev
->just_checked
= 0;
611 /** which base gets to handle signals */
612 static struct event_base
* signal_base
= NULL
;
613 /** signal handler */
614 static RETSIGTYPE
sigh(int sig
)
617 if(!signal_base
|| sig
< 0 || sig
>= MAX_SIG
)
619 ev
= signal_base
->signals
[sig
];
622 fptr_ok(fptr_whitelist_event(ev
->ev_callback
));
623 (*ev
->ev_callback
)(sig
, EV_SIGNAL
, ev
->ev_arg
);
626 int signal_add(struct event
*ev
, struct timeval
* ATTR_UNUSED(tv
))
628 if(ev
->ev_fd
== -1 || ev
->ev_fd
>= MAX_SIG
)
630 signal_base
= ev
->ev_base
;
631 ev
->ev_base
->signals
[ev
->ev_fd
] = ev
;
633 if(signal(ev
->ev_fd
, sigh
) == SIG_ERR
) {
639 int signal_del(struct event
*ev
)
641 if(ev
->ev_fd
== -1 || ev
->ev_fd
>= MAX_SIG
)
643 ev
->ev_base
->signals
[ev
->ev_fd
] = NULL
;
648 void winsock_tcp_wouldblock(struct event
* ev
, int eventbits
)
650 verbose(VERB_ALGO
, "winsock: tcp wouldblock %s",
651 eventbits
==EV_READ
?"EV_READ":"EV_WRITE");
652 ev
->old_events
&= (~eventbits
);
653 if(ev
->old_events
== 0)
654 ev
->stick_events
= 0;
655 /* in case this is the last sticky event, we could
656 * possibly run an empty handler loop to reset the base
657 * tcp_stickies variable
661 int winsock_register_wsaevent(struct event_base
* base
, struct event
* ev
,
662 WSAEVENT wsaevent
, void (*cb
)(int, short, void*), void* arg
)
664 if(base
->max
== base
->cap
)
666 memset(ev
, 0, sizeof(*ev
));
668 ev
->ev_events
= EV_READ
;
669 ev
->ev_callback
= cb
;
672 ev
->hEvent
= wsaevent
;
675 ev
->idx
= ev
->ev_base
->max
++;
676 ev
->ev_base
->items
[ev
->idx
] = ev
;
680 void winsock_unregister_wsaevent(struct event
* ev
)
682 if(!ev
|| !ev
->added
) return;
683 log_assert(ev
->added
&& ev
->ev_base
->max
> 0)
684 /* remove item and compact the list */
685 ev
->ev_base
->items
[ev
->idx
] = ev
->ev_base
->items
[ev
->ev_base
->max
-1];
686 ev
->ev_base
->items
[ev
->ev_base
->max
-1] = NULL
;
688 if(ev
->idx
< ev
->ev_base
->max
)
689 ev
->ev_base
->items
[ev
->idx
]->idx
= ev
->idx
;
693 #else /* USE_WINSOCK */
694 /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
695 int winsock_unused_symbol
= 1;
696 #endif /* USE_WINSOCK */