]> jfr.im git - irc/quakenet/newserv.git/blob - core/nsmalloc.c
nsfree is now O(1), add nsrealloc and statistics.
[irc/quakenet/newserv.git] / core / nsmalloc.c
1 /* nsmalloc: Simple pooled malloc() thing. */
2
3 #include <stdlib.h>
4
5 #include "nsmalloc.h"
6 #include "../core/error.h"
7
8 void *nsmalloc(unsigned int poolid, size_t size);
9 void nsfree(unsigned int poolid, void *ptr);
10 void nsfreeall(unsigned int poolid);
11
12 struct nsminfo {
13 struct nsminfo *next;
14 union {
15 struct nsminfo *prev;
16 unsigned long count;
17 } p;
18
19 size_t size;
20 char data[];
21 };
22
23 struct nsminfo pools[MAXPOOL];
24
25 void *nsmalloc(unsigned int poolid, size_t size) {
26 struct nsminfo *nsmp;
27
28 if (poolid >= MAXPOOL)
29 return NULL;
30
31 /* Allocate enough for the structure and the required data */
32 nsmp=(struct nsminfo *)malloc(sizeof(struct nsminfo)+size);
33
34 if (!nsmp)
35 return NULL;
36
37 nsmp->size=size;
38 pools[poolid].size+=size;
39 pools[poolid].p.count++;
40
41 nsmp->next=pools[poolid].next;
42 nsmp->p.prev=&pools[poolid];
43 if (pools[poolid].next)
44 pools[poolid].next->p.prev=nsmp;
45 pools[poolid].next=nsmp;
46
47 return (void *)nsmp->data;
48 }
49
50 /* we dump core on ptr == NULL */
51 void nsfree(unsigned int poolid, void *ptr) {
52 struct nsminfo *nsmp;
53
54 if (poolid >= MAXPOOL)
55 return;
56
57 /* evil */
58 nsmp=(struct nsminfo*)ptr - 1;
59
60 /* always set as we have a sentinel */
61 nsmp->p.prev->next=nsmp->next;
62 if (nsmp->next)
63 nsmp->next->p.prev=nsmp->p.prev;
64
65 pools[poolid].size-=nsmp->size;
66 pools[poolid].p.count--;
67
68 free(nsmp);
69 return;
70 }
71
72 void *nsrealloc(unsigned int poolid, void *ptr, size_t size) {
73 struct nsminfo *nsmp, *nsmpn;
74
75 if (ptr == NULL)
76 return nsmalloc(poolid, size);
77
78 if (size == 0) {
79 nsfree(poolid, ptr);
80 return NULL;
81 }
82
83 if (poolid >= MAXPOOL)
84 return NULL;
85
86 /* evil */
87 nsmp=(struct nsminfo *)ptr - 1;
88
89 if (size == nsmp->size)
90 return (void *)nsmp->data;
91
92 nsmpn=(struct nsminfo *)realloc(nsmp, sizeof(struct nsminfo)+size);
93 if (!nsmpn)
94 return NULL;
95
96 pools[poolid].size+=size-nsmpn->size;
97 nsmpn->size=size;
98
99 /* always set as we have a sentinel */
100 nsmpn->p.prev->next=nsmpn;
101
102 if (nsmpn->next)
103 nsmpn->next->p.prev=nsmpn;
104
105 return (void *)nsmpn->data;
106 }
107
108 void nsfreeall(unsigned int poolid) {
109 struct nsminfo *nsmp, *nnsmp;
110
111 if (poolid >= MAXPOOL)
112 return;
113
114 for (nsmp=pools[poolid].next;nsmp;nsmp=nnsmp) {
115 nnsmp=nsmp->next;
116 free(nsmp);
117 }
118
119 pools[poolid].next=NULL;
120 pools[poolid].size=0;
121 pools[poolid].p.count=0;
122 }
123
124 void nsexit() {
125 unsigned int i;
126
127 for (i=0;i<MAXPOOL;i++) {
128 if (pools[i].next) {
129 Error("core",ERR_INFO,"nsmalloc: Blocks still allocated in pool #%d (%lub, %lu items)\n",i,pools[i].size, pools[i].p.count);
130 nsfreeall(i);
131 }
132 }
133 }
134
135 int nspoolstats(unsigned int poolid, size_t *size, unsigned long *count) {
136 if (poolid >= MAXPOOL)
137 return 0;
138
139 *size = pools[poolid].size;
140 *count = pools[poolid].p.count;
141
142 return 1;
143 }