188c5f205SDaniel P. Berrange /* 288c5f205SDaniel P. Berrange * QEMU generic buffers 388c5f205SDaniel P. Berrange * 488c5f205SDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc. 588c5f205SDaniel P. Berrange * 688c5f205SDaniel P. Berrange * This library is free software; you can redistribute it and/or 788c5f205SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 888c5f205SDaniel P. Berrange * License as published by the Free Software Foundation; either 988c5f205SDaniel P. Berrange * version 2 of the License, or (at your option) any later version. 1088c5f205SDaniel P. Berrange * 1188c5f205SDaniel P. Berrange * This library is distributed in the hope that it will be useful, 1288c5f205SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 1388c5f205SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1488c5f205SDaniel P. Berrange * Lesser General Public License for more details. 1588c5f205SDaniel P. Berrange * 1688c5f205SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 1788c5f205SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1888c5f205SDaniel P. Berrange * 1988c5f205SDaniel P. Berrange */ 2088c5f205SDaniel P. Berrange 2188c5f205SDaniel P. Berrange #include "qemu/buffer.h" 22d2b90718SGerd Hoffmann #include "trace.h" 2388c5f205SDaniel P. Berrange 245c10dbb7SPeter Lieven #define BUFFER_MIN_INIT_SIZE 4096 251ff36b5dSGerd Hoffmann #define BUFFER_MIN_SHRINK_SIZE 65536 265c10dbb7SPeter Lieven 27*fd952433SPeter Lieven static size_t buffer_req_size(Buffer *buffer, size_t len) 28*fd952433SPeter Lieven { 29*fd952433SPeter Lieven return MAX(BUFFER_MIN_INIT_SIZE, 30*fd952433SPeter Lieven pow2ceil(buffer->offset + len)); 31*fd952433SPeter Lieven } 32*fd952433SPeter Lieven 33*fd952433SPeter Lieven 34810082d1SGerd Hoffmann void buffer_init(Buffer *buffer, const char *name, ...) 35810082d1SGerd Hoffmann { 36810082d1SGerd Hoffmann va_list ap; 37810082d1SGerd Hoffmann 38810082d1SGerd Hoffmann va_start(ap, name); 39810082d1SGerd Hoffmann buffer->name = g_strdup_vprintf(name, ap); 40810082d1SGerd Hoffmann va_end(ap); 41810082d1SGerd Hoffmann } 42810082d1SGerd Hoffmann 431ff36b5dSGerd Hoffmann void buffer_shrink(Buffer *buffer) 441ff36b5dSGerd Hoffmann { 45d2b90718SGerd Hoffmann size_t old; 46d2b90718SGerd Hoffmann 471ff36b5dSGerd Hoffmann /* 481ff36b5dSGerd Hoffmann * Only shrink in case the used size is *much* smaller than the 491ff36b5dSGerd Hoffmann * capacity, to avoid bumping up & down the buffers all the time. 501ff36b5dSGerd Hoffmann * realloc() isn't exactly cheap ... 511ff36b5dSGerd Hoffmann */ 521ff36b5dSGerd Hoffmann if (buffer->offset < (buffer->capacity >> 3) && 531ff36b5dSGerd Hoffmann buffer->capacity > BUFFER_MIN_SHRINK_SIZE) { 541ff36b5dSGerd Hoffmann return; 551ff36b5dSGerd Hoffmann } 561ff36b5dSGerd Hoffmann 57d2b90718SGerd Hoffmann old = buffer->capacity; 581ff36b5dSGerd Hoffmann buffer->capacity = pow2ceil(buffer->offset); 591ff36b5dSGerd Hoffmann buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE); 601ff36b5dSGerd Hoffmann buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 61d2b90718SGerd Hoffmann trace_buffer_resize(buffer->name ?: "unnamed", 62d2b90718SGerd Hoffmann old, buffer->capacity); 631ff36b5dSGerd Hoffmann } 641ff36b5dSGerd Hoffmann 6588c5f205SDaniel P. Berrange void buffer_reserve(Buffer *buffer, size_t len) 6688c5f205SDaniel P. Berrange { 67d2b90718SGerd Hoffmann size_t old; 68d2b90718SGerd Hoffmann 6988c5f205SDaniel P. Berrange if ((buffer->capacity - buffer->offset) < len) { 70d2b90718SGerd Hoffmann old = buffer->capacity; 71*fd952433SPeter Lieven buffer->capacity = buffer_req_size(buffer, len); 7288c5f205SDaniel P. Berrange buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 73d2b90718SGerd Hoffmann trace_buffer_resize(buffer->name ?: "unnamed", 74d2b90718SGerd Hoffmann old, buffer->capacity); 7588c5f205SDaniel P. Berrange } 7688c5f205SDaniel P. Berrange } 7788c5f205SDaniel P. Berrange 7888c5f205SDaniel P. Berrange gboolean buffer_empty(Buffer *buffer) 7988c5f205SDaniel P. Berrange { 8088c5f205SDaniel P. Berrange return buffer->offset == 0; 8188c5f205SDaniel P. Berrange } 8288c5f205SDaniel P. Berrange 8388c5f205SDaniel P. Berrange uint8_t *buffer_end(Buffer *buffer) 8488c5f205SDaniel P. Berrange { 8588c5f205SDaniel P. Berrange return buffer->buffer + buffer->offset; 8688c5f205SDaniel P. Berrange } 8788c5f205SDaniel P. Berrange 8888c5f205SDaniel P. Berrange void buffer_reset(Buffer *buffer) 8988c5f205SDaniel P. Berrange { 9088c5f205SDaniel P. Berrange buffer->offset = 0; 9188c5f205SDaniel P. Berrange } 9288c5f205SDaniel P. Berrange 9388c5f205SDaniel P. Berrange void buffer_free(Buffer *buffer) 9488c5f205SDaniel P. Berrange { 95d2b90718SGerd Hoffmann trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity); 9688c5f205SDaniel P. Berrange g_free(buffer->buffer); 97810082d1SGerd Hoffmann g_free(buffer->name); 9888c5f205SDaniel P. Berrange buffer->offset = 0; 9988c5f205SDaniel P. Berrange buffer->capacity = 0; 10088c5f205SDaniel P. Berrange buffer->buffer = NULL; 101810082d1SGerd Hoffmann buffer->name = NULL; 10288c5f205SDaniel P. Berrange } 10388c5f205SDaniel P. Berrange 10488c5f205SDaniel P. Berrange void buffer_append(Buffer *buffer, const void *data, size_t len) 10588c5f205SDaniel P. Berrange { 10688c5f205SDaniel P. Berrange memcpy(buffer->buffer + buffer->offset, data, len); 10788c5f205SDaniel P. Berrange buffer->offset += len; 10888c5f205SDaniel P. Berrange } 10988c5f205SDaniel P. Berrange 11088c5f205SDaniel P. Berrange void buffer_advance(Buffer *buffer, size_t len) 11188c5f205SDaniel P. Berrange { 11288c5f205SDaniel P. Berrange memmove(buffer->buffer, buffer->buffer + len, 11388c5f205SDaniel P. Berrange (buffer->offset - len)); 11488c5f205SDaniel P. Berrange buffer->offset -= len; 11588c5f205SDaniel P. Berrange } 1164d1eb5fdSGerd Hoffmann 1174d1eb5fdSGerd Hoffmann void buffer_move_empty(Buffer *to, Buffer *from) 1184d1eb5fdSGerd Hoffmann { 119d2b90718SGerd Hoffmann trace_buffer_move_empty(to->name ?: "unnamed", 120d2b90718SGerd Hoffmann from->offset, 121d2b90718SGerd Hoffmann from->name ?: "unnamed"); 1224d1eb5fdSGerd Hoffmann assert(to->offset == 0); 1234d1eb5fdSGerd Hoffmann 1244d1eb5fdSGerd Hoffmann g_free(to->buffer); 1254d1eb5fdSGerd Hoffmann to->offset = from->offset; 1264d1eb5fdSGerd Hoffmann to->capacity = from->capacity; 1274d1eb5fdSGerd Hoffmann to->buffer = from->buffer; 1284d1eb5fdSGerd Hoffmann 1294d1eb5fdSGerd Hoffmann from->offset = 0; 1304d1eb5fdSGerd Hoffmann from->capacity = 0; 1314d1eb5fdSGerd Hoffmann from->buffer = NULL; 1324d1eb5fdSGerd Hoffmann } 133830a9583SGerd Hoffmann 134830a9583SGerd Hoffmann void buffer_move(Buffer *to, Buffer *from) 135830a9583SGerd Hoffmann { 136830a9583SGerd Hoffmann if (to->offset == 0) { 137830a9583SGerd Hoffmann buffer_move_empty(to, from); 138830a9583SGerd Hoffmann return; 139830a9583SGerd Hoffmann } 140830a9583SGerd Hoffmann 141d2b90718SGerd Hoffmann trace_buffer_move(to->name ?: "unnamed", 142d2b90718SGerd Hoffmann from->offset, 143d2b90718SGerd Hoffmann from->name ?: "unnamed"); 144830a9583SGerd Hoffmann buffer_reserve(to, from->offset); 145830a9583SGerd Hoffmann buffer_append(to, from->buffer, from->offset); 146830a9583SGerd Hoffmann 147830a9583SGerd Hoffmann g_free(from->buffer); 148830a9583SGerd Hoffmann from->offset = 0; 149830a9583SGerd Hoffmann from->capacity = 0; 150830a9583SGerd Hoffmann from->buffer = NULL; 151830a9583SGerd Hoffmann } 152