Annotation of embedaddon/lighttpd/src/network_write_mmap.c, revision 1.1.1.1
1.1 misho 1: #include "first.h"
2:
3: #include "network_backends.h"
4:
5: #include "network.h"
6: #include "log.h"
7: #include "sys-mmap.h"
8:
9: #include <setjmp.h>
10: #include <signal.h>
11: #include <unistd.h>
12:
13: #include <errno.h>
14: #include <string.h>
15:
16: #define MMAP_CHUNK_SIZE (512*1024)
17:
18: off_t mmap_align_offset(off_t start) {
19: static long pagesize = 0;
20: if (0 == pagesize) {
21: pagesize = sysconf(_SC_PAGESIZE);
22: force_assert(pagesize < MMAP_CHUNK_SIZE);
23: }
24: force_assert(start >= (start % pagesize));
25: return start - (start % pagesize);
26: }
27:
28: #if defined(USE_MMAP)
29:
30: static volatile int sigbus_jmp_valid;
31: static sigjmp_buf sigbus_jmp;
32:
33: static void sigbus_handler(int sig) {
34: UNUSED(sig);
35: if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
36: log_failed_assert(__FILE__, __LINE__, "SIGBUS");
37: }
38:
39: #if 0
40: /* read mmap()ed data into local buffer */
41: #define LOCAL_BUFFERING 1
42: #endif
43:
44: int network_write_file_chunk_mmap(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) {
45: chunk* const c = cq->first;
46: off_t offset, toSend, file_end;
47: ssize_t r;
48: size_t mmap_offset, mmap_avail;
49: const char *data;
50:
51: force_assert(NULL != c);
52: force_assert(FILE_CHUNK == c->type);
53: force_assert(c->offset >= 0 && c->offset <= c->file.length);
54:
55: offset = c->file.start + c->offset;
56: toSend = c->file.length - c->offset;
57: if (toSend > *p_max_bytes) toSend = *p_max_bytes;
58: file_end = c->file.start + c->file.length; /* offset to file end in this chunk */
59:
60: if (0 == toSend) {
61: chunkqueue_remove_finished_chunks(cq);
62: return 0;
63: }
64:
65: if (0 != network_open_file_chunk(srv, con, cq)) return -1;
66:
67: /* setup SIGBUS handler, but don't activate sigbus_jmp_valid yet */
68: if (0 != sigsetjmp(sigbus_jmp, 1)) {
69: sigbus_jmp_valid = 0;
70:
71: log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
72: c->file.name, c->file.fd);
73:
74: munmap(c->file.mmap.start, c->file.mmap.length);
75: c->file.mmap.start = MAP_FAILED;
76: #ifdef LOCAL_BUFFERING
77: buffer_reset(c->mem);
78: #endif
79:
80: return -1;
81: }
82:
83: signal(SIGBUS, sigbus_handler);
84:
85: /* mmap the buffer if offset is outside old mmap area or not mapped at all */
86: if (MAP_FAILED == c->file.mmap.start
87: || offset < c->file.mmap.offset
88: || offset >= (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
89:
90: if (MAP_FAILED != c->file.mmap.start) {
91: munmap(c->file.mmap.start, c->file.mmap.length);
92: c->file.mmap.start = MAP_FAILED;
93: }
94:
95: /* Optimizations for the future:
96: *
97: * adaptive mem-mapping
98: * the problem:
99: * we mmap() the whole file. If someone has alot large files and 32bit
100: * machine the virtual address area will be unrun and we will have a failing
101: * mmap() call.
102: * solution:
103: * only mmap 16M in one chunk and move the window as soon as we have finished
104: * the first 8M
105: *
106: * read-ahead buffering
107: * the problem:
108: * sending out several large files in parallel trashes the read-ahead of the
109: * kernel leading to long wait-for-seek times.
110: * solutions: (increasing complexity)
111: * 1. use madvise
112: * 2. use a internal read-ahead buffer in the chunk-structure
113: * 3. use non-blocking IO for file-transfers
114: * */
115:
116: c->file.mmap.offset = mmap_align_offset(offset);
117:
118: /* all mmap()ed areas are MMAP_CHUNK_SIZE except the last which might be smaller */
119: c->file.mmap.length = MMAP_CHUNK_SIZE;
120: if (c->file.mmap.offset > file_end - (off_t)c->file.mmap.length) {
121: c->file.mmap.length = file_end - c->file.mmap.offset;
122: }
123:
124: if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
125: log_error_write(srv, __FILE__, __LINE__, "ssbdoo", "mmap failed:",
126: strerror(errno), c->file.name, c->file.fd, c->file.mmap.offset, (off_t) c->file.mmap.length);
127: return -1;
128: }
129:
130: #if defined(LOCAL_BUFFERING)
131: sigbus_jmp_valid = 1;
132: buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
133: sigbus_jmp_valid = 0;
134: #else
135: # if defined(HAVE_MADVISE)
136: /* don't advise files < 64Kb */
137: if (c->file.mmap.length > (64*1024)) {
138: /* darwin 7 is returning EINVAL all the time and I don't know how to
139: * detect this at runtime.
140: *
141: * ignore the return value for now */
142: madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
143: }
144: # endif
145: #endif
146: }
147:
148: force_assert(offset >= c->file.mmap.offset);
149: mmap_offset = offset - c->file.mmap.offset;
150: force_assert(c->file.mmap.length > mmap_offset);
151: mmap_avail = c->file.mmap.length - mmap_offset;
152: if (toSend > (off_t) mmap_avail) toSend = mmap_avail;
153:
154: #if defined(LOCAL_BUFFERING)
155: data = c->mem->ptr + mmap_offset;
156: #else
157: data = c->file.mmap.start + mmap_offset;
158: #endif
159:
160: sigbus_jmp_valid = 1;
161: #if defined(__WIN32)
162: r = send(fd, data, toSend, 0);
163: #else /* __WIN32 */
164: r = write(fd, data, toSend);
165: #endif /* __WIN32 */
166: sigbus_jmp_valid = 0;
167:
168: #if defined(__WIN32)
169: if (r < 0) {
170: int lastError = WSAGetLastError();
171: switch (lastError) {
172: case WSAEINTR:
173: case WSAEWOULDBLOCK:
174: break;
175: case WSAECONNRESET:
176: case WSAETIMEDOUT:
177: case WSAECONNABORTED:
178: return -2;
179: default:
180: log_error_write(srv, __FILE__, __LINE__, "sdd",
181: "send failed: ", lastError, fd);
182: return -1;
183: }
184: }
185: #else /* __WIN32 */
186: if (r < 0) {
187: switch (errno) {
188: case EAGAIN:
189: case EINTR:
190: break;
191: case EPIPE:
192: case ECONNRESET:
193: return -2;
194: default:
195: log_error_write(srv, __FILE__, __LINE__, "ssd",
196: "write failed:", strerror(errno), fd);
197: return -1;
198: }
199: }
200: #endif /* __WIN32 */
201:
202: if (r >= 0) {
203: *p_max_bytes -= r;
204: chunkqueue_mark_written(cq, r);
205: }
206:
207: return (r > 0 && r == toSend) ? 0 : -3;
208: }
209:
210: #endif /* USE_MMAP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>