📄 su_alloc.c
字号:
sub->sub_ref++; UNLOCK(home); } else su_seterrno(EFAULT); return (void *)home;}/** Set destructor function. * * The destructor function is called after the reference count of a * #su_home_t object reaches zero or a home object is deinitialized, but * before any of the memory areas within the home object are freed. * * @since New in @VERSION_1_12_4. * Earlier versions had su_home_desctructor() (spelling). */int su_home_destructor(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;}#undef su_home_desctructor/** Set destructor function. * * @deprecated The su_home_destructor() was added in @VERSION_1_12_4. The * su_home_desctructor() is now defined as a macro expanding as * su_home_destructor(). If you want to compile an application as binary * compatible with earlier versions, you have to define su_home_desctructor * as itself, e.g., * @code * #define su_home_desctructor su_home_desctructor * #include <sofia-sip/su_alloc.h> * @endcode */int su_home_desctructor(su_home_t *home, void (*destructor)(void *)){ return su_home_destructor(home, destructor);}/**Unreference a su_home_t object. * * Decrements the reference count on home object and destroys and frees it * and the memory allocations using it if the reference count reaches 0. * * @param home memory pool object to be unreferenced * * @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 == REF_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 { int hauto = sub->sub_hauto; _su_home_deinit(home); if (!hauto) safefree(home); /* UNLOCK(home); */ return 1; }}/** Return reference count of home. */size_t su_home_refcount(su_home_t *home){ size_t count = 0; if (home) { su_block_t *sub = MEMLOCK(home); if (sub) count = sub->sub_ref; UNLOCK(home); } return count;}/**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, isize_t size){ su_home_t *home; assert(size >= sizeof (*home)); if (size < sizeof (*home)) return (void)(errno = EINVAL), NULL; else if (size > INT_MAX) return (void)(errno = ENOMEM), 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. * * 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, isize_t 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. * * 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 (!data) return; if (home) { 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 != REF_MAX); /* assert(sub->sub_ref > 0); */ sub->sub_ref = 0; /* Zap all references */ _su_home_deinit(subhome); }#if MEMCHECK != 0 memset(data, 0xaa, (size_t)allocation->sua_size);#endif memset(allocation, 0, sizeof (*allocation)); sub->sub_used--; if (preloaded) data = NULL; } UNLOCK(home); } safefree(data);}/** Check if pointer has been allocated through home. * * @param home pointer to a memory home * @param data pointer to a memory area possibly allocated though home */int su_home_check_alloc(su_home_t const *home, void const *data){ int retval = 0; if (home && data) { su_block_t const *sub = MEMLOCK(home); su_alloc_t *allocation = su_block_find(sub, data); retval = allocation != NULL; UNLOCK(home); } return retval;}/** Check home consistency. * * 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) { size_t 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. * * 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_unref(). * * @return This function returns a pointer to an #su_home_t object, or * NULL upon an error. */su_home_t *su_home_create(void){ return su_home_new(sizeof(su_home_t));}/** Destroy a home object * * Frees all memory blocks associated with a home object. Note that the home * object structure is not freed. * * @param home pointer to a home object * * @deprecated * su_home_destroy() is included for backwards compatibility only. Use * su_home_unref() instead of su_home_destroy(). */void su_home_destroy(su_home_t *home){ if (MEMLOCK(home)) { assert(home->suh_blocks); assert(home->suh_blocks->sub_ref == 1); if (!home->suh_blocks->sub_hauto) /* should warn user */; home->suh_blocks->sub_hauto = 1; _su_home_deinit(home); /* UNLOCK(home); */ }}/** Initialize an su_home_t struct. * * Initializes an su_home_t structure. It can be used when the home * structure is allocated from stack or when the home structure is part of * an another object. * * @param home pointer to home object * * @retval 0 when successful * @retval -1 upon an error. * * @sa SU_HOME_INIT(), su_home_deinit(), su_home_new(), su_home_clone() * * @bug * Prior to @VERSION_1_12_8 the su_home_t structure should have been * initialized with SU_HOME_INIT() or otherwise zeroed before calling * su_home_init(). */int su_home_init(su_home_t *home){ su_block_t *sub; if (home == NULL) return -1; home->suh_blocks = sub = su_hash_alloc(SUB_N); home->suh_lock = NULL; if (!sub) return -1; return 0;}/** Internal deinitialization */staticvoid _su_home_deinit(su_home_t *home){ if (home->suh_blocks) { size_t 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; safefree(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; if (home->suh_lock) _su_home_destroy_mutexes(home->suh_lock); } home->suh_lock = NULL;}/** Free memory blocks allocated through home. * * Frees the memory blocks associated with the home object allocated. It * does not free the home object itself. Use su_home_unref() to free the * home object. * * @param home pointer to home object * * @sa su_home_init() */void su_home_deinit(su_home_t *home){ if (MEMLOCK(home)) { assert(home->suh_blocks); assert(home->suh_blocks->sub_ref == 1); assert(home->suh_blocks->sub_hauto); _su_home_deinit(home); /* UNLOCK(home); */ }}/**Move allocations from a su_home_t object to another. * * 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){ size_t 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); d = d2; } if (s->sub_used) { n = s->sub_n; for (i = 0; i < n; i++) if (s->sub_nodes[i].sua_data) { su_block_add(d, s->sub_nodes[i].sua_data)[0] = s->sub_nodes[i]; } s->sub_used = 0; memset(s->sub_nodes, 0, n * sizeof (s->sub_nodes[0])); } if (s->sub_stats) { /* XXX */ } } UNLOCK(dst); UNLOCK(src); } else { s = MEMLOCK(src); if (s && s->sub_used) { s->sub_used = 0; memset(s->sub_nodes, 0, s->sub_n * sizeof (s->sub_nodes[0])); } UNLOCK(src); } return 0;}/** Preload a memory home. * * The function su_home_preload() preloads a memory home. */void su_home_preload(su_home_t *home, isize_t n, isize_t isize){ su_block_t *sub; if (home == NULL) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -