// 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; }
// 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; }
/* Mempool freer */ BSP_PRIVATE(void) _buffer_free(void *item) { BSP_BUFFER *b = (BSP_BUFFER *) item; if (b) { if (B_DATA(b) && !B_ISCONST(b)) { bsp_free(B_DATA(b)); } bsp_free(b); } return; }
// 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; }
void print_block_info(struct block *ptr) { struct block *b = ptr; printf("pos = %p, ", ptr); printf("state = %u, k_size = %lu\n", b->state, b->k_size); printf("data =\n"); LOG("CHECK pow=%lu, bsize=%lu\n", pow2(b->k_size), B_SIZE); dump_data(B_DATA(ptr), B_DATA_SIZE(ptr)); printf("\n"); }
static int init_pool() { /* Get current heap break address */ if ((mp.base_addr = sbrk(0)) == (void *) -1) { perror("sbrk"); return -1; } /* First block on heap will contain 'avail' array */ /* First-block initialization for the avail array containing heads of lists with available memory, it has length of (max pool size + 1) */ /* Logarithm of the space, we can adress */ mp.max_size = CHAR_BIT*sizeof(void *); /* We want to have available pointers to all the memory we can adress */ mp.init_size = get_pow(B_SIZE + (mp.max_size + 1)*(sizeof(struct avail_head))); if (sbrk(pow2(mp.init_size)) == (void *) -1) { perror("sbrk"); return -1; } mp.pool_size = mp.init_size; /* Initialize the first block, which will contain 'avail' array */ struct block *first_b; first_b = (struct block *) mp.base_addr; first_b->state = USED; first_b->k_size = mp.init_size; LOG("--## POOL INIT INFO ##--\n"); LOG("## Heap memory begins at base_addr = %p\n", mp.base_addr); LOG("## Size of the first block is init_size = 2^%lu = %luB\n", mp.init_size, pow2(mp.init_size)); LOG("## Maximum pool size is max_size = 2^%lu = %luB\n", mp.max_size, -1L); /* Init 'avail', array of cyclic linked list */ mp.avail = (struct avail_head *) B_DATA(first_b); int i; for (i=0; i <= mp.max_size; i++) { mp.avail[i].next = (struct block *) &mp.avail[i]; mp.avail[i].prev = (struct block *) &mp.avail[i]; } first_b->prev = (struct block *) &mp.avail[first_b->k_size]; first_b->next = (struct block *) &mp.avail[first_b->k_size]; //TODO WIP int err; if ((err = pthread_create(&cleaner_th, NULL, cleaning_work, NULL)) != 0) { printf("pthread_create() ERROR %d!\n", err); return -1; } if ((err = pthread_detach(cleaner_th)) != 0) { printf("pthread_detach() ERROR %d!\n", err); return -1; } //TODO WIP LOG("--## END OF POOL INIT INFO ##--\n"); return 0; }
// 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; }
static void *alloc(unsigned long size_pow, enum m_state state) { /* Pool not initialized */ if (mp.base_addr == NULL) { /* Try to initialize it */ if (init_pool() == -1) { errno = ENOMEM; return NULL; } } // LOG("BEFORE ALLOC\n"); // print_avail_map(); /* Size in power of 2, which needs to be reserved */ //LOG("Request for 2^%lu = %luB\n", size_pow, pow2(size_pow)); /* Size of the first suitable block which is available (in pow of 2) */ unsigned long j; /* Find the value of 'j' in available memory space if possible */ //LOG("--## FINDING J ##--\n"); for (j=size_pow; j < mp.pool_size; j++) { if (!list_empty(&mp.avail[j])) { break; } //LOG("j=%lu not suitable\n", j); } /* Do we need to enlarge the pool? - by making buddy for existing largest block */ //LOG("--## ENLARGING ##--\n"); while (list_empty(&mp.avail[j])) { //LOG("j=%lu <= pool_size=%lu <= max=%lu\n", j, mp.pool_size, mp.max_size); /* Cannot adress this amount of memory */ if (get_pow((unsigned long)mp.base_addr) + size_pow >= mp.max_size) { //TODO ktery pouzit? //if (mp.max_size >= mp.max_size) { LOG("Maximum size reached!\n"); errno = ENOMEM; return NULL; } //LOG("Enlarging the pool.\n"); void *new_addr; if ((new_addr = sbrk(pow2(mp.pool_size))) == (void *)-1) { LOG("sbrk pool-enlarge error!\n"); errno = ENOMEM; return NULL; } //TODO bez prepsani zpusobuje neporadek s valgrindem //memset(new_addr, 0, pow2(mp.pool_size)); /* Pool was enlarged, we have twice as much space */ mp.pool_size++; /* New memory block, buddy for previous block, will live in this space */ //LOG("new_addr = %p\n", new_addr); struct block *nb = (struct block *) new_addr; nb->state = FREE; nb->k_size = mp.pool_size - 1; //LOG("k_size = %lu\n", nb->k_size); /* Avail array must be edited, we've got new free block of size 2^(nb->k_size) */ struct block *p; p = mp.avail[nb->k_size].next; //LOG("p point %p head to %p\n", p, &mp.avail[nb->k_size]); nb->next = p; p->prev = nb; nb->prev = (struct block *) &mp.avail[nb->k_size]; mp.avail[nb->k_size].next = nb; } /* We now have the 'j' value set */ //LOG("--## REMOVING BLOCK FROM AVAIL ARRAY ##--\n"); /* Remove this block from avail array */ struct block *l, *p; l = mp.avail[j].prev; //LOG("L position = %p\n", l); p = l->prev; mp.avail[j].prev = p; p->next = (struct block *) &mp.avail[j]; enum m_state block_state = l->state; l->state = USED; /* Now we need to divide the block if space in it is too large */ //LOG("--## DIVIDING BLOCK ##--\n"); while (j != size_pow) { //LOG("divination for j=%lu\n", j); j--; p = (struct block *)((unsigned long)l + pow2(j)); //LOG("pointering to %p\n", p); p->state = FREE; p->k_size = j; p->prev = (struct block *) &mp.avail[j]; p->next = (struct block *) &mp.avail[j]; /* Add this block into avail array */ mp.avail[j].prev = p; mp.avail[j].next = p; } l->k_size = size_pow; /* Does the memory need to be cleared? */ if (state == ZERO && block_state != ZERO) { memset(B_DATA(l), 0, B_DATA_SIZE(l)); } // LOG("AFTER ALLOC\n"); // print_avail_map(); // LOG("\n"); return B_DATA(l); }