| 1 | /* |
|---|
| 2 | * This file is part of libtrace |
|---|
| 3 | * |
|---|
| 4 | * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton, |
|---|
| 5 | * New Zealand. |
|---|
| 6 | * |
|---|
| 7 | * Authors: Daniel Lawson |
|---|
| 8 | * Perry Lorier |
|---|
| 9 | * Shane Alcock |
|---|
| 10 | * |
|---|
| 11 | * All rights reserved. |
|---|
| 12 | * |
|---|
| 13 | * This code has been developed by the University of Waikato WAND |
|---|
| 14 | * research group. For further information please see http://www.wand.net.nz/ |
|---|
| 15 | * |
|---|
| 16 | * libtrace is free software; you can redistribute it and/or modify |
|---|
| 17 | * it under the terms of the GNU General Public License as published by |
|---|
| 18 | * the Free Software Foundation; either version 2 of the License, or |
|---|
| 19 | * (at your option) any later version. |
|---|
| 20 | * |
|---|
| 21 | * libtrace is distributed in the hope that it will be useful, |
|---|
| 22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 24 | * GNU General Public License for more details. |
|---|
| 25 | * |
|---|
| 26 | * You should have received a copy of the GNU General Public License |
|---|
| 27 | * along with libtrace; if not, write to the Free Software |
|---|
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 29 | * |
|---|
| 30 | * $Id$ |
|---|
| 31 | * |
|---|
| 32 | */ |
|---|
| 33 | |
|---|
| 34 | #include "wandio.h" |
|---|
| 35 | #include <sys/types.h> |
|---|
| 36 | #include <sys/stat.h> |
|---|
| 37 | #include <fcntl.h> |
|---|
| 38 | #include <stdlib.h> |
|---|
| 39 | #include <unistd.h> |
|---|
| 40 | #include <string.h> |
|---|
| 41 | #include <assert.h> |
|---|
| 42 | #include <stddef.h> |
|---|
| 43 | |
|---|
| 44 | /* Libtrace IO module implementing a peeking reader. |
|---|
| 45 | * |
|---|
| 46 | * Assuming my understanding of Perry's code is correct, this module provides |
|---|
| 47 | * generic support for "peeking" that can be used in concert with any other |
|---|
| 48 | * implemented IO reader. |
|---|
| 49 | * |
|---|
| 50 | * The other IO reader is a "child" to the peeking reader and is used to read |
|---|
| 51 | * the data into a buffer managed by the peeking reader. Any actual "peeks" |
|---|
| 52 | * are serviced from the managed buffer, which means that we do not have to |
|---|
| 53 | * manipulate the read offsets directly in zlib or bzip, for instance. |
|---|
| 54 | */ |
|---|
| 55 | |
|---|
| 56 | /* for O_DIRECT we have to read in multiples of this */ |
|---|
| 57 | #define MIN_READ_SIZE 4096 |
|---|
| 58 | /* Round reads for peeks into the buffer up to this size */ |
|---|
| 59 | #define PEEK_SIZE (1024*1024) |
|---|
| 60 | |
|---|
| 61 | struct peek_t { |
|---|
| 62 | io_t *child; |
|---|
| 63 | char *buffer; |
|---|
| 64 | int length; /* Length of buffer */ |
|---|
| 65 | int offset; /* Offset into buffer */ |
|---|
| 66 | }; |
|---|
| 67 | |
|---|
| 68 | extern io_source_t peek_source; |
|---|
| 69 | |
|---|
| 70 | #define DATA(io) ((struct peek_t *)((io)->data)) |
|---|
| 71 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
|---|
| 72 | |
|---|
| 73 | io_t *peek_open(io_t *child) |
|---|
| 74 | { |
|---|
| 75 | io_t *io; |
|---|
| 76 | if (!child) |
|---|
| 77 | return NULL; |
|---|
| 78 | io = malloc(sizeof(io_t)); |
|---|
| 79 | io->data = malloc(sizeof(struct peek_t)); |
|---|
| 80 | io->source = &peek_source; |
|---|
| 81 | |
|---|
| 82 | /* Wrap the peeking reader around the "child" */ |
|---|
| 83 | DATA(io)->child = child; |
|---|
| 84 | DATA(io)->buffer = NULL; |
|---|
| 85 | DATA(io)->length = 0; |
|---|
| 86 | DATA(io)->offset = 0; |
|---|
| 87 | |
|---|
| 88 | return io; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | /* Read at least "len" bytes from the child io into the internal buffer, and return how many |
|---|
| 92 | bytes was actually read. |
|---|
| 93 | */ |
|---|
| 94 | static off_t refill_buffer(io_t *io, off_t len) |
|---|
| 95 | { |
|---|
| 96 | off_t bytes_read; |
|---|
| 97 | assert(DATA(io)->length - DATA(io)->offset == 0); |
|---|
| 98 | /* Select the largest of "len", PEEK_SIZE and the current peek buffer size |
|---|
| 99 | * and then round up to the nearest multiple of MIN_READ_SIZE |
|---|
| 100 | */ |
|---|
| 101 | bytes_read = len < PEEK_SIZE ? PEEK_SIZE : len; |
|---|
| 102 | bytes_read = bytes_read < DATA(io)->length ? DATA(io)->length : bytes_read; |
|---|
| 103 | bytes_read += MIN_READ_SIZE - (bytes_read % MIN_READ_SIZE); |
|---|
| 104 | /* Is the current buffer big enough? */ |
|---|
| 105 | if (DATA(io)->length < bytes_read) { |
|---|
| 106 | int res = 0; |
|---|
| 107 | void *buf_ptr = (void *)(DATA(io)->buffer); |
|---|
| 108 | |
|---|
| 109 | if (buf_ptr) |
|---|
| 110 | free(buf_ptr); |
|---|
| 111 | DATA(io)->length = bytes_read; |
|---|
| 112 | DATA(io)->offset = 0; |
|---|
| 113 | #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 |
|---|
| 114 | /* We need to do this as read() of O_DIRECT might happen into |
|---|
| 115 | * this buffer. The docs suggest 512 bytes is all we need to |
|---|
| 116 | * align to, but I'm suspicious. I expect disks with 4k blocks |
|---|
| 117 | * will arrive soon, and thus 4k is the minimum I'm willing to |
|---|
| 118 | * live with. |
|---|
| 119 | */ |
|---|
| 120 | res = posix_memalign(&buf_ptr, 4096, DATA(io)->length); |
|---|
| 121 | if (res != 0) { |
|---|
| 122 | fprintf(stderr, "Error aligning IO buffer: %d\n", |
|---|
| 123 | res); |
|---|
| 124 | return res; |
|---|
| 125 | } |
|---|
| 126 | DATA(io)->buffer = buf_ptr; |
|---|
| 127 | #else |
|---|
| 128 | res = 0; /* << Silly warning */ |
|---|
| 129 | DATA(io)->buffer = malloc(DATA(io)->length); |
|---|
| 130 | #endif |
|---|
| 131 | } |
|---|
| 132 | else |
|---|
| 133 | DATA(io)->length = bytes_read; |
|---|
| 134 | |
|---|
| 135 | assert(DATA(io)->buffer); |
|---|
| 136 | |
|---|
| 137 | /* Now actually attempt to read that many bytes */ |
|---|
| 138 | bytes_read = DATA(io)->child->source->read( |
|---|
| 139 | DATA(io)->child, DATA(io)->buffer, bytes_read); |
|---|
| 140 | |
|---|
| 141 | DATA(io)->offset = 0; |
|---|
| 142 | DATA(io)->length = bytes_read; |
|---|
| 143 | |
|---|
| 144 | /* Error? */ |
|---|
| 145 | if (bytes_read < 1) |
|---|
| 146 | return bytes_read; |
|---|
| 147 | |
|---|
| 148 | return bytes_read; |
|---|
| 149 | |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | static off_t peek_read(io_t *io, void *buffer, off_t len) |
|---|
| 153 | { |
|---|
| 154 | off_t ret = 0; |
|---|
| 155 | |
|---|
| 156 | /* Is some of this data in the buffer? */ |
|---|
| 157 | if (DATA(io)->buffer) { |
|---|
| 158 | ret = MIN(len,DATA(io)->length - DATA(io)->offset); |
|---|
| 159 | |
|---|
| 160 | /* Copy anything we've got into their buffer, and shift our |
|---|
| 161 | * offset so that we don't peek at the data we've read again */ |
|---|
| 162 | memcpy(buffer, |
|---|
| 163 | DATA(io)->buffer + DATA(io)->offset, |
|---|
| 164 | ret); |
|---|
| 165 | buffer += ret; |
|---|
| 166 | DATA(io)->offset += ret; |
|---|
| 167 | len -= ret; |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | /* Use the child reader to get the rest of the required data */ |
|---|
| 171 | if (len>0) { |
|---|
| 172 | /* To get here, the buffer must be empty */ |
|---|
| 173 | assert(DATA(io)->length-DATA(io)->offset == 0); |
|---|
| 174 | off_t bytes_read; |
|---|
| 175 | /* If they're reading exactly a block size, just use that, no point in malloc'ing |
|---|
| 176 | * and memcpy()ing needlessly. However, if the buffer isn't aligned, we need to |
|---|
| 177 | * pass on an aligning buffer, skip this and do it into our own aligned buffer. |
|---|
| 178 | */ |
|---|
| 179 | if ((len % MIN_READ_SIZE == 0) && ((ptrdiff_t)buffer % 4096)==0) { |
|---|
| 180 | assert(((ptrdiff_t)buffer % 4096) == 0); |
|---|
| 181 | bytes_read = DATA(io)->child->source->read( |
|---|
| 182 | DATA(io)->child, buffer, len); |
|---|
| 183 | /* Error? */ |
|---|
| 184 | if (bytes_read < 1) { |
|---|
| 185 | /* Return if we have managed to get some data ok */ |
|---|
| 186 | if (ret > 0) |
|---|
| 187 | return ret; |
|---|
| 188 | /* Return the error upstream */ |
|---|
| 189 | return bytes_read; |
|---|
| 190 | } |
|---|
| 191 | } |
|---|
| 192 | else { |
|---|
| 193 | bytes_read = refill_buffer(io, len); |
|---|
| 194 | if (bytes_read < 1) { |
|---|
| 195 | /* Return if we have managed to get some data ok */ |
|---|
| 196 | if (ret > 0) |
|---|
| 197 | return ret; |
|---|
| 198 | /* Return the error upstream */ |
|---|
| 199 | return bytes_read; |
|---|
| 200 | } |
|---|
| 201 | /* Now grab the number of bytes asked for. */ |
|---|
| 202 | len = len < bytes_read ? len : bytes_read; |
|---|
| 203 | memcpy(buffer, DATA(io)->buffer, len); |
|---|
| 204 | |
|---|
| 205 | DATA(io)->offset = len; |
|---|
| 206 | bytes_read = len; |
|---|
| 207 | } |
|---|
| 208 | ret += bytes_read; |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | /* Have we read past the end of the buffer? */ |
|---|
| 212 | if (DATA(io)->buffer && DATA(io)->offset >= DATA(io)->length) { |
|---|
| 213 | /* If so, free the memory it used */ |
|---|
| 214 | free(DATA(io)->buffer); |
|---|
| 215 | DATA(io)->buffer = NULL; |
|---|
| 216 | DATA(io)->offset = 0; |
|---|
| 217 | DATA(io)->length = 0; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | return ret; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | static void *alignedrealloc(void *old, size_t oldsize, size_t size, int *res) |
|---|
| 224 | { |
|---|
| 225 | #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 |
|---|
| 226 | void *new; |
|---|
| 227 | /* Shortcut resizing */ |
|---|
| 228 | if (size < oldsize) |
|---|
| 229 | return old; |
|---|
| 230 | *res = posix_memalign(&new, 4096, size); |
|---|
| 231 | if (*res != 0) { |
|---|
| 232 | fprintf(stderr, "Error aligning IO buffer: %d\n", *res); |
|---|
| 233 | |
|---|
| 234 | return NULL; |
|---|
| 235 | } |
|---|
| 236 | assert(oldsize<size); |
|---|
| 237 | memcpy(new,old,oldsize); |
|---|
| 238 | free(old); |
|---|
| 239 | return new; |
|---|
| 240 | #else |
|---|
| 241 | /* These no-ops are to stop the compiler whinging about unused |
|---|
| 242 | * parameters */ |
|---|
| 243 | oldsize = oldsize; |
|---|
| 244 | res = res; |
|---|
| 245 | return realloc(old,size); |
|---|
| 246 | #endif |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | |
|---|
| 250 | static off_t peek_peek(io_t *io, void *buffer, off_t len) |
|---|
| 251 | { |
|---|
| 252 | off_t ret = 0; |
|---|
| 253 | int res = 0; |
|---|
| 254 | |
|---|
| 255 | /* Is there enough data in the buffer to serve this request? */ |
|---|
| 256 | if (DATA(io)->length - DATA(io)->offset < len) { |
|---|
| 257 | /* No, we need to extend the buffer. */ |
|---|
| 258 | off_t read_amount = len - (DATA(io)->length - DATA(io)->offset); |
|---|
| 259 | /* Round the read_amount up to the nearest MB */ |
|---|
| 260 | read_amount += PEEK_SIZE - ((DATA(io)->length + read_amount) % PEEK_SIZE); |
|---|
| 261 | DATA(io)->buffer = alignedrealloc(DATA(io)->buffer, |
|---|
| 262 | DATA(io)->length, |
|---|
| 263 | DATA(io)->length + read_amount, &res); |
|---|
| 264 | |
|---|
| 265 | if (DATA(io)->buffer == NULL) { |
|---|
| 266 | return res; |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | /* Use the child reader to read more data into our managed |
|---|
| 270 | * buffer */ |
|---|
| 271 | read_amount = wandio_read(DATA(io)->child, |
|---|
| 272 | DATA(io)->buffer + DATA(io)->length, |
|---|
| 273 | read_amount); |
|---|
| 274 | |
|---|
| 275 | /* Pass errors up */ |
|---|
| 276 | if (read_amount <1) { |
|---|
| 277 | return read_amount; |
|---|
| 278 | } |
|---|
| 279 | |
|---|
| 280 | DATA(io)->length += read_amount; |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | /* Right, now return data from the buffer (that now should be large |
|---|
| 284 | * enough, but might not be if we hit EOF) */ |
|---|
| 285 | ret = MIN(len, DATA(io)->length - DATA(io)->offset); |
|---|
| 286 | memcpy(buffer, DATA(io)->buffer + DATA(io)->offset, ret); |
|---|
| 287 | return ret; |
|---|
| 288 | } |
|---|
| 289 | |
|---|
| 290 | static off_t peek_tell(io_t *io) |
|---|
| 291 | { |
|---|
| 292 | /* We don't actually maintain a read offset as such, so we want to |
|---|
| 293 | * return the child's read offset */ |
|---|
| 294 | return wandio_tell(DATA(io)->child); |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | static off_t peek_seek(io_t *io, off_t offset, int whence) |
|---|
| 298 | { |
|---|
| 299 | /* Again, we don't have a genuine read offset so we need to pass this |
|---|
| 300 | * one on to the child */ |
|---|
| 301 | return wandio_seek(DATA(io)->child,offset,whence); |
|---|
| 302 | } |
|---|
| 303 | |
|---|
| 304 | static void peek_close(io_t *io) |
|---|
| 305 | { |
|---|
| 306 | /* Make sure we close the child that is doing the actual reading! */ |
|---|
| 307 | wandio_destroy(DATA(io)->child); |
|---|
| 308 | if (DATA(io)->buffer) |
|---|
| 309 | free(DATA(io)->buffer); |
|---|
| 310 | free(io->data); |
|---|
| 311 | free(io); |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | io_source_t peek_source = { |
|---|
| 315 | "peek", |
|---|
| 316 | peek_read, |
|---|
| 317 | peek_peek, |
|---|
| 318 | peek_tell, |
|---|
| 319 | peek_seek, |
|---|
| 320 | peek_close |
|---|
| 321 | }; |
|---|
| 322 | |
|---|