]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_sendfile.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc_r / uthread / uthread_sendfile.c
1 /*
2  * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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
15  *    distribution.
16  * 
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.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/fcntl.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36 #include <errno.h>
37 #include <pthread.h>
38 #include "pthread_private.h"
39
40 __weak_reference(_sendfile, sendfile);
41
42 int
43 _sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr,
44     off_t *sbytes, int flags)
45 {
46         struct pthread  *curthread = _get_curthread();
47         int     type, blocking;
48         int     ret = 0;
49         ssize_t wvret, num = 0;
50         off_t   n, nwritten = 0;
51
52         /*
53          * Write the headers if any.
54          * If some data is written but not all we must return here.
55          */
56         if ((hdtr != NULL) && (hdtr->headers != NULL)) {
57                 if ((wvret = writev(s, hdtr->headers, hdtr->hdr_cnt)) == -1) {
58                         ret = -1;
59                         goto ERROR;
60                 } else {
61                         int i;
62                         ssize_t hdrtot;
63
64                         nwritten += wvret;
65
66                         for (i = 0, hdrtot = 0; i < hdtr->hdr_cnt; i++)
67                                 hdrtot += hdtr->headers[i].iov_len;
68                         if (wvret < hdrtot)
69                                 goto SHORT_WRITE;
70                 }
71         }
72         
73         /* Lock the descriptors. */
74         if ((ret = _FD_LOCK(fd, FD_READ, NULL)) != 0) {
75                 ret = -1;
76                 errno = EBADF;
77                 goto ERROR;
78         }
79         if ((ret = _FD_LOCK(s, FD_WRITE, NULL)) != 0) {
80                 ret = -1;
81                 errno = EBADF;
82                 goto ERROR_1;
83         }
84         
85         /* Check the descriptor access modes. */
86         type = _thread_fd_getflags(fd) & O_ACCMODE;
87         if (type != O_RDONLY && type != O_RDWR) {
88                 /* File is not open for read. */
89                 ret = -1;
90                 errno = EBADF;
91                 goto ERROR_2;
92         }
93         type = _thread_fd_getflags(s) & O_ACCMODE;
94         if (type != O_WRONLY && type != O_RDWR) {
95                 /* File is not open for write. */
96                 ret = -1;
97                 errno = EBADF;
98                 goto ERROR_2;
99         }
100
101         /* Check if file operations are to block */
102         blocking = ((_thread_fd_getflags(s) & O_NONBLOCK) == 0);
103
104         /*
105          * Loop while no error occurs and until the expected number of bytes are
106          * written.
107          */
108         for (;;) {
109                 /* Perform a non-blocking sendfile syscall. */
110                 ret = __sys_sendfile(fd, s, offset + num, nbytes - num,
111                     NULL, &n, flags);
112
113                 /*
114                  * We have to handle the sideways return path of sendfile.
115                  *
116                  * If the result is 0, we're done.
117                  * If the result is anything else check the errno.
118                  * If the errno is not EGAIN return the error.
119                  * Otherwise, take into account how much
120                  * sendfile may have written for us because sendfile can
121                  * return EAGAIN even though it has written data.
122                  *
123                  * We don't clear 'ret' because the sendfile(2) syscall
124                  * would not have either.
125                  */
126                 if (ret == 0) {
127                         /* Writing completed. */
128                         num += n;
129                         break;
130                 } else if ((ret == -1) && (errno == EAGAIN)) {
131                         /*
132                          * Some bytes were written but there are still more to
133                          * write.
134                          */
135
136                         /* Update the count of bytes written. */
137                         num += n;
138
139                         /*
140                          * If we're not blocking then return.
141                          */
142                         if (!blocking) {
143                                 _FD_UNLOCK(s, FD_WRITE);
144                                 _FD_UNLOCK(fd, FD_READ);
145                                 goto SHORT_WRITE;
146                         }
147
148                         /*
149                          * Otherwise wait on the fd.
150                          */
151                         curthread->data.fd.fd = fd;
152                         _thread_kern_set_timeout(NULL);
153
154                         /* Reset the interrupted operation flag. */
155                         curthread->interrupted = 0;
156
157                         _thread_kern_sched_state(PS_FDW_WAIT, __FILE__,
158                             __LINE__);
159
160                         if (curthread->interrupted) {
161                                 /* Interrupted by a signal.  Return an error. */
162                                 break;
163                         }
164                 } else {
165                         /* Incomplete non-blocking syscall, or error. */
166                         break;
167                 }
168         }
169
170   ERROR_2:
171         _FD_UNLOCK(s, FD_WRITE);
172   ERROR_1:
173         _FD_UNLOCK(fd, FD_READ);
174   ERROR:
175         if (ret == 0) {
176                 /* Write the trailers, if any. */
177                 if ((hdtr != NULL) && (hdtr->trailers != NULL)) {
178                         if ((wvret = writev(s, hdtr->trailers, hdtr->trl_cnt))
179                             == -1)
180                                 ret = -1;
181                         else
182                                 nwritten += wvret;
183                 }
184         }
185   SHORT_WRITE:
186         if (sbytes != NULL) {
187                 /*
188                  * Number of bytes written in headers/trailers, plus in the main
189                  * sendfile() loop.
190                  */
191                 *sbytes = nwritten + num;
192         }
193         return (ret);
194 }