2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
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(s), this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified other than the possible
11 * addition of one or more copyright notices.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice(s), this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * $FreeBSD: src/lib/libc_r/uthread/uthread_sendfile.c,v 1.2.2.10 2002/10/22 14:44:03 fjoe Exp $
30 * $DragonFly: src/lib/libc_r/uthread/uthread_sendfile.c,v 1.2 2003/06/17 04:26:48 dillon Exp $
33 #include <sys/fcntl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
39 #include "pthread_private.h"
42 sendfile(int fd
, int s
, off_t offset
, size_t nbytes
, struct sf_hdtr
*hdtr
,
43 off_t
*sbytes
, int flags
)
45 struct pthread
*curthread
= _get_curthread();
48 ssize_t wvret
, num
= 0;
49 off_t n
, nwritten
= 0;
52 * Write the headers if any.
53 * If some data is written but not all we must return here.
55 if ((hdtr
!= NULL
) && (hdtr
->headers
!= NULL
)) {
56 if ((wvret
= writev(s
, hdtr
->headers
, hdtr
->hdr_cnt
)) == -1) {
65 for (i
= 0, hdrtot
= 0; i
< hdtr
->hdr_cnt
; i
++)
66 hdrtot
+= hdtr
->headers
[i
].iov_len
;
72 /* Lock the descriptors. */
73 if ((ret
= _FD_LOCK(fd
, FD_READ
, NULL
)) != 0) {
78 if ((ret
= _FD_LOCK(s
, FD_WRITE
, NULL
)) != 0) {
84 /* Check the descriptor access modes. */
85 type
= _thread_fd_getflags(fd
) & O_ACCMODE
;
86 if (type
!= O_RDONLY
&& type
!= O_RDWR
) {
87 /* File is not open for read. */
92 type
= _thread_fd_getflags(s
) & O_ACCMODE
;
93 if (type
!= O_WRONLY
&& type
!= O_RDWR
) {
94 /* File is not open for write. */
100 /* Check if file operations are to block */
101 blocking
= ((_thread_fd_getflags(s
) & O_NONBLOCK
) == 0);
104 * Loop while no error occurs and until the expected number of bytes are
108 /* Perform a non-blocking sendfile syscall. */
109 ret
= __sys_sendfile(fd
, s
, offset
+ num
, nbytes
- num
,
113 * We have to handle the sideways return path of sendfile.
115 * If the result is 0, we're done.
116 * If the result is anything else check the errno.
117 * If the errno is not EGAIN return the error.
118 * Otherwise, take into account how much
119 * sendfile may have written for us because sendfile can
120 * return EAGAIN even though it has written data.
122 * We don't clear 'ret' because the sendfile(2) syscall
123 * would not have either.
126 /* Writing completed. */
129 } else if ((ret
== -1) && (errno
== EAGAIN
)) {
131 * Some bytes were written but there are still more to
135 /* Update the count of bytes written. */
139 * If we're not blocking then return.
142 _FD_UNLOCK(s
, FD_WRITE
);
143 _FD_UNLOCK(fd
, FD_READ
);
148 * Otherwise wait on the fd.
150 curthread
->data
.fd
.fd
= fd
;
151 _thread_kern_set_timeout(NULL
);
153 /* Reset the interrupted operation flag. */
154 curthread
->interrupted
= 0;
156 _thread_kern_sched_state(PS_FDW_WAIT
, __FILE__
,
159 if (curthread
->interrupted
) {
160 /* Interrupted by a signal. Return an error. */
164 /* Incomplete non-blocking syscall, or error. */
170 _FD_UNLOCK(s
, FD_WRITE
);
172 _FD_UNLOCK(fd
, FD_READ
);
175 /* Write the trailers, if any. */
176 if ((hdtr
!= NULL
) && (hdtr
->trailers
!= NULL
)) {
177 if ((wvret
= writev(s
, hdtr
->trailers
, hdtr
->trl_cnt
))
185 if (sbytes
!= NULL
) {
187 * Number of bytes written in headers/trailers, plus in the main
190 *sbytes
= nwritten
+ num
;