⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 su_alloc.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
      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 + -