x86_64: Fix machdep.smp_active sysctl type.
[dragonfly.git] / lib / libc_r / uthread / uthread_sendfile.c
blob3d5d9ab8b654176dc1ff93ee1ac3c6c9325f9078
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.
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>
36 #include <sys/uio.h>
37 #include <errno.h>
38 #include <pthread.h>
39 #include "pthread_private.h"
41 int
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();
46 int type, blocking;
47 int ret = 0;
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) {
57 ret = -1;
58 goto ERROR;
59 } else {
60 int i;
61 ssize_t hdrtot;
63 nwritten += wvret;
65 for (i = 0, hdrtot = 0; i < hdtr->hdr_cnt; i++)
66 hdrtot += hdtr->headers[i].iov_len;
67 if (wvret < hdrtot)
68 goto SHORT_WRITE;
72 /* Lock the descriptors. */
73 if ((ret = _FD_LOCK(fd, FD_READ, NULL)) != 0) {
74 ret = -1;
75 errno = EBADF;
76 goto ERROR;
78 if ((ret = _FD_LOCK(s, FD_WRITE, NULL)) != 0) {
79 ret = -1;
80 errno = EBADF;
81 goto ERROR_1;
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. */
88 ret = -1;
89 errno = EBADF;
90 goto ERROR_2;
92 type = _thread_fd_getflags(s) & O_ACCMODE;
93 if (type != O_WRONLY && type != O_RDWR) {
94 /* File is not open for write. */
95 ret = -1;
96 errno = EBADF;
97 goto ERROR_2;
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
105 * written.
107 for (;;) {
108 /* Perform a non-blocking sendfile syscall. */
109 ret = __sys_sendfile(fd, s, offset + num, nbytes - num,
110 NULL, &n, flags);
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.
125 if (ret == 0) {
126 /* Writing completed. */
127 num += n;
128 break;
129 } else if ((ret == -1) && (errno == EAGAIN)) {
131 * Some bytes were written but there are still more to
132 * write.
135 /* Update the count of bytes written. */
136 num += n;
139 * If we're not blocking then return.
141 if (!blocking) {
142 _FD_UNLOCK(s, FD_WRITE);
143 _FD_UNLOCK(fd, FD_READ);
144 goto SHORT_WRITE;
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__,
157 __LINE__);
159 if (curthread->interrupted) {
160 /* Interrupted by a signal. Return an error. */
161 break;
163 } else {
164 /* Incomplete non-blocking syscall, or error. */
165 break;
169 ERROR_2:
170 _FD_UNLOCK(s, FD_WRITE);
171 ERROR_1:
172 _FD_UNLOCK(fd, FD_READ);
173 ERROR:
174 if (ret == 0) {
175 /* Write the trailers, if any. */
176 if ((hdtr != NULL) && (hdtr->trailers != NULL)) {
177 if ((wvret = writev(s, hdtr->trailers, hdtr->trl_cnt))
178 == -1)
179 ret = -1;
180 else
181 nwritten += wvret;
184 SHORT_WRITE:
185 if (sbytes != NULL) {
187 * Number of bytes written in headers/trailers, plus in the main
188 * sendfile() loop.
190 *sbytes = nwritten + num;
192 return (ret);