aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/jabber/pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/jabber/pool.c')
-rw-r--r--protocols/jabber/pool.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/protocols/jabber/pool.c b/protocols/jabber/pool.c
new file mode 100644
index 00000000..8b88d747
--- /dev/null
+++ b/protocols/jabber/pool.c
@@ -0,0 +1,247 @@
+/* --------------------------------------------------------------------------
+ *
+ * License
+ *
+ * The contents of this file are subject to the Jabber Open Source License
+ * Version 1.0 (the "JOSL"). You may not copy or use this file, in either
+ * source code or executable form, except in compliance with the JOSL. You
+ * may obtain a copy of the JOSL at http://www.jabber.org/ or at
+ * http://www.opensource.org/.
+ *
+ * Software distributed under the JOSL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL
+ * for the specific language governing rights and limitations under the
+ * JOSL.
+ *
+ * Copyrights
+ *
+ * Portions created by or assigned to Jabber.com, Inc. are
+ * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
+ * information for Jabber.com, Inc. is available at http://www.jabber.com/.
+ *
+ * Portions Copyright (c) 1998-1999 Jeremie Miller.
+ *
+ * Acknowledgements
+ *
+ * Special thanks to the Jabber Open Source Contributors for their
+ * suggestions and support of Jabber.
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * GNU General Public License Version 2 or later (the "GPL"), in which case
+ * the provisions of the GPL are applicable instead of those above. If you
+ * wish to allow use of your version of this file only under the terms of the
+ * GPL and not to allow others to use your version of this file under the JOSL,
+ * indicate your decision by deleting the provisions above and replace them
+ * with the notice and other provisions required by the GPL. If you do not
+ * delete the provisions above, a recipient may use your version of this file
+ * under either the JOSL or the GPL.
+ *
+ *
+ * --------------------------------------------------------------------------*/
+
+#include "jabber.h"
+#include "bitlbee.h"
+#include <glib.h>
+
+
+#ifdef POOL_DEBUG
+int pool__total = 0;
+int pool__ltotal = 0;
+HASHTABLE pool__disturbed = NULL;
+void *_pool__malloc(size_t size)
+{
+ pool__total++;
+ return g_malloc(size);
+}
+void _pool__free(void *block)
+{
+ pool__total--;
+ g_free(block);
+}
+#else
+#define _pool__malloc g_malloc
+#define _pool__free g_free
+#endif
+
+
+/* make an empty pool */
+pool _pool_new(char *zone)
+{
+ pool p;
+ while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1);
+ p->cleanup = NULL;
+ p->heap = NULL;
+ p->size = 0;
+
+#ifdef POOL_DEBUG
+ p->lsize = -1;
+ p->zone[0] = '\0';
+ strcat(p->zone,zone);
+ sprintf(p->name,"%X",p);
+
+ if(pool__disturbed == NULL)
+ {
+ pool__disturbed = 1; /* reentrancy flag! */
+ pool__disturbed = ghash_create(POOL_DEBUG,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp);
+ }
+ if(pool__disturbed != 1)
+ ghash_put(pool__disturbed,p->name,p);
+#endif
+
+ return p;
+}
+
+/* free a heap */
+static void _pool_heap_free(void *arg)
+{
+ struct pheap *h = (struct pheap *)arg;
+
+ _pool__free(h->block);
+ _pool__free(h);
+}
+
+/* mem should always be freed last */
+static void _pool_cleanup_append(pool p, struct pfree *pf)
+{
+ struct pfree *cur;
+
+ if(p->cleanup == NULL)
+ {
+ p->cleanup = pf;
+ return;
+ }
+
+ /* fast forward to end of list */
+ for(cur = p->cleanup; cur->next != NULL; cur = cur->next);
+
+ cur->next = pf;
+}
+
+/* create a cleanup tracker */
+static struct pfree *_pool_free(pool p, pool_cleaner f, void *arg)
+{
+ struct pfree *ret;
+
+ /* make the storage for the tracker */
+ while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1);
+ ret->f = f;
+ ret->arg = arg;
+ ret->next = NULL;
+
+ return ret;
+}
+
+/* create a heap and make sure it get's cleaned up */
+static struct pheap *_pool_heap(pool p, int size)
+{
+ struct pheap *ret;
+ struct pfree *clean;
+
+ /* make the return heap */
+ while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1);
+ while((ret->block = _pool__malloc(size)) == NULL) sleep(1);
+ ret->size = size;
+ p->size += size;
+ ret->used = 0;
+
+ /* append to the cleanup list */
+ clean = _pool_free(p, _pool_heap_free, (void *)ret);
+ clean->heap = ret; /* for future use in finding used mem for pstrdup */
+ _pool_cleanup_append(p, clean);
+
+ return ret;
+}
+
+pool _pool_new_heap(int size, char *zone)
+{
+ pool p;
+ p = _pool_new(zone);
+ p->heap = _pool_heap(p,size);
+ return p;
+}
+
+void *pmalloc(pool p, int size)
+{
+ void *block;
+
+ if(p == NULL)
+ {
+ fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
+ abort();
+ }
+
+ /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
+ if(p->heap == NULL || size > (p->heap->size / 2))
+ {
+ while((block = _pool__malloc(size)) == NULL) sleep(1);
+ p->size += size;
+ _pool_cleanup_append(p, _pool_free(p, _pool__free, block));
+ return block;
+ }
+
+ /* we have to preserve boundaries, long story :) */
+ if(size >= 4)
+ while(p->heap->used&7) p->heap->used++;
+
+ /* if we don't fit in the old heap, replace it */
+ if(size > (p->heap->size - p->heap->used))
+ p->heap = _pool_heap(p, p->heap->size);
+
+ /* the current heap has room */
+ block = (char *)p->heap->block + p->heap->used;
+ p->heap->used += size;
+ return block;
+}
+
+void *pmalloc_x(pool p, int size, char c)
+{
+ void* result = pmalloc(p, size);
+ if (result != NULL)
+ memset(result, c, size);
+ return result;
+}
+
+/* easy safety utility (for creating blank mem for structs, etc) */
+void *pmalloco(pool p, int size)
+{
+ void *block = pmalloc(p, size);
+ memset(block, 0, size);
+ return block;
+}
+
+/* XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */
+char *pstrdup(pool p, const char *src)
+{
+ char *ret;
+
+ if(src == NULL)
+ return NULL;
+
+ ret = pmalloc(p,strlen(src) + 1);
+ strcpy(ret,src);
+
+ return ret;
+}
+
+void pool_free(pool p)
+{
+ struct pfree *cur, *stub;
+
+ if(p == NULL) return;
+
+ cur = p->cleanup;
+ while(cur != NULL)
+ {
+ (*cur->f)(cur->arg);
+ stub = cur->next;
+ _pool__free(cur);
+ cur = stub;
+ }
+
+#ifdef POOL_DEBUG
+ ghash_remove(pool__disturbed,p->name);
+#endif
+
+ _pool__free(p);
+
+}