📄 su_alloc.c
字号:
/**Create a new su_home_t object. * * Create a home object used to collect multiple memory allocations under * one handle. The memory allocations made using this home object is freed * either when this home is destroyed. * * @param size size of home object * * The memory home object allocated with su_home_new() can be reclaimed with * su_home_unref(). * * @return * This function returns a pointer to an su_home_t object, or NULL upon * an error. */void *su_home_new(int size){ su_home_t *home; assert(size >= sizeof (*home)); if (size < sizeof (*home)) return NULL; home = calloc(1, size); if (home) { home->suh_size = size; home->suh_blocks = su_hash_alloc(SUB_N); if (home->suh_blocks) home->suh_blocks->sub_ref = 1; else free(home), home = NULL; } return home;}/** Create a new reference to a home object. */void *su_home_ref(su_home_t const *home){ if (home) { su_block_t *sub = MEMLOCK(home); if (sub == NULL || sub->sub_ref == 0) { assert(sub && sub->sub_ref != 0); UNLOCK(home); return NULL; } if (sub->sub_ref != UINT_MAX) sub->sub_ref++; UNLOCK(home); } else su_seterrno(EFAULT); return (void *)home;}/** Set destructor function */SU_DLL int su_home_desctructor(su_home_t *home, void (*destructor)(void *)){ int retval = -1; if (home) { su_block_t *sub = MEMLOCK(home); if (sub && sub->sub_destructor == NULL) { sub->sub_destructor = destructor; retval = 0; } UNLOCK(home); } else su_seterrno(EFAULT); return retval;}/**Unreference a su_home_t object. * * The function su_home_unref() decrements the reference count on a home * object and destroys and frees it and the memory allocations using it. * * @param home memory pool object to be unreferences * * The function return values is * * @retval 1 if object was freed * @retval 0 if object is still alive */int su_home_unref(su_home_t *home){ su_block_t *sub; if (home == NULL) return 0; sub = MEMLOCK(home); if (sub == NULL) { /* Xyzzy */ return 0; } else if (sub->sub_ref == UINT_MAX) { UNLOCK(home); return 0; } else if (--sub->sub_ref > 0) { UNLOCK(home); return 0; } else if (sub->sub_parent) { su_home_t *parent = sub->sub_parent; UNLOCK(home); su_free(parent, home); return 1; } else { _su_home_deinit(home); free(home); /* UNLOCK(home); */ return 1; }}/**Clone a su_home_t object. * * Clone a secondary home object used to collect multiple memoryf * allocations under one handle. The memory is freed either when the cloned * home is destroyed or when the parent home is destroyed. * * An independent * home object is created if NULL is passed as @a parent argument. * * @param parent a parent object (may be NULL) * @param size size of home object * * The memory home object allocated with su_home_clone() can be freed with * su_home_unref(). * * @return * This function returns a pointer to an su_home_t object, or NULL upon * an error. */void *su_home_clone(su_home_t *parent, int size){ su_home_t *home; assert(size >= sizeof (*home)); if (size < sizeof (*home)) return NULL; if (parent) { su_block_t *sub = MEMLOCK(parent); home = sub_alloc(parent, sub, size, 2); UNLOCK(parent); } else { home = su_home_new(size); } return home;}/** Return true if home is a clone. */int su_home_has_parent(su_home_t const *home){ return home && !home->suh_lock && home->suh_blocks && home->suh_blocks->sub_parent;}/** Allocate a memory block. * * The function su_alloc() allocates a memory block of a given @a size. * * If @a home is NULL, this function behaves exactly like malloc(). * * @param home pointer to home object * @param size size of the memory block to be allocated * * @return * This function returns a pointer to the allocated memory block or * NULL if an error occurred. */void *su_alloc(su_home_t *home, int size){ void *data; if (home) { data = sub_alloc(home, MEMLOCK(home), size, 0); UNLOCK(home); } else data = malloc(size); return data;}/**Free a memory block. * * The function su_free() frees a single memory block. The @a home must be * the owner of the memory block (usually the memory home used to allocate * the memory block, or NULL if no home was used). * * @param home pointer to home object * @param data pointer to the memory block to be freed */void su_free(su_home_t *home, void *data){ if (home && data) { su_alloc_t *allocation; su_block_t *sub = MEMLOCK(home); assert(sub); allocation = su_block_find(sub, data); assert(allocation); if (su_alloc_check(sub, allocation)) { void *preloaded = NULL; /* Is this preloaded data? */ if (su_is_preloaded(sub, data)) preloaded = data; if (sub->sub_stats) su_home_stats_free(sub, data, preloaded, allocation->sua_size); if (allocation->sua_home) { su_home_t *subhome = data; su_block_t *sub = MEMLOCK(subhome); assert(sub->sub_ref != UINT_MAX); /* assert(sub->sub_ref > 0); */ sub->sub_ref = 0; /* Zap all references */ _su_home_deinit(subhome); }#if MEMCHECK != 0 memset(data, 0xaa, allocation->sua_size);#endif memset(allocation, 0, sizeof (*allocation)); sub->sub_used--; if (preloaded) data = NULL; } UNLOCK(home); } free(data);}/** Check home consistency. * * The function su_home_check() ensures that the home structure and all * memory blocks allocated through it are consistent. It can be used to * catch memory allocation and usage errors. * * @param home Pointer to a memory home. */void su_home_check(su_home_t const *home){#if MEMCHECK != 0 su_block_t const *b = MEMLOCK(home); su_home_check_blocks(b); UNLOCK(home);#endif}/** Check home blocks. */staticvoid su_home_check_blocks(su_block_t const *b){#if MEMCHECK != 0 if (b) { unsigned i, used; assert(b->sub_used <= b->sub_n); for (i = 0, used = 0; i < b->sub_n; i++) if (b->sub_nodes[i].sua_data) { su_alloc_check(b, &b->sub_nodes[i]), used++; if (b->sub_nodes[i].sua_home) su_home_check((su_home_t *)b->sub_nodes[i].sua_data); } assert(used == b->sub_used); }#endif}/** * Create an su_home_t object. * * The function su_home_create() creates a home object. A home object is * used to collect multiple memory allocations, so that they all can be * freed by calling su_home_destroy(). * * @return This function returns a pointer to an @c su_home_t object, or @c * NULL upon an error. * * @deprecated * Use su_home_clone() instead of su_home_create(). */su_home_t *su_home_create(void){ su_home_t *home = su_salloc(NULL, sizeof (*home)); if (home) { su_home_init(home); } return home;}/** Deinitialize a home object * * The function su_home_destroy() frees a home object, and all memory * blocks associated with it. * * @param home pointer to a home object * * @deprecated * Use su_home_deinit() instead of su_home_destroy(). */void su_home_destroy(su_home_t *home){ su_home_deinit(home); /* free(home); - what if this is cloned one? */}/** Initialize an su_home_t object. * * The function su_home_init() initializes an object derived from su_home_t. * * @param home pointer to home object * * @return * The function su_home_init() returns 0 when successful, * or -1 upon an error. */int su_home_init(su_home_t *home){ if (home == NULL) return -1; home->suh_blocks = su_hash_alloc(SUB_N); return 0;}/** Internal deinitialization */staticvoid _su_home_deinit(su_home_t *home){ if (home->suh_blocks) { unsigned i; su_block_t *b; if (home->suh_blocks->sub_destructor) { void (*destructor)(void *) = home->suh_blocks->sub_destructor; home->suh_blocks->sub_destructor = NULL; destructor(home); } b = home->suh_blocks; su_home_check_blocks(b); for (i = 0; i < b->sub_n; i++) { if (b->sub_nodes[i].sua_data) { if (b->sub_nodes[i].sua_home) { su_home_t *subhome = b->sub_nodes[i].sua_data; su_block_t *subb = MEMLOCK(subhome); assert(subb); assert(subb->sub_ref >= 1);#if 0 if (subb->sub_ref > 0) SU_DEBUG_7(("su_home_unref: subhome %p with destructor %p has still %u refs\n", subhome, subb->sub_destructor, subb->sub_ref));#endif subb->sub_ref = 0; /* zap them all */ _su_home_deinit(subhome); } else if (su_is_preloaded(b, b->sub_nodes[i].sua_data)) continue; free(b->sub_nodes[i].sua_data); } } if (b->sub_preload && !b->sub_preauto) free(b->sub_preload); if (b->sub_stats) free(b->sub_stats); if (!b->sub_auto) free(b); home->suh_blocks = NULL; } home->suh_lock = NULL;}/** Free memory blocks allocated through home. * * The function @c su_home_deinit() frees the memory blocks associated with * the home object. * * @param home pointer to home object */void su_home_deinit(su_home_t *home){ if (MEMLOCK(home)) { assert(home->suh_blocks && home->suh_blocks->sub_ref == 0); _su_home_deinit(home); /* UNLOCK(home); */ }}/**Move allocations from a su_home_t object to another. * * The function su_home_move() moves allocations made through the @a src * home object under the @a dst home object. It is handy, for example, if an * operation allocates some number of blocks that should be freed upon an * error. It uses a temporary home and moves the blocks from temporary to a * proper home when successful, but frees the temporary home upon an error. * * If @a src has destructor, it is called before starting to move. * * @param dst destination home * @param src source home * * @retval 0 if succesful * @retval -1 upon an error */int su_home_move(su_home_t *dst, su_home_t *src){ unsigned i, n, n2, used; su_block_t *s, *d, *d2; if (src == NULL || dst == src) return 0; if (dst) { s = MEMLOCK(src); d = MEMLOCK(dst); if (s && s->sub_n) { if (s->sub_destructor) { void (*destructor)(void *) = s->sub_destructor; s->sub_destructor = NULL; destructor(src); } if (d) used = s->sub_used + d->sub_used; else used = s->sub_used; if ((used && d == NULL) || 3 * used > 2 * d->sub_n) { if (d) for (n = n2 = d->sub_n; 3 * used > 2 * n2; n2 = 4 * n2 + 3) ; else n = 0, n2 = s->sub_n; if (!(d2 = su_hash_alloc(n2))) { UNLOCK(dst); UNLOCK(src); return -1; } dst->suh_blocks = d2; for (i = 0; i < n; i++) if (d->sub_nodes[i].sua_data) su_block_add(d2, d->sub_nodes[i].sua_data)[0] = d->sub_nodes[i]; if (d) { d2->sub_parent = d->sub_parent; d2->sub_ref = d->sub_ref; d2->sub_preload = d->sub_preload; d2->sub_prsize = d->sub_prsize; d2->sub_prused = d->sub_prused; d2->sub_preauto = d->sub_preauto; d2->sub_stats = d->sub_stats; } if (d && !d->sub_auto) free(d);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -