1 /* $NetBSD: buffer_iocp.c,v 1.1.1.1 2013/04/11 16:43:25 christos Exp $ */
3 * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 This module implements overlapped read and write functions for evbuffer
35 #include "event2/buffer.h"
36 #include "event2/buffer_compat.h"
37 #include "event2/util.h"
38 #include "event2/thread.h"
39 #include "event2/event-config.h"
40 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: buffer_iocp.c,v 1.1.1.1 2013/04/11 16:43:25 christos Exp $");
42 #include "util-internal.h"
43 #include "evthread-internal.h"
44 #include "evbuffer-internal.h"
45 #include "iocp-internal.h"
46 #include "mm-internal.h"
52 #define MAX_WSABUFS 16
54 /** An evbuffer that can handle overlapped IO. */
55 struct evbuffer_overlapped
{
56 struct evbuffer buffer
;
57 /** The socket that we're doing overlapped IO on. */
60 /** pending I/O type */
61 unsigned read_in_progress
: 1;
62 unsigned write_in_progress
: 1;
64 /** The first pinned chain in the buffer. */
65 struct evbuffer_chain
*first_pinned
;
67 /** How many chains are pinned; how many of the fields in buffers
70 WSABUF buffers
[MAX_WSABUFS
];
73 /** Given an evbuffer, return the correponding evbuffer structure, or NULL if
74 * the evbuffer isn't overlapped. */
75 static inline struct evbuffer_overlapped
*
76 upcast_evbuffer(struct evbuffer
*buf
)
78 if (!buf
|| !buf
->is_overlapped
)
80 return EVUTIL_UPCAST(buf
, struct evbuffer_overlapped
, buffer
);
83 /** Unpin all the chains noted as pinned in 'eo'. */
85 pin_release(struct evbuffer_overlapped
*eo
, unsigned flag
)
88 struct evbuffer_chain
*next
, *chain
= eo
->first_pinned
;
90 for (i
= 0; i
< eo
->n_buffers
; ++i
) {
93 _evbuffer_chain_unpin(chain
, flag
);
99 evbuffer_commit_read(struct evbuffer
*evbuf
, ev_ssize_t nBytes
)
101 struct evbuffer_overlapped
*buf
= upcast_evbuffer(evbuf
);
102 struct evbuffer_chain
**chainp
;
103 size_t remaining
, len
;
106 EVBUFFER_LOCK(evbuf
);
107 EVUTIL_ASSERT(buf
->read_in_progress
&& !buf
->write_in_progress
);
108 EVUTIL_ASSERT(nBytes
>= 0); /* XXXX Can this be false? */
110 evbuffer_unfreeze(evbuf
, 0);
112 chainp
= evbuf
->last_with_datap
;
113 if (!((*chainp
)->flags
& EVBUFFER_MEM_PINNED_R
))
114 chainp
= &(*chainp
)->next
;
116 for (i
= 0; remaining
> 0 && i
< (unsigned)buf
->n_buffers
; ++i
) {
117 EVUTIL_ASSERT(*chainp
);
118 len
= buf
->buffers
[i
].len
;
121 (*chainp
)->off
+= len
;
122 evbuf
->last_with_datap
= chainp
;
124 chainp
= &(*chainp
)->next
;
127 pin_release(buf
, EVBUFFER_MEM_PINNED_R
);
129 buf
->read_in_progress
= 0;
131 evbuf
->total_len
+= nBytes
;
132 evbuf
->n_add_for_cb
+= nBytes
;
134 evbuffer_invoke_callbacks(evbuf
);
136 _evbuffer_decref_and_unlock(evbuf
);
140 evbuffer_commit_write(struct evbuffer
*evbuf
, ev_ssize_t nBytes
)
142 struct evbuffer_overlapped
*buf
= upcast_evbuffer(evbuf
);
144 EVBUFFER_LOCK(evbuf
);
145 EVUTIL_ASSERT(buf
->write_in_progress
&& !buf
->read_in_progress
);
146 evbuffer_unfreeze(evbuf
, 1);
147 evbuffer_drain(evbuf
, nBytes
);
148 pin_release(buf
,EVBUFFER_MEM_PINNED_W
);
149 buf
->write_in_progress
= 0;
150 _evbuffer_decref_and_unlock(evbuf
);
154 evbuffer_overlapped_new(evutil_socket_t fd
)
156 struct evbuffer_overlapped
*evo
;
158 evo
= mm_calloc(1, sizeof(struct evbuffer_overlapped
));
162 TAILQ_INIT(&evo
->buffer
.callbacks
);
163 evo
->buffer
.refcnt
= 1;
164 evo
->buffer
.last_with_datap
= &evo
->buffer
.first
;
166 evo
->buffer
.is_overlapped
= 1;
173 evbuffer_launch_write(struct evbuffer
*buf
, ev_ssize_t at_most
,
174 struct event_overlapped
*ol
)
176 struct evbuffer_overlapped
*buf_o
= upcast_evbuffer(buf
);
179 struct evbuffer_chain
*chain
;
183 /* No buffer, or it isn't overlapped */
188 EVUTIL_ASSERT(!buf_o
->read_in_progress
);
189 if (buf
->freeze_start
|| buf_o
->write_in_progress
)
191 if (!buf
->total_len
) {
192 /* Nothing to write */
195 } else if (at_most
< 0 || (size_t)at_most
> buf
->total_len
) {
196 at_most
= buf
->total_len
;
198 evbuffer_freeze(buf
, 1);
200 buf_o
->first_pinned
= NULL
;
201 buf_o
->n_buffers
= 0;
202 memset(buf_o
->buffers
, 0, sizeof(buf_o
->buffers
));
204 chain
= buf_o
->first_pinned
= buf
->first
;
206 for (i
=0; i
< MAX_WSABUFS
&& chain
; ++i
, chain
=chain
->next
) {
207 WSABUF
*b
= &buf_o
->buffers
[i
];
208 b
->buf
= (char*)( chain
->buffer
+ chain
->misalign
);
209 _evbuffer_chain_pin(chain
, EVBUFFER_MEM_PINNED_W
);
211 if ((size_t)at_most
> chain
->off
) {
212 /* XXXX Cast is safe for now, since win32 has no
213 mmaped chains. But later, we need to have this
214 add more WSAbufs if chain->off is greater than
216 b
->len
= (unsigned long)chain
->off
;
217 at_most
-= chain
->off
;
219 b
->len
= (unsigned long)at_most
;
225 buf_o
->n_buffers
= i
;
226 _evbuffer_incref(buf
);
227 if (WSASend(buf_o
->fd
, buf_o
->buffers
, i
, &bytesSent
, 0,
228 &ol
->overlapped
, NULL
)) {
229 int error
= WSAGetLastError();
230 if (error
!= WSA_IO_PENDING
) {
231 /* An actual error. */
232 pin_release(buf_o
, EVBUFFER_MEM_PINNED_W
);
233 evbuffer_unfreeze(buf
, 1);
234 evbuffer_free(buf
); /* decref */
239 buf_o
->write_in_progress
= 1;
242 EVBUFFER_UNLOCK(buf
);
247 evbuffer_launch_read(struct evbuffer
*buf
, size_t at_most
,
248 struct event_overlapped
*ol
)
250 struct evbuffer_overlapped
*buf_o
= upcast_evbuffer(buf
);
254 struct evbuffer_chain
*chain
=NULL
, **chainp
;
257 struct evbuffer_iovec vecs
[MAX_WSABUFS
];
262 EVUTIL_ASSERT(!buf_o
->write_in_progress
);
263 if (buf
->freeze_end
|| buf_o
->read_in_progress
)
266 buf_o
->first_pinned
= NULL
;
267 buf_o
->n_buffers
= 0;
268 memset(buf_o
->buffers
, 0, sizeof(buf_o
->buffers
));
270 if (_evbuffer_expand_fast(buf
, at_most
, MAX_WSABUFS
) == -1)
272 evbuffer_freeze(buf
, 0);
274 nvecs
= _evbuffer_read_setup_vecs(buf
, at_most
,
275 vecs
, MAX_WSABUFS
, &chainp
, 1);
276 for (i
=0;i
<nvecs
;++i
) {
277 WSABUF_FROM_EVBUFFER_IOV(
282 buf_o
->n_buffers
= nvecs
;
283 buf_o
->first_pinned
= chain
= *chainp
;
286 for ( ; chain
; chain
= chain
->next
) {
287 _evbuffer_chain_pin(chain
, EVBUFFER_MEM_PINNED_R
);
290 EVUTIL_ASSERT(npin
== nvecs
);
292 _evbuffer_incref(buf
);
293 if (WSARecv(buf_o
->fd
, buf_o
->buffers
, nvecs
, &bytesRead
, &flags
,
294 &ol
->overlapped
, NULL
)) {
295 int error
= WSAGetLastError();
296 if (error
!= WSA_IO_PENDING
) {
297 /* An actual error. */
298 pin_release(buf_o
, EVBUFFER_MEM_PINNED_R
);
299 evbuffer_unfreeze(buf
, 0);
300 evbuffer_free(buf
); /* decref */
305 buf_o
->read_in_progress
= 1;
308 EVBUFFER_UNLOCK(buf
);
313 _evbuffer_overlapped_get_fd(struct evbuffer
*buf
)
315 struct evbuffer_overlapped
*buf_o
= upcast_evbuffer(buf
);
316 return buf_o
? buf_o
->fd
: -1;
320 _evbuffer_overlapped_set_fd(struct evbuffer
*buf
, evutil_socket_t fd
)
322 struct evbuffer_overlapped
*buf_o
= upcast_evbuffer(buf
);
324 /* XXX is this right?, should it cancel current I/O operations? */
327 EVBUFFER_UNLOCK(buf
);