]> jfr.im git - irc/quakenet/newserv.git/blame - lib/sstring-new.c
fix last 2 warnings
[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 }
131 }
132#endif
855548e6 133 return;
134 }
135 }
136
137 Error("sstring",ERR_WARNING,"sstring_dehash(): Unable to find string (ref=%d, length=%d) in hash: %s",ss->refcount,ss->length,ss->content);
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
CP
207 sunprotectb(mblock);
208 retval->block=mblock;
855548e6 209 retval->alloc=(ssmemfree-sizeof(sstring));
210 retval->refcount=0;
211 freesstring(retval);
212 }
213
48866b49
CP
214 allocs++;
215 salloc();
216 } else {
217 sunprotectb(mblock);
855548e6 218 }
219
220 retval=(sstring *)ssmem;
221 ssmem+=(sizeof(sstring)+length);
222 ssmemfree-=(sizeof(sstring)+length);
223
224 retval->alloc=length;
225
226 /* If there's a fragment left over, lump it into this allocation */
227 if (ssmemfree < (sizeof(sstring)+1)) {
228 retval->alloc += ssmemfree;
229 ssmemfree=0;
230 ssmem=NULL;
231 }
232 }
233
234 /*
235 * At this point, retval points to a valid structure which is at
236 * least the right size and has the "alloc" value set correctly
237 */
238
239 retval->length=(length-1);
240 strcpy(retval->content,strbuf);
241 retval->refcount=1;
242
48866b49
CP
243#ifdef USE_VALGRIND
244 if(!foreignblock)
245 retval->block = mblock;
246#endif
247
855548e6 248 sstring_enhash(retval);
48866b49
CP
249 sprotect(retval);
250
855548e6 251 return retval;
252}
253
254void freesstring(sstring *inval) {
255 int alloc;
256
257 /* Allow people to call this with a NULL value */
258 if (inval==NULL)
259 return;
260
261 /* Only count calls that actually did something */
262 freecalls++;
263
37a40440
CP
264 if (inval->refcount)
265 sunprotect(inval);
266
855548e6 267 if (inval->refcount > 1) {
37a40440
CP
268 inval->refcount--;
269 sprotect(inval);
855548e6 270 return;
271 }
272
48866b49 273 /* If refcount==0 it wasn't hashed, or protected */
37a40440 274 if (inval->refcount)
855548e6 275 sstring_dehash(inval);
48866b49 276
855548e6 277 alloc=inval->alloc;
278 assert(alloc<=SSTRING_MAXLEN);
279 inval->next=freelist[alloc];
280 freelist[alloc]=inval;
37a40440 281 sprotect(inval);
855548e6 282}
283
284void sstringstats(int hooknum, void *arg) {
285 char buf[512];
286 int i,j;
287 sstring *ssp;
288 long statslev=(long)arg;
289
290 if (statslev>10) {
291 for(i=0,j=0;i<=SSTRING_MAXLEN;i++) {
292 for(ssp=freelist[i];ssp;ssp=ssp->next)
293 j++;
294 }
295
296 snprintf(buf,512,"SString : %7d get calls, %7d free calls, %7d allocs, %7d strings free",getcalls,freecalls,allocs,j);
297 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
298 }
299}
300
301int sstringcompare(sstring *ss1, sstring *ss2) {
302 if (ss1->length != ss2->length)
303 return -1;
304
305 return strncmp(ss1->content, ss2->content, ss1->length);
306}
307
48866b49
CP
308#ifdef USE_VALGRIND
309void finisstring() {
310 struct mblock_list *c, *n;
311 for (c=mblock_head;c;c=n) {
312 n=c->next;
313 munmap(c->block, SSTRING_ALLOC);
314 }
315}
316
317static void salloc(void) {
318 struct mblock_list *n;
319 mblock=mmap((void *)0, SSTRING_ALLOC, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
320
321 n=(struct mblock_list *)mblock;
322 n->block = mblock;
323 n->next = mblock_head;
324 mblock_head = n;
325
326 ssmem=(char *)mblock + sizeof(struct mblock_list);
327 ssmemfree=SSTRING_ALLOC-sizeof(struct mblock_list);
328}
329#endif /* USE_VALGRIND */