1/* 2 * MessagePack for C zero-copy buffer implementation 3 * 4 * Copyright (C) 2008-2009 FURUHASHI Sadayuki 5 * 6 * Distributed under the Boost Software License, Version 1.0. 7 * (See accompanying file LICENSE_1_0.txt or copy at 8 * http://www.boost.org/LICENSE_1_0.txt) 9 */ 10#include "msgpack/vrefbuffer.h" 11#include <stdlib.h> 12#include <string.h> 13 14#define MSGPACK_PACKER_MAX_BUFFER_SIZE 9 15 16struct msgpack_vrefbuffer_chunk { 17 struct msgpack_vrefbuffer_chunk* next; 18 /* data ... */ 19}; 20 21bool msgpack_vrefbuffer_init(msgpack_vrefbuffer* vbuf, 22 size_t ref_size, size_t chunk_size) 23{ 24 size_t nfirst; 25 struct iovec* array; 26 msgpack_vrefbuffer_chunk* chunk; 27 28 vbuf->chunk_size = chunk_size; 29 vbuf->ref_size = 30 ref_size > MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ? 31 ref_size : MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ; 32 33 nfirst = (sizeof(struct iovec) < 72/2) ? 34 72 / sizeof(struct iovec) : 8; 35 36 array = (struct iovec*)malloc( 37 sizeof(struct iovec) * nfirst); 38 if(array == NULL) { 39 return false; 40 } 41 42 vbuf->tail = array; 43 vbuf->end = array + nfirst; 44 vbuf->array = array; 45 46 chunk = (msgpack_vrefbuffer_chunk*)malloc( 47 sizeof(msgpack_vrefbuffer_chunk) + chunk_size); 48 if(chunk == NULL) { 49 free(array); 50 return false; 51 } 52 else { 53 msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; 54 55 ib->free = chunk_size; 56 ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); 57 ib->head = chunk; 58 chunk->next = NULL; 59 60 return true; 61 } 62} 63 64void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf) 65{ 66 msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head; 67 while(true) { 68 msgpack_vrefbuffer_chunk* n = c->next; 69 free(c); 70 if(n != NULL) { 71 c = n; 72 } else { 73 break; 74 } 75 } 76 free(vbuf->array); 77} 78 79void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vbuf) 80{ 81 msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head->next; 82 msgpack_vrefbuffer_chunk* n; 83 while(c != NULL) { 84 n = c->next; 85 free(c); 86 c = n; 87 } 88 89 { 90 msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; 91 msgpack_vrefbuffer_chunk* chunk = ib->head; 92 chunk->next = NULL; 93 ib->free = vbuf->chunk_size; 94 ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); 95 96 vbuf->tail = vbuf->array; 97 } 98} 99 100int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf, 101 const char* buf, size_t len) 102{ 103 if(vbuf->tail == vbuf->end) { 104 const size_t nused = (size_t)(vbuf->tail - vbuf->array); 105 const size_t nnext = nused * 2; 106 107 struct iovec* nvec = (struct iovec*)realloc( 108 vbuf->array, sizeof(struct iovec)*nnext); 109 if(nvec == NULL) { 110 return -1; 111 } 112 113 vbuf->array = nvec; 114 vbuf->end = nvec + nnext; 115 vbuf->tail = nvec + nused; 116 } 117 118 vbuf->tail->iov_base = (char*)buf; 119 vbuf->tail->iov_len = len; 120 ++vbuf->tail; 121 122 return 0; 123} 124 125int msgpack_vrefbuffer_append_copy(msgpack_vrefbuffer* vbuf, 126 const char* buf, size_t len) 127{ 128 msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; 129 char* m; 130 131 if(ib->free < len) { 132 msgpack_vrefbuffer_chunk* chunk; 133 size_t sz = vbuf->chunk_size; 134 if(sz < len) { 135 sz = len; 136 } 137 138 chunk = (msgpack_vrefbuffer_chunk*)malloc( 139 sizeof(msgpack_vrefbuffer_chunk) + sz); 140 if(chunk == NULL) { 141 return -1; 142 } 143 144 chunk->next = ib->head; 145 ib->head = chunk; 146 ib->free = sz; 147 ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); 148 } 149 150 m = ib->ptr; 151 memcpy(m, buf, len); 152 ib->free -= len; 153 ib->ptr += len; 154 155 if(vbuf->tail != vbuf->array && m == 156 (const char*)((vbuf->tail-1)->iov_base) + (vbuf->tail-1)->iov_len) { 157 (vbuf->tail-1)->iov_len += len; 158 return 0; 159 } else { 160 return msgpack_vrefbuffer_append_ref(vbuf, m, len); 161 } 162} 163 164int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to) 165{ 166 size_t sz = vbuf->chunk_size; 167 168 msgpack_vrefbuffer_chunk* empty = (msgpack_vrefbuffer_chunk*)malloc( 169 sizeof(msgpack_vrefbuffer_chunk) + sz); 170 if(empty == NULL) { 171 return -1; 172 } 173 174 empty->next = NULL; 175 176 { 177 const size_t nused = (size_t)(vbuf->tail - vbuf->array); 178 if(to->tail + nused < vbuf->end) { 179 struct iovec* nvec; 180 const size_t tosize = (size_t)(to->tail - to->array); 181 const size_t reqsize = nused + tosize; 182 size_t nnext = (size_t)(to->end - to->array) * 2; 183 while(nnext < reqsize) { 184 size_t tmp_nnext = nnext * 2; 185 if (tmp_nnext <= nnext) { 186 nnext = reqsize; 187 break; 188 } 189 nnext = tmp_nnext; 190 } 191 192 nvec = (struct iovec*)realloc( 193 to->array, sizeof(struct iovec)*nnext); 194 if(nvec == NULL) { 195 free(empty); 196 return -1; 197 } 198 199 to->array = nvec; 200 to->end = nvec + nnext; 201 to->tail = nvec + tosize; 202 } 203 204 memcpy(to->tail, vbuf->array, sizeof(struct iovec)*nused); 205 206 to->tail += nused; 207 vbuf->tail = vbuf->array; 208 209 { 210 msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; 211 msgpack_vrefbuffer_inner_buffer* const toib = &to->inner_buffer; 212 213 msgpack_vrefbuffer_chunk* last = ib->head; 214 while(last->next != NULL) { 215 last = last->next; 216 } 217 last->next = toib->head; 218 toib->head = ib->head; 219 220 if(toib->free < ib->free) { 221 toib->free = ib->free; 222 toib->ptr = ib->ptr; 223 } 224 225 ib->head = empty; 226 ib->free = sz; 227 ib->ptr = ((char*)empty) + sizeof(msgpack_vrefbuffer_chunk); 228 } 229 } 230 231 return 0; 232} 233