1 /* $NetBSD: win32select.c,v 1.1.1.2 2015/01/29 06:37:53 spz Exp $ */
3 * Copyright 2007-2012 Niels Provos and Nick Mathewson
4 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5 * Copyright 2003 Michael A. Davis <mike@datanerds.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/queue.h>
41 #include "event2/util.h"
42 #include "event2/event-config.h"
43 #include <sys/cdefs.h>
44 __RCSID("$NetBSD: win32select.c,v 1.1.1.2 2015/01/29 06:37:53 spz Exp $");
45 #include "util-internal.h"
46 #include "log-internal.h"
47 #include "event2/event.h"
48 #include "event-internal.h"
49 #include "evmap-internal.h"
50 #include "event2/thread.h"
51 #include "evthread-internal.h"
53 #define XFREE(ptr) do { if (ptr) mm_free(ptr); } while (0)
55 extern struct event_list timequeue
;
56 extern struct event_list addqueue
;
63 /* MSDN says this is required to handle SIGFPE */
64 volatile double SIGFPE_REQ
= 0.0f
;
72 unsigned num_fds_in_fd_sets
;
74 struct win_fd_set
*readset_in
;
75 struct win_fd_set
*writeset_in
;
76 struct win_fd_set
*readset_out
;
77 struct win_fd_set
*writeset_out
;
78 struct win_fd_set
*exset_out
;
79 unsigned signals_are_broken
: 1;
82 static void *win32_init(struct event_base
*);
83 static int win32_add(struct event_base
*, evutil_socket_t
, short old
, short events
, void *_idx
);
84 static int win32_del(struct event_base
*, evutil_socket_t
, short old
, short events
, void *_idx
);
85 static int win32_dispatch(struct event_base
*base
, struct timeval
*);
86 static void win32_dealloc(struct event_base
*);
88 struct eventop win32ops
= {
95 0, /* doesn't need reinit */
96 0, /* No features supported. */
97 sizeof(struct idx_info
),
100 #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
103 grow_fd_sets(struct win32op
*op
, unsigned new_num_fds
)
107 EVUTIL_ASSERT(new_num_fds
>= op
->readset_in
->fd_count
&&
108 new_num_fds
>= op
->writeset_in
->fd_count
);
109 EVUTIL_ASSERT(new_num_fds
>= 1);
111 size
= FD_SET_ALLOC_SIZE(new_num_fds
);
112 if (!(op
->readset_in
= mm_realloc(op
->readset_in
, size
)))
114 if (!(op
->writeset_in
= mm_realloc(op
->writeset_in
, size
)))
116 op
->resize_out_sets
= 1;
117 op
->num_fds_in_fd_sets
= new_num_fds
;
122 do_fd_set(struct win32op
*op
, struct idx_info
*ent
, evutil_socket_t s
, int read
)
124 struct win_fd_set
*set
= read
? op
->readset_in
: op
->writeset_in
;
126 if (ent
->read_pos_plus1
> 0)
129 if (ent
->write_pos_plus1
> 0)
132 if (set
->fd_count
== op
->num_fds_in_fd_sets
) {
133 if (grow_fd_sets(op
, op
->num_fds_in_fd_sets
*2))
135 /* set pointer will have changed and needs reiniting! */
136 set
= read
? op
->readset_in
: op
->writeset_in
;
138 set
->fd_array
[set
->fd_count
] = s
;
140 ent
->read_pos_plus1
= set
->fd_count
+1;
142 ent
->write_pos_plus1
= set
->fd_count
+1;
143 return (set
->fd_count
++);
147 do_fd_clear(struct event_base
*base
,
148 struct win32op
*op
, struct idx_info
*ent
, int read
)
151 struct win_fd_set
*set
= read
? op
->readset_in
: op
->writeset_in
;
153 i
= ent
->read_pos_plus1
- 1;
154 ent
->read_pos_plus1
= 0;
156 i
= ent
->write_pos_plus1
- 1;
157 ent
->write_pos_plus1
= 0;
161 if (--set
->fd_count
!= (unsigned)i
) {
162 struct idx_info
*ent2
;
164 s2
= set
->fd_array
[i
] = set
->fd_array
[set
->fd_count
];
166 ent2
= evmap_io_get_fdinfo(&base
->io
, s2
);
168 if (!ent2
) /* This indicates a bug. */
171 ent2
->read_pos_plus1
= i
+1;
173 ent2
->write_pos_plus1
= i
+1;
180 win32_init(struct event_base
*_base
)
182 struct win32op
*winop
;
184 if (!(winop
= mm_calloc(1, sizeof(struct win32op
))))
186 winop
->num_fds_in_fd_sets
= NEVENT
;
187 size
= FD_SET_ALLOC_SIZE(NEVENT
);
188 if (!(winop
->readset_in
= mm_malloc(size
)))
190 if (!(winop
->writeset_in
= mm_malloc(size
)))
192 if (!(winop
->readset_out
= mm_malloc(size
)))
194 if (!(winop
->writeset_out
= mm_malloc(size
)))
196 if (!(winop
->exset_out
= mm_malloc(size
)))
198 winop
->readset_in
->fd_count
= winop
->writeset_in
->fd_count
= 0;
199 winop
->readset_out
->fd_count
= winop
->writeset_out
->fd_count
200 = winop
->exset_out
->fd_count
= 0;
202 if (evsig_init(_base
) < 0)
203 winop
->signals_are_broken
= 1;
207 XFREE(winop
->readset_in
);
208 XFREE(winop
->writeset_in
);
209 XFREE(winop
->readset_out
);
210 XFREE(winop
->writeset_out
);
211 XFREE(winop
->exset_out
);
217 win32_add(struct event_base
*base
, evutil_socket_t fd
,
218 short old
, short events
, void *_idx
)
220 struct win32op
*win32op
= base
->evbase
;
221 struct idx_info
*idx
= _idx
;
223 if ((events
& EV_SIGNAL
) && win32op
->signals_are_broken
)
226 if (!(events
& (EV_READ
|EV_WRITE
)))
229 event_debug(("%s: adding event for %d", __func__
, (int)fd
));
230 if (events
& EV_READ
) {
231 if (do_fd_set(win32op
, idx
, fd
, 1)<0)
234 if (events
& EV_WRITE
) {
235 if (do_fd_set(win32op
, idx
, fd
, 0)<0)
242 win32_del(struct event_base
*base
, evutil_socket_t fd
, short old
, short events
,
245 struct win32op
*win32op
= base
->evbase
;
246 struct idx_info
*idx
= _idx
;
248 event_debug(("%s: Removing event for "EV_SOCK_FMT
,
249 __func__
, EV_SOCK_ARG(fd
)));
250 if (events
& EV_READ
)
251 do_fd_clear(base
, win32op
, idx
, 1);
252 if (events
& EV_WRITE
)
253 do_fd_clear(base
, win32op
, idx
, 0);
259 fd_set_copy(struct win_fd_set
*out
, const struct win_fd_set
*in
)
261 out
->fd_count
= in
->fd_count
;
262 memcpy(out
->fd_array
, in
->fd_array
, in
->fd_count
* (sizeof(SOCKET
)));
266 static void dump_fd_set(struct win_fd_set *s)
270 for(i=0;i<s->fd_count;++i)
271 printf("%d ",(int)s->fd_array[i]);
277 win32_dispatch(struct event_base
*base
, struct timeval
*tv
)
279 struct win32op
*win32op
= base
->evbase
;
285 if (win32op
->resize_out_sets
) {
286 size_t size
= FD_SET_ALLOC_SIZE(win32op
->num_fds_in_fd_sets
);
287 if (!(win32op
->readset_out
= mm_realloc(win32op
->readset_out
, size
)))
289 if (!(win32op
->exset_out
= mm_realloc(win32op
->exset_out
, size
)))
291 if (!(win32op
->writeset_out
= mm_realloc(win32op
->writeset_out
, size
)))
293 win32op
->resize_out_sets
= 0;
296 fd_set_copy(win32op
->readset_out
, win32op
->readset_in
);
297 fd_set_copy(win32op
->exset_out
, win32op
->writeset_in
);
298 fd_set_copy(win32op
->writeset_out
, win32op
->writeset_in
);
301 (win32op
->readset_out
->fd_count
> win32op
->writeset_out
->fd_count
) ?
302 win32op
->readset_out
->fd_count
: win32op
->writeset_out
->fd_count
;
305 long msec
= tv
? evutil_tv_to_msec(tv
) : LONG_MAX
;
306 /* Sleep's DWORD argument is unsigned long */
309 /* Windows doesn't like you to call select() with no sockets */
314 EVBASE_RELEASE_LOCK(base
, th_base_lock
);
316 res
= select(fd_count
,
317 (struct fd_set
*)win32op
->readset_out
,
318 (struct fd_set
*)win32op
->writeset_out
,
319 (struct fd_set
*)win32op
->exset_out
, tv
);
321 EVBASE_ACQUIRE_LOCK(base
, th_base_lock
);
323 event_debug(("%s: select returned %d", __func__
, res
));
329 if (win32op
->readset_out
->fd_count
) {
330 i
= rand() % win32op
->readset_out
->fd_count
;
331 for (j
=0; j
<win32op
->readset_out
->fd_count
; ++j
) {
332 if (++i
>= win32op
->readset_out
->fd_count
)
334 s
= win32op
->readset_out
->fd_array
[i
];
335 evmap_io_active(base
, s
, EV_READ
);
338 if (win32op
->exset_out
->fd_count
) {
339 i
= rand() % win32op
->exset_out
->fd_count
;
340 for (j
=0; j
<win32op
->exset_out
->fd_count
; ++j
) {
341 if (++i
>= win32op
->exset_out
->fd_count
)
343 s
= win32op
->exset_out
->fd_array
[i
];
344 evmap_io_active(base
, s
, EV_WRITE
);
347 if (win32op
->writeset_out
->fd_count
) {
349 i
= rand() % win32op
->writeset_out
->fd_count
;
350 for (j
=0; j
<win32op
->writeset_out
->fd_count
; ++j
) {
351 if (++i
>= win32op
->writeset_out
->fd_count
)
353 s
= win32op
->writeset_out
->fd_array
[i
];
354 evmap_io_active(base
, s
, EV_WRITE
);
361 win32_dealloc(struct event_base
*_base
)
363 struct win32op
*win32op
= _base
->evbase
;
365 evsig_dealloc(_base
);
366 if (win32op
->readset_in
)
367 mm_free(win32op
->readset_in
);
368 if (win32op
->writeset_in
)
369 mm_free(win32op
->writeset_in
);
370 if (win32op
->readset_out
)
371 mm_free(win32op
->readset_out
);
372 if (win32op
->writeset_out
)
373 mm_free(win32op
->writeset_out
);
374 if (win32op
->exset_out
)
375 mm_free(win32op
->exset_out
);
376 /* XXXXX free the tree. */
378 memset(win32op
, 0, sizeof(*win32op
));