📄 su_alloc.c
字号:
if (home->suh_blocks == NULL) su_home_init(home); sub = MEMLOCK(home); if (!sub->sub_preload) { size_t size; void *preload; size = n * ALIGN(isize); if (size > 65535) /* We have 16 bits... */ size = 65535 & (ALIGNMENT - 1); preload = malloc(size); home->suh_blocks->sub_preload = preload; home->suh_blocks->sub_prsize = (unsigned)size; } UNLOCK(home);}/** Preload a memory home from stack. * * Initializes a memory home using an area allocated from stack. Poor man's * alloca(). */su_home_t *su_home_auto(void *area, isize_t size){ su_home_t *home; su_block_t *sub; size_t homesize = ALIGN(sizeof *home); size_t subsize = ALIGN(offsetof(su_block_t, sub_nodes[SUB_N_AUTO])); size_t prepsize; char *p = area; prepsize = homesize + subsize + (ALIGN((intptr_t)p) - (intptr_t)p); if (area == NULL || size < prepsize) return NULL; if (size > INT_MAX) size = INT_MAX; home = memset(p, 0, homesize); home->suh_size = (int)size; sub = memset(p + homesize, 0, subsize); home->suh_blocks = sub; if (size > prepsize + 65535) size = prepsize + 65535; sub->sub_n = SUB_N_AUTO; sub->sub_ref = 1; sub->sub_preload = p + prepsize; sub->sub_prsize = (unsigned)(size - prepsize); sub->sub_hauto = 1; sub->sub_auto = 1; sub->sub_preauto = 1; sub->sub_auto_all = 1; return home;}/** Reallocate a memory block. * * Allocates a memory block of @a size bytes. * It copies the old block contents to the new block and frees the old * block. * * If @a home is NULL, this function behaves exactly like realloc(). * * @param home pointer to memory pool object * @param data pointer to old memory block * @param size size of the memory block to be allocated * * @return * A pointer to the allocated memory block or * NULL if an error occurred. */void *su_realloc(su_home_t *home, void *data, isize_t size){ void *ndata; su_alloc_t *sua; su_block_t *sub; size_t p; size_t term = 0 - size; if (!home) return realloc(data, size); if (size == 0) { if (data) su_free(home, data); return NULL; } sub = MEMLOCK(home); if (!data) { data = sub_alloc(home, sub, size, 0); UNLOCK(home); return data; } sua = su_block_find(sub, data); if (!su_alloc_check(sub, sua)) return UNLOCK(home); assert(!sua->sua_home); if (sua->sua_home) return UNLOCK(home); if (!su_is_preloaded(sub, data)) { ndata = realloc(data, size + MEMCHECK_EXTRA); if (ndata) { if (sub->sub_stats) { su_home_stats_free(sub, data, 0, sua->sua_size); su_home_stats_alloc(sub, data, 0, size, 1); }#if MEMCHECK_EXTRA memcpy((char *)ndata + size, &term, sizeof (term));#else (void)term;#endif memset(sua, 0, sizeof *sua); sub->sub_used--; su_block_add(sub, ndata)->sua_size = (unsigned)size; } UNLOCK(home); return ndata; } p = (char *)data - home->suh_blocks->sub_preload; p += sua->sua_size + MEMCHECK_EXTRA; p = ALIGN(p); if (p == sub->sub_prused) { size_t p2 = (char *)data - sub->sub_preload + size + MEMCHECK_EXTRA; p2 = ALIGN(p2); if (p2 <= sub->sub_prsize) { /* Extend/reduce existing preload */ if (sub->sub_stats) { su_home_stats_free(sub, data, data, sua->sua_size); su_home_stats_alloc(sub, data, data, size, 0); } sub->sub_prused = (unsigned)p2; sua->sua_size = (unsigned)size;#if MEMCHECK_EXTRA memcpy((char *)data + size, &term, sizeof (term));#endif UNLOCK(home); return data; } } else if (size < (size_t)sua->sua_size) { /* Reduce existing preload */ if (sub->sub_stats) { su_home_stats_free(sub, data, data, sua->sua_size); su_home_stats_alloc(sub, data, data, size, 0); }#if MEMCHECK_EXTRA memcpy((char *)data + size, &term, sizeof (term));#endif sua->sua_size = (unsigned)size; UNLOCK(home); return data; } ndata = malloc(size + MEMCHECK_EXTRA); if (ndata) { if (p == sub->sub_prused) { /* Free preload */ sub->sub_prused = (char *)data - home->suh_blocks->sub_preload; if (sub->sub_stats) su_home_stats_free(sub, data, data, sua->sua_size); } memcpy(ndata, data, (size_t)sua->sua_size < size ? (size_t)sua->sua_size : size);#if MEMCHECK_EXTRA memcpy((char *)ndata + size, &term, sizeof (term));#endif if (sub->sub_stats) su_home_stats_alloc(sub, data, 0, size, 1); memset(sua, 0, sizeof *sua); sub->sub_used--; su_block_add(sub, ndata)->sua_size = (unsigned)size; } UNLOCK(home); return ndata;}/**Check if a memory block has been allocated from the @a home. * * Check if the given memory block has been allocated from the home. * * @param home pointer to memory pool object * @param memory ponter to memory block * * @retval 1 if @a memory has been allocated from @a home. * @retval 0 otherwise * * @since New in @VERSION_1_12_4. */int su_in_home(su_home_t *home, void const *memory){ su_alloc_t *sua; su_block_t *sub; int retval = 0; if (!home || !memory) return 0; sub = MEMLOCK(home); if (sub) { sua = su_block_find(sub, memory); retval = su_alloc_check(sub, sua); UNLOCK(home); } return retval;}/**Allocate and zero a memory block. * * Allocates a memory block with a given size from * given memory home @a home and zeroes the allocated block. * * @param home pointer to memory pool object * @param size size of the memory block * * @note The memory home pointer @a home may be @c NULL. In that case, the * allocated memory block is not associated with any memory home, and it * must be freed by calling su_free() or free(). * * @return * The function su_zalloc() returns a pointer to the allocated memory block, * or NULL upon an error. */void *su_zalloc(su_home_t *home, isize_t size){ void *data; assert (size >= 0); if (home) { data = sub_alloc(home, MEMLOCK(home), size, 1); UNLOCK(home); } else data = calloc(1, size); return data;}/** Allocate a structure * * Allocates a structure with a given size, zeros * it, and initializes the size field to the given size. The size field * is an int at the beginning of the structure. Note that it has type of int. * * @param home pointer to memory pool object * @param size size of the structure * * @par Example * The structure is defined and allocated as follows: * @code * struct test { * int tst_size; * char *tst_name; * void *tst_ptr[3]; * }; * * struct test *t; * ... * t = su_salloc(home, sizeof (*t)); * assert(t && t->t_size == sizeof (*t)); * * @endcode * After calling su_salloc() we get a pointer t to a struct test, * initialized to zero except the tst_size field, which is initialized to * sizeof (*t). * * @return A pointer to the allocated structure, or NULL upon an error. */void *su_salloc(su_home_t *home, isize_t size){ struct { int size; } *retval; if (size < sizeof (*retval)) size = sizeof (*retval); if (size > INT_MAX) return (void)(errno = ENOMEM), NULL; if (home) { retval = sub_alloc(home, MEMLOCK(home), size, 1); UNLOCK(home); } else retval = calloc(1, size); if (retval) retval->size = (int)size; return retval;}/** Check if a memory home is threadsafe */int su_home_is_threadsafe(su_home_t const *home){ return home && home->suh_lock;}/** Increase refcount and obtain exclusive lock on home. * * @note The #su_home_t structure must be created with su_home_new() or * su_home_clone(), or initialized with su_home_init() before using this * function. * * In order to enable actual locking, use su_home_threadsafe(), too. * Otherwise the su_home_mutex_lock() will just increase the reference * count. */int su_home_mutex_lock(su_home_t *home){ int error; if (home == NULL) return su_seterrno(EFAULT); if (home->suh_blocks == NULL || !su_home_ref(home)) return su_seterrno(EINVAL); /* Uninitialized home */ if (!home->suh_lock) return 0; /* No-op */ error = _su_home_mutex_locker(home->suh_lock); if (error) return su_seterrno(error); return 0;}/** Release exclusive lock on home and decrease refcount (if home is threadsafe). * * @sa su_home_unlock(). */int su_home_mutex_unlock(su_home_t *home){ if (home == NULL) return su_seterrno(EFAULT); if (home->suh_lock) { int error = _su_home_mutex_unlocker(home->suh_lock); if (error) return su_seterrno(error); } if (home->suh_blocks == NULL) return su_seterrno(EINVAL), -1; /* Uninitialized home */ su_home_unref(home); return 0;}/** Obtain exclusive lock on home without increasing refcount. * * Unless su_home_threadsafe() has been used to intialize locking on home * object the function just returns -1. * * @return 0 if successful, -1 if not threadsafe, error code otherwise. * * @sa su_home_mutex_lock(), su_home_unlock(), su_home_trylock(). * * @NEW_1_12_8 */int su_home_lock(su_home_t *home){ if (home == NULL) return EFAULT; if (home->suh_lock == NULL) return -1; /* No-op */ return _su_home_mutex_locker(home->suh_lock);}/** Try to obtain exclusive lock on home without increasing refcount. * * @return 0 if successful, -1 if not threadsafe, * EBUSY if already locked, error code otherwise. * * @sa su_home_lock(), su_home_unlock(). * * @NEW_1_12_8 */int su_home_trylock(su_home_t *home){ if (home == NULL) return EFAULT; if (home->suh_lock == NULL) return -1; /* No-op */ return _su_home_mutex_trylocker(home->suh_lock);}/** Release exclusive lock on home. * * Release lock without decreasing refcount. * * @return 0 if successful, -1 if not threadsafe, error code otherwise. * * @sa su_home_lock(), su_home_trylock(), su_home_mutex_unlock(). * * @NEW_1_12_8 */int su_home_unlock(su_home_t *home){ if (home == NULL) return EFAULT; if (home->suh_lock == NULL) return -1; /* No-op */ return _su_home_mutex_unlocker(home->suh_lock);}/** Initialize statistics structure */void su_home_init_stats(su_home_t *home){ su_block_t *sub; size_t size; if (home == NULL) return; sub = home->suh_blocks; if (!sub) sub = home->suh_blocks = su_hash_alloc(SUB_N); if (!sub) return; if (!sub->sub_stats) { size = sizeof (*sub->sub_stats); sub->sub_stats = malloc(size); if (!sub->sub_stats) return; } else size = sub->sub_stats->hs_size; memset(sub->sub_stats, 0, size); sub->sub_stats->hs_size = (int)size; sub->sub_stats->hs_blocksize = sub->sub_n;}/** Retrieve statistics from memory home. */void su_home_get_stats(su_home_t *home, int include_clones, su_home_stat_t *hs, isize_t size){ su_block_t *sub; if (hs == NULL || size < (sizeof hs->hs_size)) return; memset((void *)hs, 0, size); sub = MEMLOCK(home); if (sub && sub->sub_stats) { int sub_size = sub->sub_stats->hs_size; if (sub_size > (int)size) sub_size = (int)size; sub->sub_stats->hs_preload.hsp_size = sub->sub_prsize; sub->sub_stats->hs_preload.hsp_used = sub->sub_prused; memcpy(hs, sub->sub_stats, sub_size); hs->hs_size = sub_size; } UNLOCK(home);}static void su_home_stats_alloc(su_block_t *sub, void *p, void *preload, size_t size, int zero){ su_home_stat_t *hs = sub->sub_stats; size_t rsize = ALIGN(size); hs->hs_rehash += (sub->sub_n != hs->hs_blocksize); hs->hs_blocksize = sub->sub_n; hs->hs_clones += zero > 1; if (preload) { hs->hs_allocs.hsa_preload++; return; } hs->hs_allocs.hsa_number++; hs->hs_allocs.hsa_bytes += size; hs->hs_allocs.hsa_rbytes += rsize; if (hs->hs_allocs.hsa_rbytes > hs->hs_allocs.hsa_maxrbytes) hs->hs_allocs.hsa_maxrbytes = hs->hs_allocs.hsa_rbytes; hs->hs_blocks.hsb_number++; hs->hs_blocks.hsb_bytes += size; hs->hs_blocks.hsb_rbytes += rsize;}static void su_home_stats_free(su_block_t *sub, void *p, void *preload, unsigned size){ su_home_stat_t *hs = sub->sub_stats; size_t rsize = ALIGN(size); if (preload) { hs->hs_frees.hsf_preload++; return; } hs->hs_frees.hsf_number++; hs->hs_frees.hsf_bytes += size; hs->hs_frees.hsf_rbytes += rsize; hs->hs_blocks.hsb_number--; hs->hs_blocks.hsb_bytes -= size; hs->hs_blocks.hsb_rbytes -= rsize;}void su_home_stat_add(su_home_stat_t total[1], su_home_stat_t const hs[1]){ total->hs_clones += hs->hs_clones; total->hs_rehash += hs->hs_rehash; if (total->hs_blocksize < hs->hs_blocksize) total->hs_blocksize = hs->hs_blocksize; total->hs_allocs.hsa_number += hs->hs_allocs.hsa_number; total->hs_allocs.hsa_bytes += hs->hs_allocs.hsa_bytes; total->hs_allocs.hsa_rbytes += hs->hs_allocs.hsa_rbytes; total->hs_allocs.hsa_maxrbytes += hs->hs_allocs.hsa_maxrbytes; total->hs_frees.hsf_number += hs->hs_frees.hsf_number; total->hs_frees.hsf_bytes += hs->hs_frees.hsf_bytes; total->hs_frees.hsf_rbytes += hs->hs_frees.hsf_rbytes; total->hs_blocks.hsb_number += hs->hs_blocks.hsb_number; total->hs_blocks.hsb_bytes += hs->hs_blocks.hsb_bytes; total->hs_blocks.hsb_rbytes += hs->hs_blocks.hsb_rbytes;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -