// Cancellation a buffer BSP_DECLARE(void) bsp_del_buffer(BSP_BUFFER *b) { if (b) { if (!B_ISCONST(b)) { if (_BSP_BUFFER_HIGHWATER < B_SIZE(b)) { // Buffer too big, just clean bsp_free(B_DATA(b)); B_DATA(b) = NULL; B_SIZE(b) = 0; B_LEN(b) = 0; B_NOW(b) = 0; } if (_BSP_BUFFER_UNSATURATION < (B_SIZE(b) - B_LEN(b))) { _shrink_buffer(b); } } else { B_DATA(b) = NULL; B_SIZE(b) = 0; } bsp_mempool_free(mp_buffer, (void *) b); } return; }
BSP_PRIVATE(int) _shrink_buffer(BSP_BUFFER *b) { if (b) { size_t new_size = 2 << (int) log2(B_LEN(b)); if (new_size < B_SIZE(b)) { char *new_data = bsp_realloc(B_DATA(b), new_size); if (new_data) { B_DATA(b) = new_data; B_SIZE(b) = new_size; return BSP_RTN_SUCCESS; } return BSP_RTN_ERR_MEMORY; } else { // May not shrink return BSP_RTN_SUCCESS; } } return BSP_RTN_ERR_GENERAL; }
void _free(void *ptr) { t_block *block; RETURN(!ptr || ptr > LAST_PTR() || ptr < FIRST_PTR()); block = GET_BLOCK(ptr); RETURN(block->isFree); block->isFree = true; if (block->parent == last && last->startBlock == last->lastBlock) { if (!(last = last->prev)) blocks = NULL; else last->next = NULL; brk(block->parent); } else if (block == block->parent->lastBlock) { if (!(block->parent->lastBlock = block->prev)) block->parent->startBlock = NULL; block->parent->freeSize += B_SIZE(block->size); } else if (block->parent->maxFreeSize < block->size) block->parent->maxFreeSize = block->size; }
// Read file descriptor to buffer BSP_DECLARE(ssize_t) bsp_buffer_io_read(BSP_BUFFER *b, int fd, size_t len) { if (!b || !fd || !len) { return 0; } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } // Try read ssize_t ret = read(fd, B_DATA(b) + B_LEN(b), len); if (ret > 0) { bsp_trace_message(BSP_TRACE_DEBUG, _tag_, "Read %d bytes from fd %d to buffer", (int) ret, fd); B_LEN(b) += ret; } return ret; }
// Append data to buffer BSP_DECLARE(size_t) bsp_buffer_append(BSP_BUFFER *b, const char *data, ssize_t len) { if (!b || !data || B_ISCONST(b)) { return 0; } if (len < 0) { len = strnlen(data, _BSP_MAX_UNSIZED_STRLEN); } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { // Space not enough, realloc buffer if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } memcpy(B_DATA(b) + B_LEN(b), data, len); B_LEN(b) = need; return len; }
// Set const data to en empty buffer BSP_DECLARE(size_t) bsp_buffer_set_const(BSP_BUFFER *b, const char *data, ssize_t len) { if (!b || !data || B_ISCONST(b)) { return 0; } if (len < 0) { len = strnlen(data, _BSP_MAX_UNSIZED_STRLEN); } if (B_DATA(b)) { bsp_free(B_DATA(b)); } B_DATA(b) = (char *) data; B_SIZE(b) = 0; B_LEN(b) = len; // Set to const b->is_const = BSP_TRUE; return len; }
void _free(void *ptr) { t_block *block; RETURN(!ptr || ptr > (void *)moreSpace(0, true)); block = GET_BLOCK(ptr); RETURN(block->isFree); mergeBlocks(&block); block->isFree = true; if (block == block->parent->lastBlock) { block->parent->lastBlock = block->prev; block->parent->freeSize += B_SIZE(block->size); if (!block->parent->next && block->parent->freeSize > PAGE_SIZE) { if (blocks != block->parent) { if (block->parent->prev) block->parent->prev->next = block->parent->next; brk(block->parent); } } } else if (block->parent->maxFreeSize < block->size) block->parent->maxFreeSize = block->size; }
void mergeBlocks(t_block **block) { if ((*block)->next && (*block)->next->isFree) { (*block)->size += B_SIZE((*block)->next->size); (*block)->next = (*block)->next->next; if ((*block)->next) (*block)->next->prev = (*block); } if ((*block)->prev && (*block)->prev->isFree) { (*block)->prev->size += B_SIZE((*block)->size); (*block)->prev->next = (*block)->next; if ((*block)->next) (*block)->next->prev = (*block)->prev; *block = (*block)->prev; } }
// Read all data from file descriptor to buffer BSP_DECLARE(ssize_t) bsp_buffer_io_read_all(BSP_BUFFER *b, int fd) { if (!b || !fd) { return 0; } ssize_t len = 0, tlen = 0; while (BSP_TRUE) { size_t need = B_LEN(b) + _BSP_FD_READ_ONCE; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error break; } } len = read(fd, B_DATA(b) + B_LEN(b), _BSP_FD_READ_ONCE); if (len < 0) { if (EINTR == errno || EWOULDBLOCK == errno || EAGAIN == errno) { // Break break; } } else if (0 == len) { // TCP FIN tlen = 0; break; } else { // Data already in buffer -_- tlen += len; B_LEN(b) += len; bsp_trace_message(BSP_TRACE_DEBUG, _tag_, "Read %d bytes from fd %d to buffer", (int) len, fd); if (len < _BSP_FD_READ_ONCE) { // All gone break; } } } return tlen; }
BSP_PRIVATE(int) _enlarge_buffer(BSP_BUFFER *b, size_t size) { if (b && size > B_SIZE(b)) { size_t new_size = 2 << bsp_log2(size); char *new_data = bsp_realloc(B_DATA(b), new_size); if (new_data) { B_DATA(b) = new_data; B_SIZE(b) = new_size; return BSP_RTN_SUCCESS; } else { bsp_trace_message(BSP_TRACE_CRITICAL, _tag_, "Enlarge buffer to %llu bytes failed", (unsigned long long int) new_size); } return BSP_RTN_ERR_MEMORY; } return BSP_RTN_ERR_GENERAL; }
// Fill seriate character to buffer BSP_DECLARE(size_t) bsp_buffer_fill(BSP_BUFFER *b, int code, size_t len) { if (!b || !len) { return 0; } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } memset(B_DATA(b) + B_LEN(b), code, len); B_LEN(b) = need; return len; }