]> jfr.im git - irc/quakenet/newserv.git/blame - lib/sstring-new.c
Make the pool allocator Valgrind-aware.
[irc/quakenet/newserv.git] / lib / sstring-new.c
CommitLineData
855548e6 1/* sstring.h - Declaration of "static strings" functions */
2
3#define COMPILING_SSTRING
c5ec4806 4#define SSTRING_NEW
855548e6 5#include "sstring.h"
6
7#include "../core/hooks.h"
8#include "../core/nsmalloc.h"
9#include "../core/error.h"
10#include "../lib/irc_string.h"
11
12#include <stdio.h>
13
14#include <assert.h>
15#include <stdlib.h>
f8ba827c 16#define _GNU_SOURCE
855548e6 17#include <string.h>
18
19/* List of free stuff */
20static sstring *freelist[SSTRING_MAXLEN+1];
21static sstring *sshash[SSTRING_HASHSIZE];
22
23/* Global variables to track allocated memory */
24static char *ssmem;
25static int ssmemfree;
26
27/* Statistics counters */
28static int getcalls;
29static int freecalls;
30static int allocs;
31
48866b49 32/* Internal functions */
855548e6 33static void sstringstats(int hooknum, void *arg);
48866b49
CP
34static void salloc(void);
35
66297844 36#ifndef SSTRING_MMAP
48866b49
CP
37
38#define sunprotect(x)
39#define sunprotectb(x)
40#define sprotect(x)
41
42#else
43
b91d4f9e
CP
44#define __USE_MISC
45
48866b49
CP
46#include <sys/mman.h>
47static void *mblock;
48struct mblock_list {
49 void *block;
50 struct mblock_list *next;
51};
52
53static void *mblock_head;
54
55#define sunprotectb(x) mprotect(x, SSTRING_ALLOC, PROT_READ|PROT_WRITE);
37a40440
CP
56#define sunprotect(x) sunprotectb((x)->block);
57#define sprotect(x) mprotect((x)->block, SSTRING_ALLOC, PROT_READ);
48866b49 58
b91d4f9e
CP
59#ifndef MAP_ANON
60#define MAP_ANON MAP_ANONYMOUS
61#endif
62
66297844 63#endif /* SSTRING_MMAP */
855548e6 64
65void initsstring() {
66 int i;
67 for(i=0;i<=SSTRING_MAXLEN;i++)
68 freelist[i]=NULL;
69
70 for(i=0;i<SSTRING_HASHSIZE;i++)
71 sshash[i]=NULL;
72
73 ssmemfree=0;
74 ssmem=NULL;
75
76 /* Initialise statistics counters */
77 getcalls=0;
78 freecalls=0;
79 allocs=0;
80
81 registerhook(HOOK_CORE_STATSREQUEST,&sstringstats);
82}
83
84void finisstring() {
84d0b6e7
P
85 deregisterhook(HOOK_CORE_STATSREQUEST,&sstringstats);
86
87 #ifndef SSTRING_MMAP
855548e6 88 nsfreeall(POOL_SSTRING);
84d0b6e7 89 #endif /* SSTRING_MMAP */
855548e6 90}
91
84d0b6e7 92#ifndef SSTRING_MMAP
48866b49
CP
93static void salloc(void) {
94 ssmem=(char *)nsmalloc(POOL_SSTRING, SSTRING_ALLOC);
95 ssmemfree=SSTRING_ALLOC;
96}
66297844 97#endif /* SSTRING_MMAP */
48866b49 98
855548e6 99sstring *findsstring(const char *str) {
100 unsigned int hash=crc32(str)%SSTRING_HASHSIZE;
101 sstring *ss;
102
103 for (ss=sshash[hash];ss;ss=ss->next)
c5ec4806 104 if (!strcmp(str, sstring_content(ss)))
855548e6 105 return ss;
106
107 return NULL;
108}
109
110void sstring_enhash(sstring *ss) {
c5ec4806 111 unsigned int hash=crc32(sstring_content(ss))%SSTRING_HASHSIZE;
855548e6 112
113 ss->next=sshash[hash];
114 sshash[hash]=ss;
115}
116
117void sstring_dehash(sstring *ss) {
c5ec4806 118 unsigned int hash=crc32(sstring_content(ss))%SSTRING_HASHSIZE;
37a40440 119 sstring *ssh, *ssp;
855548e6 120
37a40440
CP
121 for (ssh=sshash[hash],ssp=NULL; ssh; ssp=ssh,ssh=ssh->next) {
122 if (ssh==ss) {
123 if (!ssp) {
124 sshash[hash]=ss->next;
125 } else {
66297844 126#ifndef SSTRING_MMAP
37a40440
CP
127 ssp->next=ss->next;
128#else
129 if (ssp->block!=ss->block) {
130 sunprotect(ssp) {
131 ssp->next=ss->next;
132 } sprotect(ssp);
133 } else {
134 ssp->next=ss->next;
135 }
37a40440 136#endif
7901b05a 137 }
855548e6 138 return;
139 }
140 }
141
c5ec4806 142 Error("sstring",ERR_WARNING,"sstring_dehash(): Unable to find string (ref=%lu, length=%d) in hash: %s",ss->refcount,ss->length,sstring_content(ss));
855548e6 143}
144
145sstring *getsstring(const char *inputstr, int maxlen) {
146 int i;
147 sstring *retval=NULL;
48866b49 148 int length, foreignblock;
855548e6 149 char strbuf[SSTRING_MAXLEN];
150
151 /* getsstring() on a NULL pointer returns a NULL sstring.. */
152 if (inputstr==NULL) {
153 return NULL;
154 }
155
156 if (inputstr[0]=='\0') {
157 return NULL;
158 }
159
160 if (maxlen>SSTRING_MAX) {
161 Error("sstring", ERR_ERROR, "Attempt to allocate overlength string (maxlen=%d)",maxlen);
162 return NULL;
163 }
164
165 /* Only count calls that actually did something */
166 getcalls++;
167
168 /* Make a copy of the desired string to make things easier later */
169 for (length=0;length<maxlen;length++) {
170 strbuf[length]=inputstr[length];
171 if (!strbuf[length])
172 break;
173 }
174 strbuf[length]='\0';
175
176 length++;
177
178 /* If it's hashed this is easy */
179 if ((retval=findsstring(strbuf))) {
48866b49
CP
180 sunprotect(retval) {
181 retval->refcount++;
182 } sprotect(retval);
183
855548e6 184 return retval;
185 }
48866b49
CP
186
187 foreignblock=0;
855548e6 188 /* Check to see if an approximately correct
189 * sized string is available */
190 for(i=0;i<SSTRING_SLACK;i++) {
191 if (length+i>SSTRING_MAXLEN)
192 break;
193
194 if (freelist[length+i]!=NULL) {
195 retval=freelist[length+i];
196 freelist[length+i]=retval->next;
48866b49
CP
197 sunprotect(retval);
198 foreignblock=1;
199
855548e6 200 retval->alloc=(length+i);
201 break;
202 }
203 }
204
205 /* None found, allocate a new one */
206 if (retval==NULL) {
207 /* Check for free memory */
208 if (ssmemfree < (sizeof(sstring)+length)) {
209 /* Not enough for us - turn the remaining memory into a free string for later */
210 if (ssmemfree>sizeof(sstring)) {
211 retval=(sstring *)ssmem;
37a40440 212 sunprotectb(mblock);
66297844 213#ifdef SSTRING_MMAP
37a40440 214 retval->block=mblock;
7901b05a 215#endif
855548e6 216 retval->alloc=(ssmemfree-sizeof(sstring));
217 retval->refcount=0;
218 freesstring(retval);
219 }
220
48866b49
CP
221 allocs++;
222 salloc();
223 } else {
224 sunprotectb(mblock);
855548e6 225 }
226
227 retval=(sstring *)ssmem;
228 ssmem+=(sizeof(sstring)+length);
229 ssmemfree-=(sizeof(sstring)+length);
230
231 retval->alloc=length;
232
233 /* If there's a fragment left over, lump it into this allocation */
234 if (ssmemfree < (sizeof(sstring)+1)) {
235 retval->alloc += ssmemfree;
236 ssmemfree=0;
237 ssmem=NULL;
238 }
239 }
240
241 /*
242 * At this point, retval points to a valid structure which is at
243 * least the right size and has the "alloc" value set correctly
244 */
245
246 retval->length=(length-1);
c5ec4806 247 strcpy(sstring_content(retval),strbuf);
855548e6 248 retval->refcount=1;
c5ec4806 249
66297844 250#ifdef SSTRING_MMAP
48866b49
CP
251 if(!foreignblock)
252 retval->block = mblock;
253#endif
254
855548e6 255 sstring_enhash(retval);
c5ec4806
CP
256
257#ifdef SSTRING_COMPAT
258 retval->content = retval->__content;
259#endif
260
48866b49
CP
261 sprotect(retval);
262
855548e6 263 return retval;
264}
265
266void freesstring(sstring *inval) {
267 int alloc;
268
269 /* Allow people to call this with a NULL value */
270 if (inval==NULL)
271 return;
272
273 /* Only count calls that actually did something */
274 freecalls++;
275
37a40440
CP
276 if (inval->refcount)
277 sunprotect(inval);
278
855548e6 279 if (inval->refcount > 1) {
37a40440
CP
280 inval->refcount--;
281 sprotect(inval);
855548e6 282 return;
283 }
284
48866b49 285 /* If refcount==0 it wasn't hashed, or protected */
37a40440 286 if (inval->refcount)
855548e6 287 sstring_dehash(inval);
48866b49 288
855548e6 289 alloc=inval->alloc;
290 assert(alloc<=SSTRING_MAXLEN);
291 inval->next=freelist[alloc];
292 freelist[alloc]=inval;
37a40440 293 sprotect(inval);
855548e6 294}
295
296void sstringstats(int hooknum, void *arg) {
297 char buf[512];
298 int i,j;
299 sstring *ssp;
300 long statslev=(long)arg;
301
302 if (statslev>10) {
303 for(i=0,j=0;i<=SSTRING_MAXLEN;i++) {
304 for(ssp=freelist[i];ssp;ssp=ssp->next)
305 j++;
306 }
307
308 snprintf(buf,512,"SString : %7d get calls, %7d free calls, %7d allocs, %7d strings free",getcalls,freecalls,allocs,j);
309 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
310 }
311}
312
66297844 313#ifdef SSTRING_MMAP
48866b49
CP
314void finisstring() {
315 struct mblock_list *c, *n;
316 for (c=mblock_head;c;c=n) {
317 n=c->next;
318 munmap(c->block, SSTRING_ALLOC);
319 }
320}
321
322static void salloc(void) {
323 struct mblock_list *n;
324 mblock=mmap((void *)0, SSTRING_ALLOC, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
325
326 n=(struct mblock_list *)mblock;
327 n->block = mblock;
328 n->next = mblock_head;
329 mblock_head = n;
330
331 ssmem=(char *)mblock + sizeof(struct mblock_list);
332 ssmemfree=SSTRING_ALLOC-sizeof(struct mblock_list);
333}
66297844 334#endif /* SSTRING_MMAP */