bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / unix / readwrite.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_arch_file_io.h"
18 #include "apr_strings.h"
19 #include "apr_thread_mutex.h"
20 #include "apr_support.h"
21
22 /* The only case where we don't use wait_for_io_or_timeout is on
23  * pre-BONE BeOS, so this check should be sufficient and simpler */
24 #if !BEOS_R5
25 #define USE_WAIT_FOR_IO
26 #endif
27
28 /* problems: 
29  * 1) ungetchar not used for buffered files
30  */
31 APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
32 {
33     apr_ssize_t rv;
34     apr_size_t bytes_read;
35
36     if (*nbytes <= 0) {
37         *nbytes = 0;
38         return APR_SUCCESS;
39     }
40
41     if (thefile->buffered) {
42         char *pos = (char *)buf;
43         apr_uint64_t blocksize;
44         apr_uint64_t size = *nbytes;
45
46         file_lock(thefile);
47
48         if (thefile->direction == 1) {
49             rv = apr_file_flush_locked(thefile);
50             if (rv) {
51                 file_unlock(thefile);
52                 return rv;
53             }
54             thefile->bufpos = 0;
55             thefile->direction = 0;
56             thefile->dataRead = 0;
57         }
58
59         rv = 0;
60         if (thefile->ungetchar != -1) {
61             *pos = (char)thefile->ungetchar;
62             ++pos;
63             --size;
64             thefile->ungetchar = -1;
65         }
66         while (rv == 0 && size > 0) {
67             if (thefile->bufpos >= thefile->dataRead) {
68                 int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
69                 if (bytesread == 0) {
70                     thefile->eof_hit = TRUE;
71                     rv = APR_EOF;
72                     break;
73                 }
74                 else if (bytesread == -1) {
75                     rv = errno;
76                     break;
77                 }
78                 thefile->dataRead = bytesread;
79                 thefile->filePtr += thefile->dataRead;
80                 thefile->bufpos = 0;
81             }
82
83             blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
84             memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
85             thefile->bufpos += blocksize;
86             pos += blocksize;
87             size -= blocksize;
88         }
89
90         *nbytes = pos - (char *)buf;
91         if (*nbytes) {
92             rv = 0;
93         }
94
95         file_unlock(thefile);
96
97         return rv;
98     }
99     else {
100         bytes_read = 0;
101         if (thefile->ungetchar != -1) {
102             bytes_read = 1;
103             *(char *)buf = (char)thefile->ungetchar;
104             buf = (char *)buf + 1;
105             (*nbytes)--;
106             thefile->ungetchar = -1;
107             if (*nbytes == 0) {
108                 *nbytes = bytes_read;
109                 return APR_SUCCESS;
110             }
111         }
112
113         do {
114             rv = read(thefile->filedes, buf, *nbytes);
115         } while (rv == -1 && errno == EINTR);
116 #ifdef USE_WAIT_FOR_IO
117         if (rv == -1 && 
118             (errno == EAGAIN || errno == EWOULDBLOCK) && 
119             thefile->timeout != 0) {
120             apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
121             if (arv != APR_SUCCESS) {
122                 *nbytes = bytes_read;
123                 return arv;
124             }
125             else {
126                 do {
127                     rv = read(thefile->filedes, buf, *nbytes);
128                 } while (rv == -1 && errno == EINTR);
129             }
130         }  
131 #endif
132         *nbytes = bytes_read;
133         if (rv == 0) {
134             thefile->eof_hit = TRUE;
135             return APR_EOF;
136         }
137         if (rv > 0) {
138             *nbytes += rv;
139             return APR_SUCCESS;
140         }
141         return errno;
142     }
143 }
144
145 APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
146 {
147     apr_size_t rv;
148
149     if (thefile->buffered) {
150         char *pos = (char *)buf;
151         int blocksize;
152         int size = *nbytes;
153
154         file_lock(thefile);
155
156         if ( thefile->direction == 0 ) {
157             /* Position file pointer for writing at the offset we are 
158              * logically reading from
159              */
160             apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
161             if (offset != thefile->filePtr)
162                 lseek(thefile->filedes, offset, SEEK_SET);
163             thefile->bufpos = thefile->dataRead = 0;
164             thefile->direction = 1;
165         }
166
167         rv = 0;
168         while (rv == 0 && size > 0) {
169             if (thefile->bufpos == APR_FILE_BUFSIZE)   /* write buffer is full*/
170                 rv = apr_file_flush_locked(thefile);
171
172             blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
173                         APR_FILE_BUFSIZE - thefile->bufpos : size;
174             memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);                      
175             thefile->bufpos += blocksize;
176             pos += blocksize;
177             size -= blocksize;
178         }
179
180         file_unlock(thefile);
181
182         return rv;
183     }
184     else {
185         do {
186             rv = write(thefile->filedes, buf, *nbytes);
187         } while (rv == (apr_size_t)-1 && errno == EINTR);
188 #ifdef USE_WAIT_FOR_IO
189         if (rv == (apr_size_t)-1 &&
190             (errno == EAGAIN || errno == EWOULDBLOCK) && 
191             thefile->timeout != 0) {
192             apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
193             if (arv != APR_SUCCESS) {
194                 *nbytes = 0;
195                 return arv;
196             }
197             else {
198                 do {
199                     do {
200                         rv = write(thefile->filedes, buf, *nbytes);
201                     } while (rv == (apr_size_t)-1 && errno == EINTR);
202                     if (rv == (apr_size_t)-1 &&
203                         (errno == EAGAIN || errno == EWOULDBLOCK)) {
204                         *nbytes /= 2; /* yes, we'll loop if kernel lied
205                                        * and we can't even write 1 byte
206                                        */
207                     }
208                     else {
209                         break;
210                     }
211                 } while (1);
212             }
213         }  
214 #endif
215         if (rv == (apr_size_t)-1) {
216             (*nbytes) = 0;
217             return errno;
218         }
219         *nbytes = rv;
220         return APR_SUCCESS;
221     }
222 }
223
224 APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
225                                           apr_size_t nvec, apr_size_t *nbytes)
226 {
227 #ifdef HAVE_WRITEV
228     apr_status_t rv;
229     int bytes;
230
231     if (thefile->buffered) {
232         file_lock(thefile);
233
234         rv = apr_file_flush_locked(thefile);
235         if (rv != APR_SUCCESS) {
236             file_unlock(thefile);
237             return rv;
238         }
239         if (thefile->direction == 0) {
240             /* Position file pointer for writing at the offset we are
241              * logically reading from
242              */
243             apr_int64_t offset = thefile->filePtr - thefile->dataRead +
244                                  thefile->bufpos;
245             if (offset != thefile->filePtr)
246                 lseek(thefile->filedes, offset, SEEK_SET);
247             thefile->bufpos = thefile->dataRead = 0;
248         }
249
250         file_unlock(thefile);
251     }
252
253     if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
254         *nbytes = 0;
255         rv = errno;
256     }
257     else {
258         *nbytes = bytes;
259         rv = APR_SUCCESS;
260     }
261     return rv;
262 #else
263     *nbytes = vec[0].iov_len;
264     return apr_file_write(thefile, vec[0].iov_base, nbytes);
265 #endif
266 }
267
268 APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
269 {
270     apr_size_t nbytes = 1;
271
272     return apr_file_write(thefile, &ch, &nbytes);
273 }
274
275 APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
276 {
277     thefile->ungetchar = (unsigned char)ch;
278     return APR_SUCCESS; 
279 }
280
281 APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
282 {
283     apr_size_t nbytes = 1;
284
285     return apr_file_read(thefile, ch, &nbytes);
286 }
287
288 APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
289 {
290     apr_size_t nbytes = strlen(str);
291
292     return apr_file_write(thefile, str, &nbytes);
293 }
294
295 apr_status_t apr_file_flush_locked(apr_file_t *thefile)
296 {
297     apr_status_t rv = APR_SUCCESS;
298
299     if (thefile->direction == 1 && thefile->bufpos) {
300         apr_ssize_t written;
301
302         do {
303             written = write(thefile->filedes, thefile->buffer, thefile->bufpos);
304         } while (written == -1 && errno == EINTR);
305         if (written == -1) {
306             rv = errno;
307         } else {
308             thefile->filePtr += written;
309             thefile->bufpos = 0;
310         }
311     }
312
313     return rv;
314 }
315
316 APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
317 {
318     apr_status_t rv = APR_SUCCESS;
319
320     if (thefile->buffered) {
321         file_lock(thefile);
322         rv = apr_file_flush_locked(thefile);
323         file_unlock(thefile);
324     }
325     /* There isn't anything to do if we aren't buffering the output
326      * so just return success.
327      */
328     return rv; 
329 }
330
331 APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
332 {
333     apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
334     apr_size_t nbytes;
335     const char *str_start = str;
336     char *final = str + len - 1;
337
338     if (len <= 1) {  
339         /* sort of like fgets(), which returns NULL and stores no bytes 
340          */
341         return APR_SUCCESS;
342     }
343
344     while (str < final) { /* leave room for trailing '\0' */
345         nbytes = 1;
346         rv = apr_file_read(thefile, str, &nbytes);
347         if (rv != APR_SUCCESS) {
348             break;
349         }
350         if (*str == '\n') {
351             ++str;
352             break;
353         }
354         ++str;
355     }
356     /* We must store a terminating '\0' if we've stored any chars. We can
357      * get away with storing it if we hit an error first. 
358      */
359     *str = '\0';
360     if (str > str_start) {
361         /* we stored chars; don't report EOF or any other errors;
362          * the app will find out about that on the next call
363          */
364         return APR_SUCCESS;
365     }
366     return rv;
367 }
368
369 APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, 
370                                         const char *format, ...)
371 {
372     apr_status_t cc;
373     va_list ap;
374     char *buf;
375     int len;
376
377     buf = malloc(HUGE_STRING_LEN);
378     if (buf == NULL) {
379         return 0;
380     }
381     va_start(ap, format);
382     len = apr_vsnprintf(buf, HUGE_STRING_LEN, format, ap);
383     cc = apr_file_puts(buf, fptr);
384     va_end(ap);
385     free(buf);
386     return (cc == APR_SUCCESS) ? len : -1;
387 }