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