2 * Copyright 2007-2012 Niels Provos and Nick Mathewson
3 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
4 * Copyright 2003 Michael A. Davis <mike@datanerds.net>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/types.h>
32 #include <sys/queue.h>
40 #include "event2/util.h"
41 #include "event2/event-config.h"
42 #include "util-internal.h"
43 #include "log-internal.h"
44 #include "event2/event.h"
45 #include "event-internal.h"
46 #include "evmap-internal.h"
47 #include "event2/thread.h"
48 #include "evthread-internal.h"
50 #define XFREE(ptr) do { if (ptr) mm_free(ptr); } while (0)
52 extern struct event_list timequeue
;
53 extern struct event_list addqueue
;
60 /* MSDN says this is required to handle SIGFPE */
61 volatile double SIGFPE_REQ
= 0.0f
;
69 unsigned num_fds_in_fd_sets
;
71 struct win_fd_set
*readset_in
;
72 struct win_fd_set
*writeset_in
;
73 struct win_fd_set
*readset_out
;
74 struct win_fd_set
*writeset_out
;
75 struct win_fd_set
*exset_out
;
76 unsigned signals_are_broken
: 1;
79 static void *win32_init(struct event_base
*);
80 static int win32_add(struct event_base
*, evutil_socket_t
, short old
, short events
, void *_idx
);
81 static int win32_del(struct event_base
*, evutil_socket_t
, short old
, short events
, void *_idx
);
82 static int win32_dispatch(struct event_base
*base
, struct timeval
*);
83 static void win32_dealloc(struct event_base
*);
85 struct eventop win32ops
= {
92 0, /* doesn't need reinit */
93 0, /* No features supported. */
94 sizeof(struct idx_info
),
97 #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
100 grow_fd_sets(struct win32op
*op
, unsigned new_num_fds
)
104 EVUTIL_ASSERT(new_num_fds
>= op
->readset_in
->fd_count
&&
105 new_num_fds
>= op
->writeset_in
->fd_count
);
106 EVUTIL_ASSERT(new_num_fds
>= 1);
108 size
= FD_SET_ALLOC_SIZE(new_num_fds
);
109 if (!(op
->readset_in
= mm_realloc(op
->readset_in
, size
)))
111 if (!(op
->writeset_in
= mm_realloc(op
->writeset_in
, size
)))
113 op
->resize_out_sets
= 1;
114 op
->num_fds_in_fd_sets
= new_num_fds
;
119 do_fd_set(struct win32op
*op
, struct idx_info
*ent
, evutil_socket_t s
, int read
)
121 struct win_fd_set
*set
= read
? op
->readset_in
: op
->writeset_in
;
123 if (ent
->read_pos_plus1
> 0)
126 if (ent
->write_pos_plus1
> 0)
129 if (set
->fd_count
== op
->num_fds_in_fd_sets
) {
130 if (grow_fd_sets(op
, op
->num_fds_in_fd_sets
*2))
132 /* set pointer will have changed and needs reiniting! */
133 set
= read
? op
->readset_in
: op
->writeset_in
;
135 set
->fd_array
[set
->fd_count
] = s
;
137 ent
->read_pos_plus1
= set
->fd_count
+1;
139 ent
->write_pos_plus1
= set
->fd_count
+1;
140 return (set
->fd_count
++);
144 do_fd_clear(struct event_base
*base
,
145 struct win32op
*op
, struct idx_info
*ent
, int read
)
148 struct win_fd_set
*set
= read
? op
->readset_in
: op
->writeset_in
;
150 i
= ent
->read_pos_plus1
- 1;
151 ent
->read_pos_plus1
= 0;
153 i
= ent
->write_pos_plus1
- 1;
154 ent
->write_pos_plus1
= 0;
158 if (--set
->fd_count
!= (unsigned)i
) {
159 struct idx_info
*ent2
;
161 s2
= set
->fd_array
[i
] = set
->fd_array
[set
->fd_count
];
163 ent2
= evmap_io_get_fdinfo(&base
->io
, s2
);
165 if (!ent2
) /* This indicates a bug. */
168 ent2
->read_pos_plus1
= i
+1;
170 ent2
->write_pos_plus1
= i
+1;
177 win32_init(struct event_base
*_base
)
179 struct win32op
*winop
;
181 if (!(winop
= mm_calloc(1, sizeof(struct win32op
))))
183 winop
->num_fds_in_fd_sets
= NEVENT
;
184 size
= FD_SET_ALLOC_SIZE(NEVENT
);
185 if (!(winop
->readset_in
= mm_malloc(size
)))
187 if (!(winop
->writeset_in
= mm_malloc(size
)))
189 if (!(winop
->readset_out
= mm_malloc(size
)))
191 if (!(winop
->writeset_out
= mm_malloc(size
)))
193 if (!(winop
->exset_out
= mm_malloc(size
)))
195 winop
->readset_in
->fd_count
= winop
->writeset_in
->fd_count
= 0;
196 winop
->readset_out
->fd_count
= winop
->writeset_out
->fd_count
197 = winop
->exset_out
->fd_count
= 0;
199 if (evsig_init(_base
) < 0)
200 winop
->signals_are_broken
= 1;
204 XFREE(winop
->readset_in
);
205 XFREE(winop
->writeset_in
);
206 XFREE(winop
->readset_out
);
207 XFREE(winop
->writeset_out
);
208 XFREE(winop
->exset_out
);
214 win32_add(struct event_base
*base
, evutil_socket_t fd
,
215 short old
, short events
, void *_idx
)
217 struct win32op
*win32op
= base
->evbase
;
218 struct idx_info
*idx
= _idx
;
220 if ((events
& EV_SIGNAL
) && win32op
->signals_are_broken
)
223 if (!(events
& (EV_READ
|EV_WRITE
)))
226 event_debug(("%s: adding event for %d", __func__
, (int)fd
));
227 if (events
& EV_READ
) {
228 if (do_fd_set(win32op
, idx
, fd
, 1)<0)
231 if (events
& EV_WRITE
) {
232 if (do_fd_set(win32op
, idx
, fd
, 0)<0)
239 win32_del(struct event_base
*base
, evutil_socket_t fd
, short old
, short events
,
242 struct win32op
*win32op
= base
->evbase
;
243 struct idx_info
*idx
= _idx
;
245 event_debug(("%s: Removing event for "EV_SOCK_FMT
,
246 __func__
, EV_SOCK_ARG(fd
)));
247 if (events
& EV_READ
)
248 do_fd_clear(base
, win32op
, idx
, 1);
249 if (events
& EV_WRITE
)
250 do_fd_clear(base
, win32op
, idx
, 0);
256 fd_set_copy(struct win_fd_set
*out
, const struct win_fd_set
*in
)
258 out
->fd_count
= in
->fd_count
;
259 memcpy(out
->fd_array
, in
->fd_array
, in
->fd_count
* (sizeof(SOCKET
)));
263 static void dump_fd_set(struct win_fd_set *s)
267 for(i=0;i<s->fd_count;++i)
268 printf("%d ",(int)s->fd_array[i]);
274 win32_dispatch(struct event_base
*base
, struct timeval
*tv
)
276 struct win32op
*win32op
= base
->evbase
;
282 if (win32op
->resize_out_sets
) {
283 size_t size
= FD_SET_ALLOC_SIZE(win32op
->num_fds_in_fd_sets
);
284 if (!(win32op
->readset_out
= mm_realloc(win32op
->readset_out
, size
)))
286 if (!(win32op
->exset_out
= mm_realloc(win32op
->exset_out
, size
)))
288 if (!(win32op
->writeset_out
= mm_realloc(win32op
->writeset_out
, size
)))
290 win32op
->resize_out_sets
= 0;
293 fd_set_copy(win32op
->readset_out
, win32op
->readset_in
);
294 fd_set_copy(win32op
->exset_out
, win32op
->writeset_in
);
295 fd_set_copy(win32op
->writeset_out
, win32op
->writeset_in
);
298 (win32op
->readset_out
->fd_count
> win32op
->writeset_out
->fd_count
) ?
299 win32op
->readset_out
->fd_count
: win32op
->writeset_out
->fd_count
;
302 long msec
= tv
? evutil_tv_to_msec(tv
) : LONG_MAX
;
303 /* Sleep's DWORD argument is unsigned long */
306 /* Windows doesn't like you to call select() with no sockets */
311 EVBASE_RELEASE_LOCK(base
, th_base_lock
);
313 res
= select(fd_count
,
314 (struct fd_set
*)win32op
->readset_out
,
315 (struct fd_set
*)win32op
->writeset_out
,
316 (struct fd_set
*)win32op
->exset_out
, tv
);
318 EVBASE_ACQUIRE_LOCK(base
, th_base_lock
);
320 event_debug(("%s: select returned %d", __func__
, res
));
326 if (win32op
->readset_out
->fd_count
) {
327 i
= rand() % win32op
->readset_out
->fd_count
;
328 for (j
=0; j
<win32op
->readset_out
->fd_count
; ++j
) {
329 if (++i
>= win32op
->readset_out
->fd_count
)
331 s
= win32op
->readset_out
->fd_array
[i
];
332 evmap_io_active(base
, s
, EV_READ
);
335 if (win32op
->exset_out
->fd_count
) {
336 i
= rand() % win32op
->exset_out
->fd_count
;
337 for (j
=0; j
<win32op
->exset_out
->fd_count
; ++j
) {
338 if (++i
>= win32op
->exset_out
->fd_count
)
340 s
= win32op
->exset_out
->fd_array
[i
];
341 evmap_io_active(base
, s
, EV_WRITE
);
344 if (win32op
->writeset_out
->fd_count
) {
346 i
= rand() % win32op
->writeset_out
->fd_count
;
347 for (j
=0; j
<win32op
->writeset_out
->fd_count
; ++j
) {
348 if (++i
>= win32op
->writeset_out
->fd_count
)
350 s
= win32op
->writeset_out
->fd_array
[i
];
351 evmap_io_active(base
, s
, EV_WRITE
);
358 win32_dealloc(struct event_base
*_base
)
360 struct win32op
*win32op
= _base
->evbase
;
362 evsig_dealloc(_base
);
363 if (win32op
->readset_in
)
364 mm_free(win32op
->readset_in
);
365 if (win32op
->writeset_in
)
366 mm_free(win32op
->writeset_in
);
367 if (win32op
->readset_out
)
368 mm_free(win32op
->readset_out
);
369 if (win32op
->writeset_out
)
370 mm_free(win32op
->writeset_out
);
371 if (win32op
->exset_out
)
372 mm_free(win32op
->exset_out
);
373 /* XXXXX free the tree. */
375 memset(win32op
, 0, sizeof(win32op
));