Browse code

HIGLY EXPERIMENTAL memory pool for libclamav The goal is to put an end to memory wasted due to stupid allocators and fragmentation In the long run mpool libraries will be replaced with better code. For now there just good enough.

This branch is currently under development and totally broken.
If it will ever compile, it'll probably result in random crashes or at least (slightly) higher load times.
The code is also terrible, just don't look.
Do not use except for testing.


git-svn-id: file:///var/lib/svn/clamav-devel/branches/mpool@4266 77e5149b-7576-45b1-b177-96237e5ba77b

aCaB authored on 2008/10/18 02:00:13
Showing 16 changed files
... ...
@@ -23,6 +23,10 @@
23 23
 
24 24
 #include <sys/types.h>
25 25
 #include <sys/stat.h>
26
+
27
+#ifdef USE_MPOOL
28
+#include mpool.h
29
+#endif
26 30
  
27 31
 #ifdef __cplusplus
28 32
 extern "C"
... ...
@@ -152,6 +156,10 @@ struct cl_engine {
152 152
 
153 153
     /* PUA categories (to be included or excluded) */
154 154
     char *pua_cats;
155
+
156
+#ifdef USE_MPOOL
157
+    mpool_t *mempool;
158
+#endif
155 159
 };
156 160
 
157 161
 struct cl_limits {
... ...
@@ -35,6 +35,10 @@
35 35
 #include "str.h"
36 36
 #include "others.h"
37 37
 
38
+#ifdef USE_MPOOL
39
+#include "mpool.h"
40
+#endif
41
+
38 42
 struct dconf_module {
39 43
     const char	*mname;	    /* module name */
40 44
     const char	*sname;	    /* submodule name */
... ...
@@ -108,13 +112,20 @@ static struct dconf_module modules[] = {
108 108
     { NULL,	    NULL,	    0,			    0 }
109 109
 };
110 110
 
111
+#ifdef USE_MPOOL
112
+struct cli_dconf *cli_dconf_init(mpool_t mempool)
113
+#else
111 114
 struct cli_dconf *cli_dconf_init(void)
115
+#endif
112 116
 {
113 117
 	unsigned int i;
114 118
 	struct cli_dconf *dconf;
115 119
 
116
-
120
+#ifdef USE_MPOOL
121
+    dconf = (struct cli_dconf *) mpool_calloc(mempool, sizeof(struct cli_dconf), 1, NULL);
122
+#else
117 123
     dconf = (struct cli_dconf *) cli_calloc(sizeof(struct cli_dconf), 1);
124
+#endif
118 125
     if(!dconf)
119 126
 	return NULL;
120 127
 
... ...
@@ -29,6 +29,10 @@
29 29
 #include "cltypes.h"
30 30
 #include "cvd.h"
31 31
 
32
+#ifdef USE_MPOOL
33
+#include "mpool.h"
34
+#endif
35
+
32 36
 struct cli_dconf {
33 37
     uint32_t pe;
34 38
     uint32_t elf;
... ...
@@ -97,7 +101,11 @@ struct cli_dconf {
97 97
 #define PHISHING_CONF_ENGINE   0x1
98 98
 #define PHISHING_CONF_ENTCONV  0x2
99 99
 
100
+#ifdef USE_MPOOL
101
+struct cli_dconf *cli_dconf_init(mpool_t);
102
+#else
100 103
 struct cli_dconf *cli_dconf_init(void);
104
+#endif
101 105
 void cli_dconf_print(struct cli_dconf *dconf);
102 106
 int cli_dconf_load(FILE *fs, struct cl_engine **engine, unsigned int options, struct cli_dbio *dbio);
103 107
 #endif
... ...
@@ -39,6 +39,10 @@
39 39
 #include "str.h"
40 40
 #include "readdb.h"
41 41
 
42
+#ifdef USE_MPOOL
43
+#include "mpool.h"
44
+#endif
45
+
42 46
 uint8_t cli_ac_mindepth = AC_DEFAULT_MIN_DEPTH;
43 47
 uint8_t cli_ac_maxdepth = AC_DEFAULT_MAX_DEPTH;
44 48
 
... ...
@@ -66,7 +70,11 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern)
66 66
 
67 67
     for(i = 0; i < len; i++) {
68 68
 	if(!pt->trans) {
69
+#ifdef USE_MPOOL
70
+	    pt->trans = (struct cli_ac_node **) mpool_calloc(root->mempool, 256, sizeof(struct cli_ac_node *), NULL);
71
+#else
69 72
 	    pt->trans = (struct cli_ac_node **) cli_calloc(256, sizeof(struct cli_ac_node *));
73
+#endif
70 74
 	    if(!pt->trans) {
71 75
 		cli_errmsg("cli_ac_addpatt: Can't allocate memory for pt->trans\n");
72 76
 		return CL_EMEM;
... ...
@@ -76,17 +84,29 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern)
76 76
 	next = pt->trans[(unsigned char) (pattern->pattern[i] & 0xff)]; 
77 77
 
78 78
 	if(!next) {
79
+#ifdef USE_MPOOL
80
+	    next = (struct cli_ac_node *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_node), NULL);
81
+#else
79 82
 	    next = (struct cli_ac_node *) cli_calloc(1, sizeof(struct cli_ac_node));
83
+#endif
80 84
 	    if(!next) {
81 85
 		cli_errmsg("cli_ac_addpatt: Can't allocate memory for AC node\n");
82 86
 		return CL_EMEM;
83 87
 	    }
84 88
 
85 89
 	    if(i != len - 1) {
90
+#ifdef USE_MPOOL
91
+		next->trans = (struct cli_ac_node **) mpool_calloc(root->mempool, 256, sizeof(struct cli_ac_node *), NULL);
92
+#else
86 93
 		next->trans = (struct cli_ac_node **) cli_calloc(256, sizeof(struct cli_ac_node *));
94
+#endif
87 95
 		if(!next->trans) {
88 96
 		    cli_errmsg("cli_ac_addpatt: Can't allocate memory for next->trans\n");
97
+#ifdef USE_MPOOL
98
+		    mpool_free(root->mempool, next);
99
+#else
89 100
 		    free(next);
101
+#endif
90 102
 		    return CL_EMEM;
91 103
 		}
92 104
 	    } else {
... ...
@@ -94,13 +114,22 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern)
94 94
 	    }
95 95
 
96 96
 	    root->ac_nodes++;
97
+#ifdef USE_MPOOL
98
+	    newtable = mpool_resize(root->mempool, root->ac_nodetable, root->ac_nodes * sizeof(struct cli_ac_node *), NULL);
99
+#else
97 100
 	    newtable = cli_realloc(root->ac_nodetable, root->ac_nodes * sizeof(struct cli_ac_node *));
101
+#endif
98 102
 	    if(!newtable) {
99 103
 		root->ac_nodes--;
100 104
 		cli_errmsg("cli_ac_addpatt: Can't realloc ac_nodetable\n");
101 105
 		if(next->trans)
106
+#ifdef USE_MPOOL
107
+		    mpool_free(root->mempool, next->trans);
108
+		mpool_free(root->mempool, next);
109
+#else
102 110
 		    free(next->trans);
103 111
 		free(next);
112
+#endif
104 113
 		return CL_EMEM;
105 114
 	    }
106 115
 	    root->ac_nodetable = (struct cli_ac_node **) newtable;
... ...
@@ -114,7 +143,11 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern)
114 114
     }
115 115
 
116 116
     root->ac_patterns++;
117
+#ifdef USE_MPOOL
118
+    newtable = mpool_resize(root->mempool, root->ac_pattable, root->ac_patterns * sizeof(struct cli_ac_patt *), NULL);
119
+#else
117 120
     newtable = cli_realloc(root->ac_pattable, root->ac_patterns * sizeof(struct cli_ac_patt *));
121
+#endif
118 122
     if(!newtable) {
119 123
 	root->ac_patterns--;
120 124
 	cli_errmsg("cli_ac_addpatt: Can't realloc ac_pattable\n");
... ...
@@ -299,16 +332,28 @@ int cli_ac_buildtrie(struct cli_matcher *root)
299 299
 int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth)
300 300
 {
301 301
 
302
+#ifdef USE_MPOOL
303
+    root->ac_root = (struct cli_ac_node *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_node), NULL);
304
+#else
302 305
     root->ac_root = (struct cli_ac_node *) cli_calloc(1, sizeof(struct cli_ac_node));
306
+#endif
303 307
     if(!root->ac_root) {
304 308
 	cli_errmsg("cli_ac_init: Can't allocate memory for ac_root\n");
305 309
 	return CL_EMEM;
306 310
     }
307 311
 
312
+#ifdef USE_MPOOL
313
+    root->ac_root->trans = (struct cli_ac_node **) mpool_calloc(root->mempool, 256, sizeof(struct cli_ac_node *), NULL);
314
+#else
308 315
     root->ac_root->trans = (struct cli_ac_node **) cli_calloc(256, sizeof(struct cli_ac_node *));
316
+#endif
309 317
     if(!root->ac_root->trans) {
310 318
 	cli_errmsg("cli_ac_init: Can't allocate memory for ac_root->trans\n");
319
+#ifdef USE_MPOOL
320
+	mpool_free(engine->mempool, root->ac_root, sizeof(struct cli_ac_node));
321
+#else
311 322
 	free(root->ac_root);
323
+#endif
312 324
 	return CL_EMEM;
313 325
     }
314 326
 
... ...
@@ -318,7 +363,11 @@ int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth)
318 318
     return CL_SUCCESS;
319 319
 }
320 320
 
321
+#ifdef USE_MPOOL
322
+static void ac_free_alt(mpool_t *mempool, struct cli_ac_patt *p)
323
+#else
321 324
 static void ac_free_alt(struct cli_ac_patt *p)
325
+#endif
322 326
 {
323 327
 	uint16_t i;
324 328
 	struct cli_ac_alt *a1, *a2;
... ...
@@ -333,11 +382,20 @@ static void ac_free_alt(struct cli_ac_patt *p)
333 333
 	    a2 = a1;
334 334
 	    a1 = a1->next;
335 335
 	    if(a2->str)
336
+#ifdef USE_MPOOL
337
+		mpool_free(mempool, a2->str);
338
+	    mpool_free(mempool, a2);
339
+#else
336 340
 		free(a2->str);
337 341
 	    free(a2);
342
+#endif
338 343
 	}
339 344
     }
345
+#ifdef USE_MPOOL
346
+    mpool_free(mempool, p->alttable);
347
+#else
340 348
     free(p->alttable);
349
+#endif
341 350
 }
342 351
 
343 352
 void cli_ac_free(struct cli_matcher *root)
... ...
@@ -1093,8 +1151,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1093 1093
 
1094 1094
     if(strlen(hexsig) / 2 < root->ac_mindepth)
1095 1095
 	return CL_EPATSHORT;
1096
-
1096
+#ifdef USE_MPOOL
1097
+    if((new = (struct cli_ac_patt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_patt), NULL)) == NULL)
1098
+#else
1097 1099
     if((new = (struct cli_ac_patt *) cli_calloc(1, sizeof(struct cli_ac_patt))) == NULL)
1100
+#endif
1098 1101
 	return CL_EMEM;
1099 1102
 
1100 1103
     new->rtype = rtype;
... ...
@@ -1114,7 +1175,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1114 1114
 
1115 1115
     if(strchr(hexsig, '[')) {
1116 1116
 	if(!(hexcpy = cli_strdup(hexsig))) {
1117
+#ifdef USE_MPOOL
1118
+	    mpool_free(root->mempool, new);
1119
+#else
1117 1120
 	    free(new);
1121
+#endif
1118 1122
 	    return CL_EMEM;
1119 1123
 	}
1120 1124
 
... ...
@@ -1179,14 +1244,22 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1179 1179
 
1180 1180
 	if(error) {
1181 1181
 	    free(hexcpy);
1182
+#ifdef USE_MPOOL
1183
+	    mpool_free(root->mempool, new);
1184
+#else
1182 1185
 	    free(new);
1186
+#endif
1183 1187
 	    return error;
1184 1188
 	}
1185 1189
 
1186 1190
 	hex = cli_strdup(hex);
1187 1191
 	free(hexcpy);
1188 1192
 	if(!hex) {
1193
+#ifdef USE_MPOOL
1194
+	    mpool_free(root->mempool, new);
1195
+#else
1189 1196
 	    free(new);
1197
+#endif
1190 1198
 	    return CL_EMEM;
1191 1199
 	}
1192 1200
     }
... ...
@@ -1197,13 +1270,22 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1197 1197
 	if(hex) {
1198 1198
 	    hexcpy = hex;
1199 1199
 	} else if(!(hexcpy = cli_strdup(hexsig))) {
1200
+#ifdef USE_MPOOL
1201
+	    mpool_free(root->mempool, new);
1202
+#else
1200 1203
 	    free(new);
1204
+#endif
1201 1205
 	    return CL_EMEM;
1202 1206
 	}
1203 1207
 
1208
+#ifdef USE_MPOOL
1209
+	if(!(hexnew = (char *) mpool_calloc(root->mempool, strlen(hexsig) + 1, 1, NULL))) {
1210
+	    mpool_free(root->mempool, new);
1211
+#else
1204 1212
 	if(!(hexnew = (char *) cli_calloc(strlen(hexsig) + 1, 1))) {
1205
-	    free(hexcpy);
1206 1213
 	    free(new);
1214
+#endif
1215
+	    free(hexcpy);
1207 1216
 	    return CL_EMEM;
1208 1217
 	}
1209 1218
 
... ...
@@ -1225,7 +1307,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1225 1225
 	    }
1226 1226
 	    *start++ = 0;
1227 1227
 
1228
+#ifdef USE_MPOOL
1229
+	    newalt = (struct cli_ac_alt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_alt), NULL);
1230
+#else
1228 1231
 	    newalt = (struct cli_ac_alt *) cli_calloc(1, sizeof(struct cli_ac_alt));
1232
+#endif
1229 1233
 	    if(!newalt) {
1230 1234
 		cli_errmsg("cli_ac_addsig: Can't allocate newalt\n");
1231 1235
 		error = CL_EMEM;
... ...
@@ -1233,10 +1319,19 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1233 1233
 	    }
1234 1234
 
1235 1235
 	    new->alt++;
1236
+
1237
+#ifdef USE_MPOOL
1238
+	    newtable = (struct cli_ac_alt **) mpool_resize(root->mempool, new->alttable, new->alt * sizeof(struct cli_ac_alt *), NULL);
1239
+#else
1236 1240
 	    newtable = (struct cli_ac_alt **) cli_realloc(new->alttable, new->alt * sizeof(struct cli_ac_alt *));
1241
+#endif
1237 1242
 	    if(!newtable) {
1238 1243
 		new->alt--;
1244
+#ifdef USE_MPOOL
1245
+		mpool_free(root->mempool, newalt);
1246
+#else
1239 1247
 		free(newalt);
1248
+#endif
1240 1249
 		cli_errmsg("cli_ac_addsig: Can't realloc new->alttable\n");
1241 1250
 		error = CL_EMEM;
1242 1251
 		break;
... ...
@@ -1256,7 +1351,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1256 1256
 
1257 1257
 	    if(3 * newalt->num - 1 == (uint16_t) strlen(pt)) {
1258 1258
 		newalt->chmode = 1;
1259
+#ifdef USE_MPOOL
1260
+		newalt->str = (unsigned char *) mpool_alloc(root->mempool, newalt->num, NULL);
1261
+#else
1259 1262
 		newalt->str = (unsigned char *) cli_malloc(newalt->num);
1263
+#endif
1260 1264
 		if(!newalt->str) {
1261 1265
 		    cli_errmsg("cli_ac_addsig: Can't allocate newalt->str\n");
1262 1266
 		    error = CL_EMEM;
... ...
@@ -1285,7 +1384,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1285 1285
 			while(altpt->next)
1286 1286
 			    altpt = altpt->next;
1287 1287
 
1288
+#ifdef USE_MPOOL
1289
+			altpt->next = (struct cli_ac_alt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_alt), NULL);
1290
+#else
1288 1291
 			altpt->next = (struct cli_ac_alt *) cli_calloc(1, sizeof(struct cli_ac_alt));
1292
+#endif
1289 1293
 			if(!altpt->next) {
1290 1294
 			    cli_errmsg("cli_ac_addsig: Can't allocate altpt->next\n");
1291 1295
 			    error = CL_EMEM;
... ...
@@ -1318,20 +1421,46 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1318 1318
 	if(error) {
1319 1319
 	    if(new->alt) {
1320 1320
 		free(hex);
1321
+#ifdef USE_MPOOL
1322
+		ac_free_alt(root->mempool, new);
1323
+	    }
1324
+	    mpool_free(root->mempool, new);
1325
+#else
1321 1326
 		ac_free_alt(new);
1322 1327
 	    }
1323 1328
 	    free(new);
1329
+#endif
1324 1330
 	    return error;
1325 1331
 	}
1326 1332
     }
1327 1333
 
1328
-    if((new->pattern = cli_hex2ui(hex ? hex : hexsig)) == NULL) {
1334
+#ifdef USE_MPOOL
1335
+{
1336
+    unsigned int mpoolhexlen = (strlen(hex ? hex : hexsig) / 2 + 1) * sizeof(uint16_t);
1337
+    uint16_t *mpoolpatt = cli_hex2ui(hex ? hex : hexsig);
1338
+    if(mpoolpatt) {
1339
+        if((new->pattern = mpool_alloc(root->mempool, mpoolhexlen, NULL)) != NULL)
1340
+	    memcpy(new->pattern, mpoolpatt, mpoolhexlen);
1341
+	free(mpoolpatt);
1342
+    } else new->pattern = NULL;
1343
+}
1344
+#else
1345
+    new->pattern = cli_hex2ui(hex ? hex : hexsig)
1346
+#endif
1347
+
1348
+    if(new->pattern == NULL) {
1329 1349
 	if(new->alt)
1350
+#ifdef USE_MPOOL
1351
+	    ac_free_alt(root->mempool, new);
1352
+	mpool_free(root->mempool, new);
1353
+#else
1330 1354
 	    ac_free_alt(new);
1331
-	free(hex);
1332 1355
 	free(new);
1356
+#endif
1357
+	free(hex);
1333 1358
 	return CL_EMALFDB;
1334 1359
     }
1360
+
1335 1361
     new->length = strlen(hex ? hex : hexsig) / 2;
1336 1362
     free(hex);
1337 1363
 
... ...
@@ -1375,9 +1504,15 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1375 1375
 
1376 1376
 	if(plen < root->ac_mindepth) {
1377 1377
 	    cli_errmsg("cli_ac_addsig: Can't find a static subpattern of length %u\n", root->ac_mindepth);
1378
+#ifdef USE_MPOOL
1379
+	    ac_free_alt(root->mempool, new);
1380
+	    mpool_free(root->mempool, new->pattern);
1381
+	    mpool_free(root->mempool, new);
1382
+#else
1378 1383
 	    ac_free_alt(new);
1379 1384
 	    free(new->pattern);
1380 1385
 	    free(new);
1386
+#endif
1381 1387
 	    return CL_EMALFDB;
1382 1388
 	}
1383 1389
 
... ...
@@ -1394,11 +1529,28 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1394 1394
     if(new->length > root->maxpatlen)
1395 1395
 	root->maxpatlen = new->length;
1396 1396
 
1397
+#ifdef USE_MPOOL
1398
+{
1399
+    char *mpoolvirname = cli_virname((char *) virname, options & CL_DB_OFFICIAL, 0);
1400
+    if(mpoolvirname) {
1401
+        unsigned int mpoolvirnamesz = strlen(mpoolvirname) + 1;
1402
+        if((new->virname = mpool_alloc(root->mempool, mpoolvirnamesz, NULL)) != NULL)
1403
+	    memcpy(new->virname, mpoolvirname, mpoolvirnamesz);
1404
+    } else new->virname = NULL;
1405
+}
1406
+#else
1397 1407
     new->virname = cli_virname((char *) virname, options & CL_DB_OFFICIAL, 0);
1408
+#endif
1398 1409
     if(!new->virname) {
1410
+#ifdef USE_MPOOL
1411
+	new->prefix ? mpool_free(root->mempool, new->prefix) : mpool_free(root->mempool, new->pattern);
1412
+	ac_free_alt(root->mempool, new);
1413
+	mpool_free(root->mempool, new);
1414
+#else
1399 1415
 	new->prefix ? free(new->prefix) : free(new->pattern);
1400 1416
 	ac_free_alt(new);
1401 1417
 	free(new);
1418
+#endif
1402 1419
 	return CL_EMEM;
1403 1420
     }
1404 1421
 
... ...
@@ -1406,23 +1558,48 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1406 1406
 	root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
1407 1407
 
1408 1408
     if(offset) {
1409
+#ifdef USE_MPOOL
1410
+	char *mpooloffset = cli_strdup(offset);
1411
+	if(mpooloffset) {
1412
+	    unsigned int mpooloffsetsz = strlen(mpooloffset) + 1;
1413
+	    if((new->offset = mpool_alloc(root->mempool, mpooloffsetsz, NULL)))
1414
+	        memcpy(new->offset, mpooloffset, mpooloffsetsz);
1415
+	} else new->offset = NULL;
1416
+#else
1409 1417
 	new->offset = cli_strdup(offset);
1418
+#endif
1410 1419
 	if(!new->offset) {
1420
+#ifdef USE_MPOOL
1421
+	    new->prefix ? mpool_free(rool->mempool, new->prefix) : mpool_free(root->mempool, new->pattern);
1422
+	    ac_free_alt(root->mempool, new);
1423
+	    mpool_free(root->mempool, new->virname);
1424
+	    mpool_free(root->mempool, new);
1425
+#else
1411 1426
 	    new->prefix ? free(new->prefix) : free(new->pattern);
1412 1427
 	    ac_free_alt(new);
1413 1428
 	    free(new->virname);
1414 1429
 	    free(new);
1430
+#endif
1415 1431
 	    return CL_EMEM;
1416 1432
 	}
1417 1433
     }
1418 1434
 
1419 1435
     if((ret = cli_ac_addpatt(root, new))) {
1436
+#ifdef USE_MPOOL
1437
+	new->prefix ? mpool_free(rool->mempool, new->prefix) : mpool_free(root->mempool, new->pattern);
1438
+	mpool_free(root->mempool, new->virname);
1439
+	ac_free_alt(root->mempool, new);
1440
+	if(new->offset)
1441
+	    mpool_free(root->mempool, new->offset);
1442
+	mpool_free(root->mempool, new);
1443
+#else
1420 1444
 	new->prefix ? free(new->prefix) : free(new->pattern);
1421 1445
 	free(new->virname);
1422 1446
 	ac_free_alt(new);
1423 1447
 	if(new->offset)
1424 1448
 	    free(new->offset);
1425 1449
 	free(new);
1450
+#endif
1426 1451
 	return ret;
1427 1452
     }
1428 1453
 
... ...
@@ -32,6 +32,10 @@
32 32
 #include "matcher-bm.h"
33 33
 #include "filetypes.h"
34 34
 
35
+#ifdef USE_MPOOL
36
+#include "mpool.h"
37
+#endif
38
+
35 39
 #define BM_MIN_LENGTH	3
36 40
 #define BM_BLOCK_SIZE	3
37 41
 #define HASH(a,b,c) (211 * a + 37 * b + c)
... ...
@@ -97,12 +101,19 @@ int cli_bm_init(struct cli_matcher *root)
97 97
 {
98 98
 	uint16_t i, size = HASH(255, 255, 255) + 1;
99 99
 
100
-
100
+#ifdef USE_MPOOL
101
+    if(!(root->bm_shift = (uint8_t *) mpool_calloc(root->mempool, size, sizeof(uint8_t), NULL)))
102
+#else
101 103
     if(!(root->bm_shift = (uint8_t *) cli_calloc(size, sizeof(uint8_t))))
104
+#endif
102 105
 	return CL_EMEM;
103 106
 
104 107
     if(!(root->bm_suffix = (struct cli_bm_patt **) cli_calloc(size, sizeof(struct cli_bm_patt *)))) {
108
+#ifdef USE_MPOOL
109
+	mpool_free(root->mempool, root->bm_shift, size * sizeof(uint8_t));
110
+#else
105 111
 	free(root->bm_shift);
112
+#endif
106 113
 	return CL_EMEM;
107 114
     }
108 115
 
... ...
@@ -34,6 +34,11 @@
34 34
 #include "matcher-bm.h"
35 35
 #include "hashtab.h"
36 36
 
37
+#ifdef USE_MPOOL
38
+#include "mpool.h"
39
+#endif
40
+
41
+
37 42
 #define CLI_MATCH_WILDCARD	0xff00
38 43
 #define CLI_MATCH_CHAR		0x0000
39 44
 #define CLI_MATCH_IGNORE	0x0100
... ...
@@ -80,6 +85,7 @@ struct cli_matcher {
80 80
 
81 81
     uint16_t maxpatlen;
82 82
     uint8_t ac_only;
83
+    mpool_t mempool;
83 84
 };
84 85
 
85 86
 struct cli_meta_node {
86 87
new file mode 100644
... ...
@@ -0,0 +1,86 @@
0
+2006-05-31  Gray Watson  <>
1
+
2
+	* Version 2.1.0 released.
3
+
4
+	* Added MPOOL_ERROR_PNT_OVER to distinguish between pointer
5
+	overwrite and mpool structure overwrite.
6
+
7
+2005-05-20  Gray Watson  <>
8
+
9
+	* Version 2.0.0 released.
10
+
11
+	* First external publication of library.
12
+
13
+Thu Mar  4 10:14:21 1999  Gray Watson  <>
14
+
15
+	* Reworked the way the blocks were split up.
16
+
17
+	* Removed the round arguments.  Not used.
18
+
19
+Wed Mar  3 19:29:38 1999  Gray Watson  <>
20
+
21
+	* Moved to random().  Fucking rand() was hiding a lot of problems
22
+ 	from me.
23
+
24
+	* Added some additional sanity checks in free().
25
+
26
+	* Added mpool_set_max_pages to the library.
27
+
28
+Thu Feb 25 12:41:51 1999  Gray Watson  <>
29
+
30
+	* Added log_function transaction callback.
31
+
32
+Thu Feb 25 09:53:33 1999  Gray Watson  <>
33
+
34
+	* Changed the default page size to 16 * getpagesize.
35
+
36
+Wed Feb 24 17:52:52 1999  Gray Watson  <>
37
+
38
+	* Major reworking of internals to simplify structures. 
39
+
40
+Fri Feb 19 12:52:55 1999  Gray Watson  <>
41
+
42
+	* Made a number of changes to the internals which removed the
43
+ 	addr_to_block as a performance pig.
44
+
45
+Tue Feb 16 21:11:23 1999  Gray Watson  <>
46
+
47
+	* Added ability for free to look up in the free bit lists for
48
+ 	memory to use.
49
+
50
+	* Added mpool_clear.  Good idea.
51
+
52
+Thu Feb 11 02:53:45 1999  Gray Watson  <>
53
+
54
+	* Finally a working version.  Looks much better.
55
+
56
+	* Added rounding sizes so it will allocate aligned memory.
57
+
58
+	* Added minimum size to the mpool_free function to speed it up.
59
+
60
+Wed Feb 10 23:30:48 1999  Gray Watson  <>
61
+
62
+	* Version 1 with new fine grained memory resolution almost
63
+ 	working.
64
+
65
+Fri May  2 02:26:28 1997  Gray Watson  <>
66
+
67
+	* Moved to MAP_PRIVATE from MAP_SHARED.
68
+
69
+	* Fixed the min/max handling.
70
+
71
+	* Added additional info to mpool_stat.
72
+
73
+Thu May  1 16:51:06 1997  Gray Watson  <>
74
+
75
+	* Added page-size information request.
76
+
77
+	* Added better no-memory errors.
78
+
79
+Thu Apr 24 01:58:41 1997  Gray Watson  <>
80
+
81
+	* Added handling of null for debugging purposes.
82
+
83
+Mon Apr 14 03:31:26 1997  Gray Watson  <>
84
+
85
+	* Started the mpool routines.
0 86
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+#
1
+# $Id: Makefile.all,v 1.1.1.1 2005/05/20 19:58:29 gray Exp $
2
+#
3
+
4
+HFLS	= mpool.h
5
+OBJS	= mpool.o
6
+
7
+CC	= cc
8
+
9
+CFLAGS	= -g -I. $(DEFINES)
10
+#CFLAGS	= -g -I.
11
+LDFLAGS	=
12
+RANLIB	= ranlib
13
+
14
+DESTDIR	= /usr/local
15
+TEST	= mpool_t
16
+LIBRARY	= libmpool.a
17
+
18
+all : $(LIBRARY) $(UTIL)
19
+
20
+clean :
21
+	rm -f a.out core *.o *.t
22
+	rm -f $(LIBRARY) $(TEST)
23
+
24
+install : $(HFLS) $(LIBRARY)
25
+	install -c -m 444 $(HFLS) $(DESTDIR)/include
26
+	install -c -m 444 $(LIBRARY) $(DESTDIR)/lib
27
+	$(RANLIB) $(DESTDIR)/libo/$(LIBRARY)
28
+
29
+$(LIBRARY) : $(OBJS)
30
+	ar cr $(LIBRARY) $?
31
+	$(RANLIB) $@
32
+
33
+tests : $(TEST)
34
+
35
+$(TEST) : $(TEST).o $(LIBRARY)
36
+	rm -f $@
37
+	$(CC) $(LDFLAGS) $(TEST).o $(LIBRARY)
38
+	mv a.out $@
39
+
40
+$(UTIL) : $(UTIL).o $(LIBRARY)
41
+	rm -f $@
42
+	$(CC) $(LDFLAGS) $(UTIL).o $(LIBRARY)
43
+	mv a.out $@
44
+
45
+.c.o :
46
+	rm -f $@
47
+	$(CC) $(CFLAGS) -c $< -o $@
48
+
49
+#
50
+# Below are dependencies that are automatically generated by make
51
+# depend.  Please do not edit by hand.
52
+#
53
+
54
+mpool.o: mpool.c mpool.h mpool_loc.h
55
+mpool_t.o: mpool_t.c mpool.h
0 56
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+-------------------------------------------------------------------------------
1
+$Id: NEWS,v 1.2 2006/05/31 20:28:31 gray Exp $
2
+-------------------------------------------------------------------------------
3
+
4
+Version 2.1.0:
5
+
6
+	* Added MPOOL_ERROR_PNT_OVER to show pointer overwrites.
7
+
8
+Version 2.0.0:
9
+
10
+	* Initial external release of library after use since 1996.
0 11
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+-------------------------------------------------------------------------------
1
+$Id: README,v 1.2 2005/05/22 19:49:30 gray Exp $
2
+-------------------------------------------------------------------------------
3
+
4
+BACKGROUND:
5
+
6
+This is a memory pool library which was written to allow a program to
7
+have heaps that it could destroy without fragmenting memory.  You can
8
+have multiple heaps and reset them easily completely reclaiming the
9
+memory (as opposed to standard heaps).
10
+
11
+With it you can mpool_open() a new heap, then mpool_alloc(),
12
+mpool_calloc(), mpool_realloc(), mpool_free() to your heart's content.
13
+Once you are done with the memory-pool you can run mpool_clear() or
14
+mpool_close() and completely remove the memory associated with the
15
+pools.  This is very handy if you are working with some large blocks
16
+of memory and want to reset back to a clean state.
17
+
18
+Check out the mpool.h file for more information.  Sorry for minimal
19
+docs.
20
+
21
+-------------------------------------------------------------------------------
22
+
23
+INSTALLATION:
24
+
25
+1) Typing 'make' should be enough to build libskip.a.
26
+2) Typing 'make tests' should make the mpool_t test program.
27
+
28
+-------------------------------------------------------------------------------
29
+
30
+REPOSITORY:
31
+
32
+The newest versions of the library are available from:
33
+
34
+	http://256.com/sources/mpool/
35
+
36
+-------------------------------------------------------------------------------
37
+
38
+AUTHOR:
39
+
40
+If you have any questions or problems feel free to send me mail.
41
+
42
+Gray Watson
43
+http://256.com/gray/
44
+
45
+-------------------------------------------------------------------------------
0 46
new file mode 100644
... ...
@@ -0,0 +1,1734 @@
0
+/*
1
+ * Memory pool routines.
2
+ *
3
+ * Copyright 1996 by Gray Watson.
4
+ *
5
+ * This file is part of the mpool package.
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for
8
+ * any purpose and without fee is hereby granted, provided that the
9
+ * above copyright notice and this permission notice appear in all
10
+ * copies, and that the name of Gray Watson not be used in advertising
11
+ * or publicity pertaining to distribution of the document or software
12
+ * without specific, written prior permission.
13
+ *
14
+ * Gray Watson makes no representations about the suitability of the
15
+ * software described herein for any purpose.  It is provided "as is"
16
+ * without express or implied warranty.
17
+ *
18
+ * The author may be reached via http://256.com/gray/
19
+ *
20
+ * $Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $
21
+ */
22
+
23
+/*
24
+ * Memory-pool allocation routines.  I got sick of the GNU mmalloc
25
+ * library which was close to what we needed but did not exactly do
26
+ * what I wanted.
27
+ *
28
+ * The following uses mmap from /dev/zero.  It allows a number of
29
+ * allocations to be made inside of a memory pool then with a clear or
30
+ * close the pool can be reset without any memory fragmentation and
31
+ * growth problems.
32
+ */
33
+
34
+#include <errno.h>
35
+#include <fcntl.h>
36
+#include <stdio.h>
37
+#include <stdlib.h>
38
+#include <string.h>
39
+#include <unistd.h>
40
+#include <sys/mman.h>
41
+
42
+#ifdef DMALLOC
43
+#include "dmalloc.h"
44
+#endif
45
+
46
+#define MPOOL_MAIN
47
+
48
+#include "mpool.h"
49
+#include "mpool_loc.h"
50
+
51
+#ifdef __GNUC__
52
+#ident "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $"
53
+#else
54
+static char *rcs_id = "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $";
55
+#endif
56
+
57
+/* ACAB */
58
+#include <stddef.h>
59
+struct FRAG {
60
+  unsigned long frag_size;
61
+  void *frag_ptr;
62
+};
63
+#define FRAG_OVERHEAD (offsetof(struct FRAG, frag_ptr))
64
+
65
+/* version */
66
+static	char *version = "mpool library version 2.1.0";
67
+
68
+/* local variables */
69
+static	int		enabled_b = 0;		/* lib initialized? */
70
+static	unsigned int	min_bit_free_next = 0;	/* min size of next pnt */
71
+static	unsigned int	min_bit_free_size = 0;	/* min size of next + size */
72
+static	unsigned long	bit_array[MAX_BITS + 1]; /* size -> bit */
73
+
74
+/****************************** local utilities ******************************/
75
+
76
+/*
77
+ * static void startup
78
+ *
79
+ * DESCRIPTION:
80
+ *
81
+ * Perform any library level initialization.
82
+ *
83
+ * RETURNS:
84
+ *
85
+ * None.
86
+ *
87
+ * ARGUMENTS:
88
+ *
89
+ * None.
90
+ */
91
+static	void	startup(void)
92
+{
93
+  int		bit_c;
94
+  unsigned long	size = 1;
95
+  
96
+  if (enabled_b) {
97
+    return;
98
+  }
99
+  
100
+  /* allocate our free bit array list */
101
+  for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
102
+    bit_array[bit_c] = size;
103
+    
104
+    /*
105
+     * Note our minimum number of bits that can store a pointer.  This
106
+     * is smallest address that we can have a linked list for.
107
+     */
108
+    if (min_bit_free_next == 0 && size >= sizeof(void *)) {
109
+      min_bit_free_next = bit_c;
110
+    }
111
+    /*
112
+     * Note our minimum number of bits that can store a pointer and
113
+     * the size of the block.
114
+     */
115
+    if (min_bit_free_size == 0 && size >= sizeof(mpool_free_t)) {
116
+      min_bit_free_size = bit_c;
117
+    }
118
+    
119
+    size *= 2;
120
+  }
121
+  
122
+  enabled_b = 1;
123
+}
124
+
125
+/*
126
+ * static int size_to_bits
127
+ *
128
+ * DESCRIPTION:
129
+ *
130
+ * Calculate the number of bits in a size.
131
+ *
132
+ * RETURNS:
133
+ *
134
+ * Number of bits.
135
+ *
136
+ * ARGUMENTS:
137
+ *
138
+ * size -> Size of memory of which to calculate the number of bits.
139
+ */
140
+static	int	size_to_bits(const unsigned long size)
141
+{
142
+  int		bit_c = 0;
143
+  
144
+  for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
145
+    if (size <= bit_array[bit_c]) {
146
+      break;
147
+    }
148
+  }
149
+  
150
+  return bit_c;
151
+}
152
+
153
+/*
154
+ * static int size_to_free_bits
155
+ *
156
+ * DESCRIPTION:
157
+ *
158
+ * Calculate the number of bits in a size going on the free list.
159
+ *
160
+ * RETURNS:
161
+ *
162
+ * Number of bits.
163
+ *
164
+ * ARGUMENTS:
165
+ *
166
+ * size -> Size of memory of which to calculate the number of bits.
167
+ */
168
+static	int	size_to_free_bits(const unsigned long size)
169
+{
170
+  int		bit_c = 0;
171
+  
172
+  if (size == 0) {
173
+    return 0;
174
+  }
175
+  
176
+  for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
177
+    if (size < bit_array[bit_c]) {
178
+      break;
179
+    }
180
+  }
181
+  
182
+  return bit_c - 1;
183
+}
184
+
185
+/*
186
+ * static int bits_to_size
187
+ *
188
+ * DESCRIPTION:
189
+ *
190
+ * Calculate the size represented by a number of bits.
191
+ *
192
+ * RETURNS:
193
+ *
194
+ * Number of bits.
195
+ *
196
+ * ARGUMENTS:
197
+ *
198
+ * bit_n -> Number of bits
199
+ */
200
+static	unsigned long	bits_to_size(const int bit_n)
201
+{
202
+  if (bit_n > MAX_BITS) {
203
+    return bit_array[MAX_BITS];
204
+  }
205
+  else {
206
+    return bit_array[bit_n];
207
+  }
208
+}
209
+
210
+/*
211
+ * static void *alloc_pages
212
+ *
213
+ * DESCRIPTION:
214
+ *
215
+ * Allocate space for a number of memory pages in the memory pool.
216
+ *
217
+ * RETURNS:
218
+ *
219
+ * Success - New pages of memory
220
+ *
221
+ * Failure - NULL
222
+ *
223
+ * ARGUMENTS:
224
+ *
225
+ * mp_p <-> Pointer to our memory pool.
226
+ *
227
+ * page_n -> Number of pages to alloc.
228
+ *
229
+ * error_p <- Pointer to integer which, if not NULL, will be set with
230
+ * a mpool error code.
231
+ */
232
+static	void	*alloc_pages(mpool_t *mp_p, const unsigned int page_n,
233
+			     int *error_p)
234
+{
235
+  void		*mem, *fill_mem;
236
+  unsigned long	size, fill;
237
+  int		state;
238
+  
239
+  /* are we over our max-pages? */
240
+  if (mp_p->mp_max_pages > 0 && mp_p->mp_page_c >= mp_p->mp_max_pages) {
241
+    SET_POINTER(error_p, MPOOL_ERROR_NO_PAGES);
242
+    return NULL;
243
+  }
244
+  
245
+  size = SIZE_OF_PAGES(mp_p, page_n);
246
+  
247
+#ifdef DEBUG
248
+  (void)printf("allocating %u pages or %lu bytes\n", page_n, size);
249
+#endif
250
+  
251
+  if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_USE_SBRK)) {
252
+    mem = sbrk(size);
253
+    if (mem == (void *)-1) {
254
+      SET_POINTER(error_p, MPOOL_ERROR_NO_MEM);
255
+      return NULL;
256
+    }
257
+    fill = (unsigned long)mem % mp_p->mp_page_size;
258
+    
259
+    if (fill > 0) {
260
+      fill = mp_p->mp_page_size - fill;
261
+      fill_mem = sbrk(fill);
262
+      if (fill_mem == (void *)-1) {
263
+	SET_POINTER(error_p, MPOOL_ERROR_NO_MEM);
264
+	return NULL;
265
+      }
266
+      if ((char *)fill_mem != (char *)mem + size) {
267
+	SET_POINTER(error_p, MPOOL_ERROR_SBRK_CONTIG);
268
+	return NULL;
269
+      }
270
+      mem = (char *)mem + fill;
271
+    }
272
+  }
273
+  else {
274
+    state = MAP_PRIVATE;
275
+#ifdef MAP_FILE
276
+    state |= MAP_FILE;
277
+#endif
278
+#ifdef MAP_VARIABLE
279
+    state |= MAP_VARIABLE;
280
+#endif
281
+    
282
+    /* mmap from /dev/zero */
283
+    mem = mmap((caddr_t)mp_p->mp_addr, size, PROT_READ | PROT_WRITE, state,
284
+	       mp_p->mp_fd, mp_p->mp_top);
285
+    if (mem == (void *)MAP_FAILED) {
286
+      if (errno == ENOMEM) {
287
+	SET_POINTER(error_p, MPOOL_ERROR_NO_MEM);
288
+      }
289
+      else {
290
+	SET_POINTER(error_p, MPOOL_ERROR_MMAP);
291
+      }
292
+      return NULL;
293
+    }
294
+    mp_p->mp_top += size;
295
+    if (mp_p->mp_addr != NULL) {
296
+      mp_p->mp_addr = (char *)mp_p->mp_addr + size;
297
+    }
298
+  }
299
+  
300
+  mp_p->mp_page_c += page_n;
301
+  
302
+  SET_POINTER(error_p, MPOOL_ERROR_NONE);
303
+  return mem;
304
+}
305
+
306
+/*
307
+ * static int free_pages
308
+ *
309
+ * DESCRIPTION:
310
+ *
311
+ * Free previously allocated pages of memory.
312
+ *
313
+ * RETURNS:
314
+ *
315
+ * Success - MPOOL_ERROR_NONE
316
+ *
317
+ * Failure - Mpool error code
318
+ *
319
+ * ARGUMENTS:
320
+ *
321
+ * pages <-> Pointer to memory pages that we are freeing.
322
+ *
323
+ * size -> Size of the block that we are freeing.
324
+ *
325
+ * sbrk_b -> Set to one if the pages were allocated with sbrk else mmap.
326
+ */
327
+static	int	free_pages(void *pages, const unsigned long size,
328
+			   const int sbrk_b)
329
+{
330
+  if (! sbrk_b) {
331
+    (void)munmap((caddr_t)pages, size);
332
+  }
333
+  
334
+  return MPOOL_ERROR_NONE;
335
+}
336
+
337
+/*
338
+ * static int check_magic
339
+ *
340
+ * DESCRIPTION:
341
+ *
342
+ * Check for the existance of the magic ID in a memory pointer.
343
+ *
344
+ * RETURNS:
345
+ *
346
+ * Success - MPOOL_ERROR_NONE
347
+ *
348
+ * Failure - Mpool error code
349
+ *
350
+ * ARGUMENTS:
351
+ *
352
+ * addr -> Address inside of the block that we are tryign to locate.
353
+ *
354
+ * size -> Size of the block.
355
+ */
356
+static	int	check_magic(const void *addr, const unsigned long size)
357
+{
358
+  const unsigned char	*mem_p;
359
+  
360
+  /* set our starting point */
361
+  mem_p = (unsigned char *)addr + size;
362
+  
363
+  if (*mem_p == FENCE_MAGIC0 && *(mem_p + 1) == FENCE_MAGIC1) {
364
+    return MPOOL_ERROR_NONE;
365
+  }
366
+  else {
367
+    return MPOOL_ERROR_PNT_OVER;
368
+  }
369
+}
370
+
371
+/*
372
+ * static void write_magic
373
+ *
374
+ * DESCRIPTION:
375
+ *
376
+ * Write the magic ID to the address.
377
+ *
378
+ * RETURNS:
379
+ *
380
+ * None.
381
+ *
382
+ * ARGUMENTS:
383
+ *
384
+ * addr -> Address where to write the magic.
385
+ */
386
+static	void	write_magic(const void *addr)
387
+{
388
+  *(unsigned char *)addr = FENCE_MAGIC0;
389
+  *((unsigned char *)addr + 1) = FENCE_MAGIC1;
390
+}
391
+
392
+/*
393
+ * static void free_pointer
394
+ *
395
+ * DESCRIPTION:
396
+ *
397
+ * Moved a pointer into our free lists.
398
+ *
399
+ * RETURNS:
400
+ *
401
+ * Success - MPOOL_ERROR_NONE
402
+ *
403
+ * Failure - Mpool error code
404
+ *
405
+ * ARGUMENTS:
406
+ *
407
+ * mp_p <-> Pointer to the memory pool.
408
+ *
409
+ * addr <-> Address where to write the magic.  We may write a next
410
+ * pointer to it.
411
+ *
412
+ * size -> Size of the address space.
413
+ */
414
+static	int	free_pointer(mpool_t *mp_p, void *addr,
415
+			     const unsigned long size)
416
+{
417
+  unsigned int	bit_n;
418
+  unsigned long	real_size;
419
+  mpool_free_t	free_pnt;
420
+  
421
+#ifdef DEBUG
422
+  (void)printf("freeing a block at %lx of %lu bytes\n", (long)addr, size);
423
+#endif
424
+  
425
+  if (size == 0) {
426
+    return MPOOL_ERROR_NONE;
427
+  }
428
+  
429
+  /*
430
+   * if the user size is larger then can fit in an entire block then
431
+   * we change the size
432
+   */
433
+  if (size > MAX_BLOCK_USER_MEMORY(mp_p)) {
434
+    real_size = SIZE_OF_PAGES(mp_p, PAGES_IN_SIZE(mp_p, size)) -
435
+      sizeof(mpool_block_t);
436
+  }
437
+  else {
438
+    real_size = size;
439
+  }
440
+  
441
+  /*
442
+   * We use a specific free bits calculation here because if we are
443
+   * freeing 10 bytes then we will be putting it into the 8-byte free
444
+   * list and not the 16 byte list.  size_to_bits(10) will return 4
445
+   * instead of 3.
446
+   */
447
+  bit_n = size_to_free_bits(real_size);
448
+  
449
+  /*
450
+   * Minimal error checking.  We could go all the way through the
451
+   * list however this might be prohibitive.
452
+   */
453
+  if (mp_p->mp_free[bit_n] == addr) {
454
+    return MPOOL_ERROR_IS_FREE;
455
+  }
456
+  
457
+  /* add the freed pointer to the free list */
458
+  if (bit_n < min_bit_free_next) {
459
+    /*
460
+     * Yes we know this will lose 99% of the allocations but what else
461
+     * can we do?  No space for a next pointer.
462
+     */
463
+    if (mp_p->mp_free[bit_n] == NULL) {
464
+      mp_p->mp_free[bit_n] = addr;
465
+    }
466
+  }
467
+  else if (bit_n < min_bit_free_size) {
468
+    /* we copy, not assign, to maintain the free list */
469
+    memcpy(addr, mp_p->mp_free + bit_n, sizeof(void *));
470
+    mp_p->mp_free[bit_n] = addr;
471
+  }
472
+  else {
473
+    
474
+    /* setup our free list structure */
475
+    free_pnt.mf_next_p = mp_p->mp_free[bit_n];
476
+    free_pnt.mf_size = real_size;
477
+    
478
+    /* we copy the structure in since we don't know about alignment */
479
+    memcpy(addr, &free_pnt, sizeof(free_pnt));
480
+    mp_p->mp_free[bit_n] = addr;
481
+  }
482
+  
483
+  return MPOOL_ERROR_NONE;
484
+}
485
+
486
+/*
487
+ * static int split_block
488
+ *
489
+ * DESCRIPTION:
490
+ *
491
+ * When freeing space in a multi-block chunk we have to create new
492
+ * blocks out of the upper areas being freed.
493
+ *
494
+ * RETURNS:
495
+ *
496
+ * Success - MPOOL_ERROR_NONE
497
+ *
498
+ * Failure - Mpool error code
499
+ *
500
+ * ARGUMENTS:
501
+ *
502
+ * mp_p <-> Pointer to the memory pool.
503
+ *
504
+ * free_addr -> Address that we are freeing.
505
+ *
506
+ * size -> Size of the space that we are taking from address.
507
+ */
508
+static	int	split_block(mpool_t *mp_p, void *free_addr,
509
+			    const unsigned long size)
510
+{
511
+  mpool_block_t	*block_p, *new_block_p;
512
+  int		ret, page_n;
513
+  void		*end_p;
514
+  
515
+  /*
516
+   * 1st we find the block pointer from our free addr.  At this point
517
+   * the pointer must be the 1st one in the block if it is spans
518
+   * multiple blocks.
519
+   */
520
+  block_p = (mpool_block_t *)((char *)free_addr - sizeof(mpool_block_t));
521
+  if (block_p->mb_magic != BLOCK_MAGIC
522
+      || block_p->mb_magic2 != BLOCK_MAGIC) {
523
+    return MPOOL_ERROR_POOL_OVER;
524
+  }
525
+  
526
+  page_n = PAGES_IN_SIZE(mp_p, size);
527
+  
528
+  /* we are creating a new block structure for the 2nd ... */
529
+  new_block_p = (mpool_block_t *)((char *)block_p +
530
+				  SIZE_OF_PAGES(mp_p, page_n));
531
+  new_block_p->mb_magic = BLOCK_MAGIC;
532
+  /* New bounds is 1st block bounds.  The 1st block's is reset below. */
533
+  new_block_p->mb_bounds_p = block_p->mb_bounds_p;
534
+  /* Continue the linked list.  The 1st block will point to us below. */
535
+  new_block_p->mb_next_p = block_p->mb_next_p;
536
+  new_block_p->mb_magic2 = BLOCK_MAGIC;
537
+  
538
+  /* bounds for the 1st block are reset to the 1st page only */
539
+  block_p->mb_bounds_p = (char *)new_block_p;
540
+  /* the next block pointer for the 1st block is now the new one */
541
+  block_p->mb_next_p = new_block_p;
542
+  
543
+  /* only free the space in the 1st block if it is only 1 block in size */
544
+  if (page_n == 1) {
545
+    /* now free the rest of the 1st block block */
546
+    end_p = (char *)free_addr + size;
547
+    ret = free_pointer(mp_p, end_p,
548
+		       (char *)block_p->mb_bounds_p - (char *)end_p);
549
+    if (ret != MPOOL_ERROR_NONE) {
550
+      return ret;
551
+    }
552
+  }
553
+  
554
+  /* now free the rest of the block */
555
+  ret = free_pointer(mp_p, FIRST_ADDR_IN_BLOCK(new_block_p),
556
+		     MEMORY_IN_BLOCK(new_block_p));
557
+  if (ret != MPOOL_ERROR_NONE) {
558
+    return ret;
559
+  }
560
+  
561
+  return MPOOL_ERROR_NONE;
562
+}
563
+
564
+/*
565
+ * static void *get_space
566
+ *
567
+ * DESCRIPTION:
568
+ *
569
+ * Moved a pointer into our free lists.
570
+ *
571
+ * RETURNS:
572
+ *
573
+ * Success - New address that we can use.
574
+ *
575
+ * Failure - NULL
576
+ *
577
+ * ARGUMENTS:
578
+ *
579
+ * mp_p <-> Pointer to the memory pool.
580
+ *
581
+ * byte_size -> Size of the address space that we need.
582
+ *
583
+ * error_p <- Pointer to integer which, if not NULL, will be set with
584
+ * a mpool error code.
585
+ */
586
+static	void	*get_space(mpool_t *mp_p, const unsigned long byte_size,
587
+			   int *error_p)
588
+{
589
+  mpool_block_t	*block_p;
590
+  mpool_free_t	free_pnt;
591
+  int		ret;
592
+  unsigned long	size;
593
+  unsigned int	bit_c, page_n, left;
594
+  void		*free_addr = NULL, *free_end;
595
+  
596
+  size = byte_size;
597
+  while ((size & (sizeof(void *) - 1)) > 0) {
598
+    size++;
599
+  }
600
+  
601
+  /*
602
+   * First we check the free lists looking for something with enough
603
+   * pages.  Maybe we should only look X bits higher in the list.
604
+   *
605
+   * XXX: this is where we'd do the best fit.  We'd look for the
606
+   * closest match.  We then could put the rest of the allocation that
607
+   * we did not use in a lower free list.  Have a define which states
608
+   * how deep in the free list to go to find the closest match.
609
+   */
610
+  for (bit_c = size_to_bits(size); bit_c <= MAX_BITS; bit_c++) {
611
+    if (mp_p->mp_free[bit_c] != NULL) {
612
+      free_addr = mp_p->mp_free[bit_c];
613
+      break;
614
+    }
615
+  }
616
+  
617
+  /*
618
+   * If we haven't allocated any blocks or if the last block doesn't
619
+   * have enough memory then we need a new block.
620
+   */
621
+  if (bit_c > MAX_BITS) {
622
+    
623
+    /* we need to allocate more space */
624
+    
625
+    page_n = PAGES_IN_SIZE(mp_p, size);
626
+    
627
+    /* now we try and get the pages we need/want */
628
+    block_p = alloc_pages(mp_p, page_n, error_p);
629
+    if (block_p == NULL) {
630
+      /* error_p set in alloc_pages */
631
+      return NULL;
632
+    }
633
+    
634
+    /* init the block header */
635
+    block_p->mb_magic = BLOCK_MAGIC;
636
+    block_p->mb_bounds_p = (char *)block_p + SIZE_OF_PAGES(mp_p, page_n);
637
+    block_p->mb_next_p = mp_p->mp_first_p;
638
+    block_p->mb_magic2 = BLOCK_MAGIC;
639
+    
640
+    /*
641
+     * We insert it into the front of the queue.  We could add it to
642
+     * the end but there is not much use.
643
+     */
644
+    mp_p->mp_first_p = block_p;
645
+    if (mp_p->mp_last_p == NULL) {
646
+      mp_p->mp_last_p = block_p;
647
+    }
648
+    
649
+    free_addr = FIRST_ADDR_IN_BLOCK(block_p);
650
+    
651
+#ifdef DEBUG
652
+    (void)printf("had to allocate space for %lx of %lu bytes\n",
653
+		 (long)free_addr, size);
654
+#endif
655
+
656
+    free_end = (char *)free_addr + size;
657
+    left = (char *)block_p->mb_bounds_p - (char *)free_end;
658
+  }
659
+  else {
660
+    
661
+    if (bit_c < min_bit_free_next) {
662
+      mp_p->mp_free[bit_c] = NULL;
663
+      /* calculate the number of left over bytes */
664
+      left = bits_to_size(bit_c) - size;
665
+    }
666
+    else if (bit_c < min_bit_free_next) {
667
+      /* grab the next pointer from the freed address into our list */
668
+      memcpy(mp_p->mp_free + bit_c, free_addr, sizeof(void *));
669
+      /* calculate the number of left over bytes */
670
+      left = bits_to_size(bit_c) - size;
671
+    }
672
+    else {
673
+      /* grab the free structure from the address */
674
+      memcpy(&free_pnt, free_addr, sizeof(free_pnt));
675
+      mp_p->mp_free[bit_c] = free_pnt.mf_next_p;
676
+      
677
+      /* are we are splitting up a multiblock chunk into fewer blocks? */
678
+      if (PAGES_IN_SIZE(mp_p, free_pnt.mf_size) > PAGES_IN_SIZE(mp_p, size)) {
679
+	ret = split_block(mp_p, free_addr, size);
680
+	if (ret != MPOOL_ERROR_NONE) {
681
+	  SET_POINTER(error_p, ret);
682
+	  return NULL;
683
+	}
684
+	/* left over memory was taken care of in split_block */
685
+	left = 0;
686
+      }
687
+      else {
688
+	/* calculate the number of left over bytes */
689
+	left = free_pnt.mf_size - size;
690
+      }
691
+    }
692
+    
693
+#ifdef DEBUG
694
+    (void)printf("found a free block at %lx of %lu bytes\n",
695
+		 (long)free_addr, left + size);
696
+#endif
697
+    
698
+    free_end = (char *)free_addr + size;
699
+  }
700
+  
701
+  /*
702
+   * If we have memory left over then we free it so someone else can
703
+   * use it.  We do not free the space if we just allocated a
704
+   * multi-block chunk because we need to have every allocation easily
705
+   * find the start of the block.  Every user address % page-size
706
+   * should take us to the start of the block.
707
+   */
708
+  if (left > 0 && size <= MAX_BLOCK_USER_MEMORY(mp_p)) {
709
+    /* free the rest of the block */
710
+    ret = free_pointer(mp_p, free_end, left);
711
+    if (ret != MPOOL_ERROR_NONE) {
712
+      SET_POINTER(error_p, ret);
713
+      return NULL;
714
+    }
715
+  }
716
+  
717
+  /* update our bounds */
718
+  if (free_addr > mp_p->mp_bounds_p) {
719
+    mp_p->mp_bounds_p = free_addr;
720
+  }
721
+  else if (free_addr < mp_p->mp_min_p) {
722
+    mp_p->mp_min_p = free_addr;
723
+  }
724
+  
725
+  return free_addr;
726
+}
727
+
728
+/*
729
+ * static void *alloc_mem
730
+ *
731
+ * DESCRIPTION:
732
+ *
733
+ * Allocate space for bytes inside of an already open memory pool.
734
+ *
735
+ * RETURNS:
736
+ *
737
+ * Success - Pointer to the address to use.
738
+ *
739
+ * Failure - NULL
740
+ *
741
+ * ARGUMENTS:
742
+ *
743
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
744
+ * normal malloc.
745
+ *
746
+ * byte_size -> Number of bytes to allocate in the pool.  Must be >0.
747
+ *
748
+ * error_p <- Pointer to integer which, if not NULL, will be set with
749
+ * a mpool error code.
750
+ */
751
+static	void	*alloc_mem(mpool_t *mp_p, const unsigned long byte_size,
752
+			   int *error_p)
753
+{
754
+  unsigned long	size, fence;
755
+  void		*addr;
756
+  
757
+  /* make sure we have enough bytes */
758
+  if (byte_size < MIN_ALLOCATION) {
759
+    size = MIN_ALLOCATION;
760
+  }
761
+  else {
762
+    size = byte_size;
763
+  }
764
+  
765
+  if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
766
+    fence = 0;
767
+  }
768
+  else {
769
+    fence = FENCE_SIZE;
770
+  }
771
+  
772
+  /* get our free space + the space for the fence post */
773
+  addr = get_space(mp_p, size + fence, error_p);
774
+  if (addr == NULL) {
775
+    /* error_p set in get_space */
776
+    return NULL;
777
+  }
778
+  
779
+  if (! BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
780
+    write_magic((char *)addr + size);
781
+  }
782
+  
783
+  /* maintain our stats */
784
+  mp_p->mp_alloc_c++;
785
+  mp_p->mp_user_alloc += size;
786
+  if (mp_p->mp_user_alloc > mp_p->mp_max_alloc) {
787
+    mp_p->mp_max_alloc = mp_p->mp_user_alloc;
788
+  }
789
+  
790
+  SET_POINTER(error_p, MPOOL_ERROR_NONE);
791
+  return addr;
792
+}
793
+
794
+/*
795
+ * static int free_mem
796
+ *
797
+ * DESCRIPTION:
798
+ *
799
+ * Free an address from a memory pool.
800
+ *
801
+ * RETURNS:
802
+ *
803
+ * Success - MPOOL_ERROR_NONE
804
+ *
805
+ * Failure - Mpool error code
806
+ *
807
+ * ARGUMENTS:
808
+ *
809
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
810
+ * normal free.
811
+ *
812
+ * addr <-> Address to free.
813
+ *
814
+ * size -> Size of the address being freed.
815
+ */
816
+static	int	free_mem(mpool_t *mp_p, void *addr, const unsigned long size)
817
+{
818
+  unsigned long	old_size, fence;
819
+  int		ret;
820
+  mpool_block_t	*block_p;
821
+  
822
+  /*
823
+   * If the size is larger than a block then the allocation must be at
824
+   * the front of the block.
825
+   */
826
+  if (size > MAX_BLOCK_USER_MEMORY(mp_p)) {
827
+    block_p = (mpool_block_t *)((char *)addr - sizeof(mpool_block_t));
828
+    if (block_p->mb_magic != BLOCK_MAGIC
829
+	|| block_p->mb_magic2 != BLOCK_MAGIC) {
830
+      return MPOOL_ERROR_POOL_OVER;
831
+    }
832
+  }
833
+  
834
+  /* make sure we have enough bytes */
835
+  if (size < MIN_ALLOCATION) {
836
+    old_size = MIN_ALLOCATION;
837
+  }
838
+  else {
839
+    old_size = size;
840
+  }
841
+  
842
+  /* if we are packing the pool smaller */
843
+  if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
844
+    fence = 0;
845
+  }
846
+  else {
847
+    /* find the user's magic numbers if they were written */
848
+    ret = check_magic(addr, old_size);
849
+    if (ret != MPOOL_ERROR_NONE) { 
850
+      return ret;
851
+    }
852
+    fence = FENCE_SIZE;
853
+  }
854
+  
855
+  /* now we free the pointer */
856
+  ret = free_pointer(mp_p, addr, old_size + fence);
857
+  if (ret != MPOOL_ERROR_NONE) {
858
+    return ret;
859
+  }
860
+  mp_p->mp_user_alloc -= old_size;
861
+  
862
+  /* adjust our stats */
863
+  mp_p->mp_alloc_c--;
864
+  
865
+  return MPOOL_ERROR_NONE;
866
+}
867
+
868
+/***************************** exported routines *****************************/
869
+
870
+/*
871
+ * mpool_t *mpool_open
872
+ *
873
+ * DESCRIPTION:
874
+ *
875
+ * Open/allocate a new memory pool.
876
+ *
877
+ * RETURNS:
878
+ *
879
+ * Success - Pool pointer which must be passed to mpool_close to
880
+ * deallocate.
881
+ *
882
+ * Failure - NULL
883
+ *
884
+ * ARGUMENTS:
885
+ *
886
+ * flags -> Flags to set attributes of the memory pool.  See the top
887
+ * of mpool.h.
888
+ *
889
+ * page_size -> Set the internal memory page-size.  This must be a
890
+ * multiple of the getpagesize() value.  Set to 0 for the default.
891
+ *
892
+ * start_addr -> Starting address to try and allocate memory pools.
893
+ * This is ignored if the MPOOL_FLAG_USE_SBRK is enabled.
894
+ *
895
+ * error_p <- Pointer to integer which, if not NULL, will be set with
896
+ * a mpool error code.
897
+ */
898
+mpool_t	*mpool_open(const unsigned int flags, const unsigned int page_size,
899
+		    void *start_addr, int *error_p)
900
+{
901
+  mpool_block_t	*block_p;
902
+  int		page_n, ret;
903
+  mpool_t	mp, *mp_p;
904
+  void		*free_addr;
905
+  
906
+  if (! enabled_b) {
907
+    startup();
908
+  }
909
+  
910
+  /* zero our temp struct */
911
+  memset(&mp, 0, sizeof(mp));
912
+  
913
+  mp.mp_magic = MPOOL_MAGIC;
914
+  mp.mp_flags = flags;
915
+  mp.mp_alloc_c = 0;
916
+  mp.mp_user_alloc = 0;
917
+  mp.mp_max_alloc = 0;
918
+  mp.mp_page_c = 0;
919
+  /* mp.mp_page_size set below */
920
+  /* mp.mp_blocks_bit_n set below */
921
+  /* mp.mp_fd set below */
922
+  /* mp.mp_top set below */
923
+  /* mp.mp_addr set below */
924
+  mp.mp_log_func = NULL;
925
+  mp.mp_min_p = NULL;
926
+  mp.mp_bounds_p = NULL;
927
+  mp.mp_first_p = NULL;
928
+  mp.mp_last_p = NULL;
929
+  mp.mp_magic2 = MPOOL_MAGIC;
930
+  
931
+  /* get and sanity check our page size */
932
+  if (page_size > 0) {
933
+    mp.mp_page_size = page_size;
934
+    if (mp.mp_page_size % getpagesize() != 0) {
935
+      SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
936
+      return NULL;
937
+    }
938
+  }
939
+  else {
940
+    mp.mp_page_size = getpagesize() * DEFAULT_PAGE_MULT;
941
+    if (mp.mp_page_size % 1024 != 0) {
942
+      SET_POINTER(error_p, MPOOL_ERROR_PAGE_SIZE);
943
+      return NULL;
944
+    }
945
+  }
946
+  
947
+  if (BIT_IS_SET(flags, MPOOL_FLAG_USE_SBRK)) {
948
+    mp.mp_fd = -1;
949
+    mp.mp_addr = NULL;
950
+    mp.mp_top = 0;
951
+  }
952
+  else {
953
+    /* open dev-zero for our mmaping */
954
+    mp.mp_fd = open("/dev/zero", O_RDWR, 0);
955
+    if (mp.mp_fd < 0) {
956
+      SET_POINTER(error_p, MPOOL_ERROR_OPEN_ZERO);
957
+      return NULL;
958
+    }
959
+    mp.mp_addr = start_addr;
960
+    /* we start at the front of the file */
961
+    mp.mp_top = 0;
962
+  }
963
+  
964
+  /*
965
+   * Find out how many pages we need for our mpool structure.
966
+   *
967
+   * NOTE: this adds possibly unneeded space for mpool_block_t which
968
+   * may not be in this block.
969
+   */
970
+  page_n = PAGES_IN_SIZE(&mp, sizeof(mpool_t));
971
+  
972
+  /* now allocate us space for the actual struct */
973
+  mp_p = alloc_pages(&mp, page_n, error_p);
974
+  if (mp_p == NULL) {
975
+    if (mp.mp_fd >= 0) {
976
+      (void)close(mp.mp_fd);
977
+      mp.mp_fd = -1;
978
+    }
979
+    return NULL;
980
+  }
981
+  
982
+  /*
983
+   * NOTE: we do not normally free the rest of the block here because
984
+   * we want to lesson the chance of an allocation overwriting the
985
+   * main structure.
986
+   */
987
+  if (BIT_IS_SET(flags, MPOOL_FLAG_HEAVY_PACKING)) {
988
+    
989
+    /* we add a block header to the front of the block */
990
+    block_p = (mpool_block_t *)mp_p;
991
+    
992
+    /* init the block header */
993
+    block_p->mb_magic = BLOCK_MAGIC;
994
+    block_p->mb_bounds_p = (char *)block_p + SIZE_OF_PAGES(&mp, page_n);
995
+    block_p->mb_next_p = NULL;
996
+    block_p->mb_magic2 = BLOCK_MAGIC;
997
+    
998
+    /* the mpool pointer is then the 2nd thing in the block */
999
+    mp_p = FIRST_ADDR_IN_BLOCK(block_p);
1000
+    free_addr = (char *)mp_p + sizeof(mpool_t);
1001
+    
1002
+    /* free the rest of the block */
1003
+    ret = free_pointer(&mp, free_addr,
1004
+		       (char *)block_p->mb_bounds_p - (char *)free_addr);
1005
+    if (ret != MPOOL_ERROR_NONE) {
1006
+      if (mp.mp_fd >= 0) {
1007
+	(void)close(mp.mp_fd);
1008
+	mp.mp_fd = -1;
1009
+      }
1010
+      /* NOTE: after this line mp_p will be invalid */
1011
+      (void)free_pages(block_p, SIZE_OF_PAGES(&mp, page_n),
1012
+		       BIT_IS_SET(flags, MPOOL_FLAG_USE_SBRK));
1013
+      SET_POINTER(error_p, ret);
1014
+      return NULL;
1015
+    }
1016
+    
1017
+    /*
1018
+     * NOTE: if we are HEAVY_PACKING then the 1st block with the mpool
1019
+     * header is not on the block linked list.
1020
+     */
1021
+    
1022
+    /* now copy our tmp structure into our new memory area */
1023
+    memcpy(mp_p, &mp, sizeof(mpool_t));
1024
+    
1025
+    /* we setup min/max to our current address which is as good as any */
1026
+    mp_p->mp_min_p = block_p;
1027
+    mp_p->mp_bounds_p = block_p->mb_bounds_p;
1028
+  }
1029
+  else {
1030
+    /* now copy our tmp structure into our new memory area */
1031
+    memcpy(mp_p, &mp, sizeof(mpool_t));
1032
+    
1033
+    /* we setup min/max to our current address which is as good as any */
1034
+    mp_p->mp_min_p = mp_p;
1035
+    mp_p->mp_bounds_p = (char *)mp_p + SIZE_OF_PAGES(mp_p, page_n);
1036
+  }
1037
+  
1038
+  SET_POINTER(error_p, MPOOL_ERROR_NONE);
1039
+  return mp_p;
1040
+}
1041
+
1042
+/*
1043
+ * int mpool_close
1044
+ *
1045
+ * DESCRIPTION:
1046
+ *
1047
+ * Close/free a memory allocation pool previously opened with
1048
+ * mpool_open.
1049
+ *
1050
+ * RETURNS:
1051
+ *
1052
+ * Success - MPOOL_ERROR_NONE
1053
+ *
1054
+ * Failure - Mpool error code
1055
+ *
1056
+ * ARGUMENTS:
1057
+ *
1058
+ * mp_p <-> Pointer to our memory pool.
1059
+ */
1060
+int	mpool_close(mpool_t *mp_p)
1061
+{
1062
+  mpool_block_t	*block_p, *next_p;
1063
+  void		*addr;
1064
+  unsigned long	size;
1065
+  int		ret, final = MPOOL_ERROR_NONE;
1066
+  
1067
+  /* special case, just return no-error */
1068
+  if (mp_p == NULL) {
1069
+    return MPOOL_ERROR_ARG_NULL;
1070
+  }
1071
+  if (mp_p->mp_magic != MPOOL_MAGIC) {
1072
+    return MPOOL_ERROR_PNT;
1073
+  }
1074
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1075
+    return MPOOL_ERROR_POOL_OVER;
1076
+  }
1077
+  
1078
+  if (mp_p->mp_log_func != NULL) {
1079
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_CLOSE, 0, 0, NULL, NULL, 0);
1080
+  }
1081
+  
1082
+  /*
1083
+   * NOTE: if we are HEAVY_PACKING then the 1st block with the mpool
1084
+   * header is not on the linked list.
1085
+   */
1086
+  
1087
+  /* free/invalidate the blocks */
1088
+  for (block_p = mp_p->mp_first_p; block_p != NULL; block_p = next_p) {
1089
+    if (block_p->mb_magic != BLOCK_MAGIC
1090
+	|| block_p->mb_magic2 != BLOCK_MAGIC) {
1091
+      final = MPOOL_ERROR_POOL_OVER;
1092
+      break;
1093
+    }
1094
+    block_p->mb_magic = 0;
1095
+    block_p->mb_magic2 = 0;
1096
+    /* record the next pointer because it might be invalidated below */
1097
+    next_p = block_p->mb_next_p;
1098
+    ret = free_pages(block_p, (char *)block_p->mb_bounds_p - (char *)block_p,
1099
+		     BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_USE_SBRK));
1100
+    if (ret != MPOOL_ERROR_NONE) {
1101
+      final = ret;
1102
+    }
1103
+  }
1104
+  
1105
+  /* close /dev/zero if necessary */
1106
+  if (mp_p->mp_fd >= 0) {
1107
+    (void)close(mp_p->mp_fd);
1108
+    mp_p->mp_fd = -1;
1109
+  }
1110
+  
1111
+  /* invalidate the mpool before we ditch it */
1112
+  mp_p->mp_magic = 0;
1113
+  mp_p->mp_magic2 = 0;
1114
+  
1115
+  /* last we munmap the mpool pointer itself */
1116
+  if (! BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_USE_SBRK)) {
1117
+    
1118
+    /* if we are heavy packing then we need to free the 1st block later */
1119
+    if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_HEAVY_PACKING)) {
1120
+      addr = (char *)mp_p - sizeof(mpool_block_t);
1121
+    }
1122
+    else {
1123
+      addr = mp_p;
1124
+    }
1125
+    size = SIZE_OF_PAGES(mp_p, PAGES_IN_SIZE(mp_p, sizeof(mpool_t)));
1126
+    
1127
+    (void)munmap((caddr_t)addr, size);
1128
+  }
1129
+  
1130
+  return final;
1131
+}
1132
+
1133
+/*
1134
+ * int mpool_clear
1135
+ *
1136
+ * DESCRIPTION:
1137
+ *
1138
+ * Wipe an opened memory pool clean so we can start again.
1139
+ *
1140
+ * RETURNS:
1141
+ *
1142
+ * Success - MPOOL_ERROR_NONE
1143
+ *
1144
+ * Failure - Mpool error code
1145
+ *
1146
+ * ARGUMENTS:
1147
+ *
1148
+ * mp_p <-> Pointer to our memory pool.
1149
+ */
1150
+int	mpool_clear(mpool_t *mp_p)
1151
+{
1152
+  mpool_block_t	*block_p;
1153
+  int		final = MPOOL_ERROR_NONE, bit_n, ret;
1154
+  void		*first_p;
1155
+  
1156
+  /* special case, just return no-error */
1157
+  if (mp_p == NULL) {
1158
+    return MPOOL_ERROR_ARG_NULL;
1159
+  }
1160
+  if (mp_p->mp_magic != MPOOL_MAGIC) {
1161
+    return MPOOL_ERROR_PNT;
1162
+  }
1163
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1164
+    return MPOOL_ERROR_POOL_OVER;
1165
+  }
1166
+  
1167
+  if (mp_p->mp_log_func != NULL) {
1168
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_CLEAR, 0, 0, NULL, NULL, 0);
1169
+  }
1170
+  
1171
+  /* reset all of our free lists */
1172
+  for (bit_n = 0; bit_n <= MAX_BITS; bit_n++) {
1173
+    mp_p->mp_free[bit_n] = NULL;
1174
+  }
1175
+  
1176
+  /* free the blocks */
1177
+  for (block_p = mp_p->mp_first_p;
1178
+       block_p != NULL;
1179
+       block_p = block_p->mb_next_p) {
1180
+    if (block_p->mb_magic != BLOCK_MAGIC
1181
+	|| block_p->mb_magic2 != BLOCK_MAGIC) {
1182
+      final = MPOOL_ERROR_POOL_OVER;
1183
+      break;
1184
+    }
1185
+    
1186
+    first_p = FIRST_ADDR_IN_BLOCK(block_p);
1187
+    
1188
+    /* free the memory */
1189
+    ret = free_pointer(mp_p, first_p, MEMORY_IN_BLOCK(block_p));
1190
+    if (ret != MPOOL_ERROR_NONE) {
1191
+      final = ret;
1192
+    }
1193
+  }
1194
+  
1195
+  return final;
1196
+}
1197
+
1198
+/*
1199
+ * void *mpool_alloc
1200
+ *
1201
+ * DESCRIPTION:
1202
+ *
1203
+ * Allocate space for bytes inside of an already open memory pool.
1204
+ *
1205
+ * RETURNS:
1206
+ *
1207
+ * Success - Pointer to the address to use.
1208
+ *
1209
+ * Failure - NULL
1210
+ *
1211
+ * ARGUMENTS:
1212
+ *
1213
+ * mp_p <-> Pointer to the memory pool
1214
+ *
1215
+ * byte_size -> Number of bytes to allocate in the pool.  Must be >0.
1216
+ *
1217
+ * error_p <- Pointer to integer which, if not NULL, will be set with
1218
+ * a mpool error code.
1219
+ */
1220
+void	*mpool_alloc(mpool_t *mp_p, const unsigned long byte_size,
1221
+		     int *error_p)
1222
+{
1223
+  struct FRAG *frag;
1224
+  
1225
+  if (!mp_p || mp_p->mp_magic != MPOOL_MAGIC) {
1226
+    SET_POINTER(error_p, MPOOL_ERROR_PNT);
1227
+    return NULL;
1228
+  }
1229
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1230
+    SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
1231
+    return NULL;
1232
+  }
1233
+  
1234
+  if (byte_size == 0) {
1235
+    SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
1236
+    return NULL;
1237
+  }
1238
+  
1239
+  frag = (struct FRAG *)alloc_mem(mp_p, byte_size + FRAG_OVERHEAD, error_p);
1240
+  
1241
+  if (mp_p->mp_log_func != NULL) {
1242
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_ALLOC, byte_size, 0, (void *)frag, NULL, 0);
1243
+  }
1244
+
1245
+  frag->frag_size = byte_size;
1246
+  return &frag->frag_ptr;
1247
+}
1248
+
1249
+/*
1250
+ * void *mpool_calloc
1251
+ *
1252
+ * DESCRIPTION:
1253
+ *
1254
+ * Allocate space for elements of bytes in the memory pool and zero
1255
+ * the space afterwards.
1256
+ *
1257
+ * RETURNS:
1258
+ *
1259
+ * Success - Pointer to the address to use.
1260
+ *
1261
+ * Failure - NULL
1262
+ *
1263
+ * ARGUMENTS:
1264
+ *
1265
+ * mp_p <-> Pointer to the memory pool.
1266
+ *
1267
+ * ele_n -> Number of elements to allocate.
1268
+ *
1269
+ * ele_size -> Number of bytes per element being allocated.
1270
+ *
1271
+ * error_p <- Pointer to integer which, if not NULL, will be set with
1272
+ * a mpool error code.
1273
+ */
1274
+void	*mpool_calloc(mpool_t *mp_p, const unsigned long ele_n,
1275
+		      const unsigned long ele_size, int *error_p)
1276
+{
1277
+  struct FRAG *frag;
1278
+  unsigned long	byte_size;
1279
+  
1280
+  if (!mp_p || mp_p->mp_magic != MPOOL_MAGIC) {
1281
+    SET_POINTER(error_p, MPOOL_ERROR_PNT);
1282
+    return NULL;
1283
+  }
1284
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1285
+    SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
1286
+    return NULL;
1287
+  }
1288
+  
1289
+  if (ele_n == 0 || ele_size == 0) {
1290
+    SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
1291
+    return NULL;
1292
+  }
1293
+  
1294
+  byte_size = ele_n * ele_size;
1295
+
1296
+  frag = alloc_mem(mp_p, byte_size + FRAG_OVERHEAD, error_p);
1297
+  if (frag != NULL) {
1298
+    memset(&frag->frag_ptr, 0, byte_size);
1299
+  }
1300
+
1301
+  if (mp_p->mp_log_func != NULL) {
1302
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_CALLOC, ele_size, ele_n, (void *)frag, NULL, 0);
1303
+  }
1304
+
1305
+  frag->frag_size = byte_size;
1306
+  return &frag->frag_ptr;
1307
+}
1308
+
1309
+/*
1310
+ * int mpool_free
1311
+ *
1312
+ * DESCRIPTION:
1313
+ *
1314
+ * Free an address from a memory pool.
1315
+ *
1316
+ * RETURNS:
1317
+ *
1318
+ * Success - MPOOL_ERROR_NONE
1319
+ *
1320
+ * Failure - Mpool error code
1321
+ *
1322
+ * ARGUMENTS:
1323
+ *
1324
+ * mp_p <-> Pointer to the memory pool.
1325
+ *
1326
+ * addr <-> Address to free.
1327
+ *
1328
+ * size -> Size of the address being freed.
1329
+ */
1330
+int	mpool_free(mpool_t *mp_p, void *addr)
1331
+{
1332
+  struct FRAG *frag = (struct FRAG *) (addr - FRAG_OVERHEAD);
1333
+
1334
+  if (!mp_p || mp_p->mp_magic != MPOOL_MAGIC) {
1335
+    return MPOOL_ERROR_PNT;
1336
+  }
1337
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1338
+    return MPOOL_ERROR_POOL_OVER;
1339
+  }
1340
+  
1341
+  if (mp_p->mp_log_func != NULL) {
1342
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_FREE, 0, 0, NULL, addr, 0);
1343
+  }
1344
+  
1345
+  if (addr == NULL) {
1346
+    return MPOOL_ERROR_ARG_NULL;
1347
+  }
1348
+
1349
+  return free_mem(mp_p, (void *)frag, frag->frag_size + FRAG_OVERHEAD);
1350
+}
1351
+
1352
+/*
1353
+ * void *mpool_resize
1354
+ *
1355
+ * DESCRIPTION:
1356
+ *
1357
+ * Reallocate an address in a mmeory pool to a new size.  This is
1358
+ * different from realloc in that it needs the old address' size.  If
1359
+ * you don't have it then you need to allocate new space, copy the
1360
+ * data, and free the old pointer yourself.
1361
+ *
1362
+ * RETURNS:
1363
+ *
1364
+ * Success - Pointer to the address to use.
1365
+ *
1366
+ * Failure - NULL
1367
+ *
1368
+ * ARGUMENTS:
1369
+ *
1370
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
1371
+ * normal realloc.
1372
+ *
1373
+ * old_addr -> Previously allocated address.
1374
+ *
1375
+ * old_byte_size -> Size of the old address.  Must be known, cannot be
1376
+ * 0.
1377
+ *
1378
+ * new_byte_size -> New size of the allocation.
1379
+ *
1380
+ * error_p <- Pointer to integer which, if not NULL, will be set with
1381
+ * a mpool error code.
1382
+ */
1383
+void	*mpool_resize(mpool_t *mp_p, void *old_addr,
1384
+		      const unsigned long new_byte_size,
1385
+		      int *error_p)
1386
+{
1387
+  unsigned long	copy_size, new_size, old_size, fence;
1388
+  struct FRAG *new_frag;
1389
+  mpool_block_t	*block_p;
1390
+  int		ret;
1391
+  struct FRAG *old_frag = (struct FRAG *)(old_addr - FRAG_OVERHEAD);
1392
+  unsigned long old_byte_size;
1393
+  
1394
+  if (!mp_p || mp_p->mp_magic != MPOOL_MAGIC) {
1395
+    SET_POINTER(error_p, MPOOL_ERROR_PNT);
1396
+    return NULL;
1397
+  }
1398
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1399
+    SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
1400
+    return NULL;
1401
+  }
1402
+  
1403
+  if (old_addr == NULL) {
1404
+    SET_POINTER(error_p, MPOOL_ERROR_ARG_NULL);
1405
+    return NULL;
1406
+  }
1407
+
1408
+  old_byte_size = old_frag->frag_size;
1409
+  if (old_byte_size == 0) {
1410
+    SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
1411
+    return NULL;
1412
+  }
1413
+  
1414
+  /*
1415
+   * If the size is larger than a block then the allocation must be at
1416
+   * the front of the block.
1417
+   */
1418
+  if (old_byte_size + FRAG_OVERHEAD > MAX_BLOCK_USER_MEMORY(mp_p)) {
1419
+    block_p = (mpool_block_t *)((char *)old_frag - sizeof(mpool_block_t));
1420
+    if (block_p->mb_magic != BLOCK_MAGIC
1421
+	|| block_p->mb_magic2 != BLOCK_MAGIC) {
1422
+      SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
1423
+      return NULL;
1424
+    }
1425
+  }
1426
+  
1427
+  /* make sure we have enough bytes */
1428
+  if (old_byte_size + FRAG_OVERHEAD < MIN_ALLOCATION) {
1429
+    old_size = MIN_ALLOCATION;
1430
+  }
1431
+  else {
1432
+    old_size = old_byte_size + FRAG_OVERHEAD;
1433
+  }
1434
+  
1435
+  /* verify that the size matches exactly if we can */
1436
+  if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
1437
+    fence = 0;
1438
+  }
1439
+  else if (old_size > 0) {
1440
+    ret = check_magic((void *)old_frag, old_size);
1441
+    if (ret != MPOOL_ERROR_NONE) {
1442
+      SET_POINTER(error_p, ret);
1443
+      return NULL;
1444
+    }
1445
+    fence = FENCE_SIZE;
1446
+  }
1447
+  
1448
+  /* make sure we have enough bytes */
1449
+  if (new_byte_size < MIN_ALLOCATION) {
1450
+    new_size = MIN_ALLOCATION;
1451
+  }
1452
+  else {
1453
+    new_size = new_byte_size;
1454
+  }
1455
+  
1456
+  /*
1457
+   * NOTE: we could here see if the size is the same or less and then
1458
+   * use the current memory and free the space above.  This is harder
1459
+   * than it sounds if we are changing the block size of the
1460
+   * allocation.
1461
+   */
1462
+  
1463
+  /* we need to get another address */
1464
+  new_frag = alloc_mem(mp_p, new_byte_size + FRAG_OVERHEAD, error_p);
1465
+  if (new_frag == NULL) {
1466
+    /* error_p set in mpool_alloc */
1467
+    return NULL;
1468
+  }
1469
+  
1470
+  if (new_byte_size > old_byte_size) {
1471
+    copy_size = old_byte_size;
1472
+  }
1473
+  else {
1474
+    copy_size = new_byte_size;
1475
+  }
1476
+  new_frag->frag_size = new_byte_size;
1477
+  memcpy(&new_frag->frag_ptr, old_addr, copy_size);
1478
+  
1479
+  /* free the old address */
1480
+  ret = free_mem(mp_p, (void *)old_frag, old_byte_size + FRAG_OVERHEAD);
1481
+  if (ret != MPOOL_ERROR_NONE) {
1482
+    /* if the old free failed, try and free the new address */
1483
+    (void)free_mem(mp_p, (void *)new_frag, new_byte_size + FRAG_OVERHEAD);
1484
+    SET_POINTER(error_p, ret);
1485
+    return NULL;
1486
+  }
1487
+  
1488
+  if (mp_p->mp_log_func != NULL) {
1489
+    mp_p->mp_log_func(mp_p, MPOOL_FUNC_RESIZE, new_byte_size,
1490
+		      0, (void *)new_frag, old_addr, old_byte_size);
1491
+  }
1492
+  
1493
+  SET_POINTER(error_p, MPOOL_ERROR_NONE);
1494
+  return &new_frag->frag_ptr;
1495
+}
1496
+
1497
+/*
1498
+ * int mpool_stats
1499
+ *
1500
+ * DESCRIPTION:
1501
+ *
1502
+ * Return stats from the memory pool.
1503
+ *
1504
+ * RETURNS:
1505
+ *
1506
+ * Success - MPOOL_ERROR_NONE
1507
+ *
1508
+ * Failure - Mpool error code
1509
+ *
1510
+ * ARGUMENTS:
1511
+ *
1512
+ * mp_p -> Pointer to the memory pool.
1513
+ *
1514
+ * page_size_p <- Pointer to an unsigned integer which, if not NULL,
1515
+ * will be set to the page-size of the pool.
1516
+ *
1517
+ * num_alloced_p <- Pointer to an unsigned long which, if not NULL,
1518
+ * will be set to the number of pointers currently allocated in pool.
1519
+ *
1520
+ * user_alloced_p <- Pointer to an unsigned long which, if not NULL,
1521
+ * will be set to the number of user bytes allocated in this pool.
1522
+ *
1523
+ * max_alloced_p <- Pointer to an unsigned long which, if not NULL,
1524
+ * will be set to the maximum number of user bytes that have been
1525
+ * allocated in this pool.
1526
+ *
1527
+ * tot_alloced_p <- Pointer to an unsigned long which, if not NULL,
1528
+ * will be set to the total amount of space (including administrative
1529
+ * overhead) used by the pool.
1530
+ */
1531
+int	mpool_stats(const mpool_t *mp_p, unsigned int *page_size_p,
1532
+		    unsigned long *num_alloced_p,
1533
+		    unsigned long *user_alloced_p,
1534
+		    unsigned long *max_alloced_p,
1535
+		    unsigned long *tot_alloced_p)
1536
+{
1537
+  if (mp_p == NULL) {
1538
+    return MPOOL_ERROR_ARG_NULL;
1539
+  }
1540
+  if (mp_p->mp_magic != MPOOL_MAGIC) {
1541
+    return MPOOL_ERROR_PNT;
1542
+  }
1543
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1544
+    return MPOOL_ERROR_POOL_OVER;
1545
+  }
1546
+  
1547
+  SET_POINTER(page_size_p, mp_p->mp_page_size);
1548
+  SET_POINTER(num_alloced_p, mp_p->mp_alloc_c);
1549
+  SET_POINTER(user_alloced_p, mp_p->mp_user_alloc);
1550
+  SET_POINTER(max_alloced_p, mp_p->mp_max_alloc);
1551
+  SET_POINTER(tot_alloced_p, SIZE_OF_PAGES(mp_p, mp_p->mp_page_c));
1552
+  
1553
+  return MPOOL_ERROR_NONE;
1554
+}
1555
+
1556
+/*
1557
+ * int mpool_set_log_func
1558
+ *
1559
+ * DESCRIPTION:
1560
+ *
1561
+ * Set a logging callback function to be called whenever there was a
1562
+ * memory transaction.  See mpool_log_func_t.
1563
+ *
1564
+ * RETURNS:
1565
+ *
1566
+ * Success - MPOOL_ERROR_NONE
1567
+ *
1568
+ * Failure - Mpool error code
1569
+ *
1570
+ * ARGUMENTS:
1571
+ *
1572
+ * mp_p <-> Pointer to the memory pool.
1573
+ *
1574
+ * log_func -> Log function (defined in mpool.h) which will be called
1575
+ * with each mpool transaction.
1576
+ */
1577
+int	mpool_set_log_func(mpool_t *mp_p, mpool_log_func_t log_func)
1578
+{
1579
+  if (mp_p == NULL) {
1580
+    return MPOOL_ERROR_ARG_NULL;
1581
+  }
1582
+  if (mp_p->mp_magic != MPOOL_MAGIC) {
1583
+    return MPOOL_ERROR_PNT;
1584
+  }
1585
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1586
+    return MPOOL_ERROR_POOL_OVER;
1587
+  }
1588
+  
1589
+  mp_p->mp_log_func = log_func;
1590
+  
1591
+  return MPOOL_ERROR_NONE;
1592
+}
1593
+
1594
+/*
1595
+ * int mpool_set_max_pages
1596
+ *
1597
+ * DESCRIPTION:
1598
+ *
1599
+ * Set the maximum number of pages that the library will use.  Once it
1600
+ * hits the limit it will return MPOOL_ERROR_NO_PAGES.
1601
+ *
1602
+ * NOTE: if the MPOOL_FLAG_HEAVY_PACKING is set then this max-pages
1603
+ * value will include the page with the mpool header structure in it.
1604
+ * If the flag is _not_ set then the max-pages will not include this
1605
+ * first page.
1606
+ *
1607
+ * RETURNS:
1608
+ *
1609
+ * Success - MPOOL_ERROR_NONE
1610
+ *
1611
+ * Failure - Mpool error code
1612
+ *
1613
+ * ARGUMENTS:
1614
+ *
1615
+ * mp_p <-> Pointer to the memory pool.
1616
+ *
1617
+ * max_pages -> Maximum number of pages used by the library.
1618
+ */
1619
+int	mpool_set_max_pages(mpool_t *mp_p, const unsigned int max_pages)
1620
+{
1621
+  if (mp_p == NULL) {
1622
+    return MPOOL_ERROR_ARG_NULL;
1623
+  }
1624
+  if (mp_p->mp_magic != MPOOL_MAGIC) {
1625
+    return MPOOL_ERROR_PNT;
1626
+  }
1627
+  if (mp_p->mp_magic2 != MPOOL_MAGIC) {
1628
+    return MPOOL_ERROR_POOL_OVER;
1629
+  }
1630
+  
1631
+  if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_HEAVY_PACKING)) {
1632
+    mp_p->mp_max_pages = max_pages;
1633
+  }
1634
+  else {
1635
+    /*
1636
+     * If we are not heavy-packing the pool then we don't count the
1637
+     * 1st page allocated which holds the mpool header structure.
1638
+     */
1639
+    mp_p->mp_max_pages = max_pages + 1;
1640
+  }
1641
+  
1642
+  return MPOOL_ERROR_NONE;
1643
+}
1644
+
1645
+/*
1646
+ * const char *mpool_strerror
1647
+ *
1648
+ * DESCRIPTION:
1649
+ *
1650
+ * Return the corresponding string for the error number.
1651
+ *
1652
+ * RETURNS:
1653
+ *
1654
+ * Success - String equivalient of the error.
1655
+ *
1656
+ * Failure - String "invalid error code"
1657
+ *
1658
+ * ARGUMENTS:
1659
+ *
1660
+ * error -> Error number that we are converting.
1661
+ */
1662
+const char	*mpool_strerror(const int error)
1663
+{
1664
+  switch (error) {
1665
+  case MPOOL_ERROR_NONE:
1666
+    return "no error";
1667
+    break;
1668
+  case MPOOL_ERROR_ARG_NULL:
1669
+    return "function argument is null";
1670
+    break;
1671
+  case MPOOL_ERROR_ARG_INVALID:
1672
+    return "function argument is invalid";
1673
+    break;
1674
+  case MPOOL_ERROR_PNT:
1675
+    return "invalid mpool pointer";
1676
+    break;
1677
+  case MPOOL_ERROR_POOL_OVER:
1678
+    return "mpool structure was overwritten";
1679
+    break;
1680
+  case MPOOL_ERROR_PAGE_SIZE:
1681
+    return "could not get system page-size";
1682
+    break;
1683
+  case MPOOL_ERROR_OPEN_ZERO:
1684
+    return "could not open /dev/zero";
1685
+    break;
1686
+  case MPOOL_ERROR_NO_MEM:
1687
+    return "no memory available";
1688
+    break;
1689
+  case MPOOL_ERROR_MMAP:
1690
+    return "problems with mmap";
1691
+    break;
1692
+  case MPOOL_ERROR_SIZE:
1693
+    return "error processing requested size";
1694
+    break;
1695
+  case MPOOL_ERROR_TOO_BIG:
1696
+    return "allocation exceeds pool max size";
1697
+    break;
1698
+  case MPOOL_ERROR_MEM:
1699
+    return "invalid memory address";
1700
+    break;
1701
+  case MPOOL_ERROR_MEM_OVER:
1702
+    return "memory lower bounds overwritten";
1703
+    break;
1704
+  case MPOOL_ERROR_NOT_FOUND:
1705
+    return "memory block not found in pool";
1706
+    break;
1707
+  case MPOOL_ERROR_IS_FREE:
1708
+    return "memory address has already been freed";
1709
+    break;
1710
+  case MPOOL_ERROR_BLOCK_STAT:
1711
+    return "invalid internal block status";
1712
+    break;
1713
+  case MPOOL_ERROR_FREE_ADDR:
1714
+    return "invalid internal free address";
1715
+    break;
1716
+  case MPOOL_ERROR_SBRK_CONTIG:
1717
+    return "sbrk did not return contiguous memory";
1718
+    break;
1719
+  case MPOOL_ERROR_NO_PAGES:
1720
+    return "no available pages left in pool";
1721
+    break;
1722
+  case MPOOL_ERROR_ALLOC:
1723
+    return "system alloc function failed";
1724
+    break;
1725
+  case MPOOL_ERROR_PNT_OVER:
1726
+    return "user pointer admin space overwritten";
1727
+    break;
1728
+  default:
1729
+    break;
1730
+  }
1731
+  
1732
+  return "invalid error code";
1733
+}
0 1734
new file mode 100644
... ...
@@ -0,0 +1,462 @@
0
+/*
1
+ * Memory pool defines.
2
+ *
3
+ * Copyright 1996 by Gray Watson.
4
+ *
5
+ * This file is part of the mpool package.
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for
8
+ * any purpose and without fee is hereby granted, provided that the
9
+ * above copyright notice and this permission notice appear in all
10
+ * copies, and that the name of Gray Watson not be used in advertising
11
+ * or publicity pertaining to distribution of the document or software
12
+ * without specific, written prior permission.
13
+ *
14
+ * Gray Watson makes no representations about the suitability of the
15
+ * software described herein for any purpose.  It is provided "as is"
16
+ * without express or implied warranty.
17
+ *
18
+ * The author may be reached via http://256.com/gray/
19
+ *
20
+ * $Id: mpool.h,v 1.4 2006/05/31 20:26:11 gray Exp $
21
+ */
22
+
23
+#ifndef __MPOOL_H__
24
+#define __MPOOL_H__
25
+
26
+#include <sys/types.h>
27
+
28
+/*
29
+ * mpool flags to mpool_alloc or mpool_set_attr
30
+ */
31
+
32
+/*
33
+ * Choose a best fit algorithm not first fit.  This takes more CPU
34
+ * time but will result in a tighter heap.
35
+ */
36
+#define MPOOL_FLAG_BEST_FIT		(1<<0)
37
+
38
+/*
39
+ * By default the library adds 2 bytes onto all allocations to insert
40
+ * a magic number that it can look for to determine how large a freed
41
+ * memory chunk is.  This flag indicates that few if any frees are
42
+ * going to be performed on the pool and to not waste memory on these
43
+ * bytes.
44
+ */
45
+#define MPOOL_FLAG_NO_FREE		(1<<1)
46
+
47
+/*
48
+ * This enables very heavy packing at the possible expense of CPU.
49
+ * This affects a number of parts of the library.
50
+ *
51
+ * By default the 1st page of memory is reserved for the main mpool
52
+ * structure.  This flag will cause the rest of the 1st block to be
53
+ * available for use as user memory.
54
+ *
55
+ * By default the library looks through the memory when freed looking
56
+ * for a magic value.  There is an internal max size that it will look
57
+ * and then it will give up.  This flag forces it to look until it
58
+ * finds it.
59
+ */
60
+#define MPOOL_FLAG_HEAVY_PACKING	(1<<2)
61
+
62
+/*
63
+ * Use sbrk not mmap to allocate pages.  This is not recommended for
64
+ * normal use.
65
+ */
66
+#define MPOOL_FLAG_USE_SBRK		(1<<3)
67
+
68
+/*
69
+ * Mpool error codes
70
+ */
71
+#define MPOOL_ERROR_NONE	1	/* no error */
72
+#define MPOOL_ERROR_ARG_NULL	2	/* function argument is null */
73
+#define MPOOL_ERROR_ARG_INVALID	3	/* function argument is invalid */
74
+#define MPOOL_ERROR_PNT		4	/* invalid mpool pointer */
75
+#define MPOOL_ERROR_POOL_OVER	5	/* mpool structure was overwritten */
76
+#define MPOOL_ERROR_PAGE_SIZE	6	/* could not get system page-size */
77
+#define MPOOL_ERROR_OPEN_ZERO	7	/* could not open /dev/zero */
78
+#define MPOOL_ERROR_NO_MEM	8	/* no memory available */
79
+#define MPOOL_ERROR_MMAP	9	/* problems with mmap */
80
+#define MPOOL_ERROR_SIZE	10	/* error processing requested size */
81
+#define MPOOL_ERROR_TOO_BIG	11	/* allocation exceeded max size */
82
+#define MPOOL_ERROR_MEM		12	/* invalid memory address */
83
+#define MPOOL_ERROR_MEM_OVER	13	/* memory lower bounds overwritten */
84
+#define MPOOL_ERROR_NOT_FOUND	14	/* memory block not found in pool */
85
+#define MPOOL_ERROR_IS_FREE	15	/* memory block already free */
86
+#define MPOOL_ERROR_BLOCK_STAT	16	/* invalid internal block status */
87
+#define MPOOL_ERROR_FREE_ADDR	17	/* invalid internal free address */
88
+#define MPOOL_ERROR_SBRK_CONTIG	18	/* sbrk did not return contiguous mem*/
89
+#define MPOOL_ERROR_NO_PAGES	19	/* ran out of pages in pool */
90
+#define MPOOL_ERROR_ALLOC	20	/* calloc,malloc,free,realloc failed */
91
+#define MPOOL_ERROR_PNT_OVER	21	/* pointer structure was overwritten */
92
+
93
+/*
94
+ * Mpool function IDs for the mpool_log_func callback function.
95
+ */
96
+#define MPOOL_FUNC_CLOSE	1	/* mpool_close function called */
97
+#define MPOOL_FUNC_CLEAR	2	/* mpool_clear function called */
98
+#define MPOOL_FUNC_ALLOC	3	/* mpool_alloc function called */
99
+#define MPOOL_FUNC_CALLOC	4	/* mpool_calloc function called */
100
+#define MPOOL_FUNC_FREE		5	/* mpool_free function called */
101
+#define MPOOL_FUNC_RESIZE	6	/* mpool_resize function called */
102
+
103
+/*
104
+ * void mpool_log_func_t
105
+ *
106
+ * DESCRIPTION:
107
+ *
108
+ * Mpool transaction log function.
109
+ *
110
+ * RETURNS:
111
+ *
112
+ * None.
113
+ *
114
+ * ARGUMENT:
115
+ *
116
+ * mp_p -> Associated mpool address.
117
+ *
118
+ * func_id -> Integer function ID which identifies which mpool
119
+ * function is being called.
120
+ *
121
+ * byte_size -> Optionally specified byte size.
122
+ *
123
+ * ele_n -> Optionally specified element number.  For mpool_calloc
124
+ * only.
125
+ *
126
+ * new_addr -> Optionally specified new address.  For mpool_alloc,
127
+ * mpool_calloc, and mpool_resize only.
128
+ *
129
+ * old_addr -> Optionally specified old address.  For mpool_resize and
130
+ * mpool_free only.
131
+ *
132
+ * old_byte_size -> Optionally specified old byte size.  For
133
+ * mpool_resize only.
134
+ */
135
+typedef void	(*mpool_log_func_t)(const void *mp_p,
136
+				    const int func_id,
137
+				    const unsigned long byte_size,
138
+				    const unsigned long ele_n,
139
+				    const void *old_addr, const void *new_addr,
140
+				    const unsigned long old_byte_size);
141
+
142
+#ifdef MPOOL_MAIN
143
+
144
+#include "mpool_loc.h"
145
+
146
+#else
147
+
148
+/* generic mpool type */
149
+typedef	void	mpool_t;
150
+
151
+#endif
152
+
153
+/*<<<<<<<<<<  The below prototypes are auto-generated by fillproto */
154
+
155
+/*
156
+ * mpool_t *mpool_open
157
+ *
158
+ * DESCRIPTION:
159
+ *
160
+ * Open/allocate a new memory pool.
161
+ *
162
+ * RETURNS:
163
+ *
164
+ * Success - Pool pointer which must be passed to mpool_close to
165
+ * deallocate.
166
+ *
167
+ * Failure - NULL
168
+ *
169
+ * ARGUMENTS:
170
+ *
171
+ * flags -> Flags to set attributes of the memory pool.  See the top
172
+ * of mpool.h.
173
+ *
174
+ * page_size -> Set the internal memory page-size.  This must be a
175
+ * multiple of the getpagesize() value.  Set to 0 for the default.
176
+ *
177
+ * start_addr -> Starting address to try and allocate memory pools.
178
+ * This is ignored if the MPOOL_FLAG_USE_SBRK is enabled.
179
+ *
180
+ * error_p <- Pointer to integer which, if not NULL, will be set with
181
+ * a mpool error code.
182
+ */
183
+extern
184
+mpool_t	*mpool_open(const unsigned int flags, const unsigned int page_size,
185
+		    void *start_addr, int *error_p);
186
+
187
+/*
188
+ * int mpool_close
189
+ *
190
+ * DESCRIPTION:
191
+ *
192
+ * Close/free a memory allocation pool previously opened with
193
+ * mpool_open.
194
+ *
195
+ * RETURNS:
196
+ *
197
+ * Success - MPOOL_ERROR_NONE
198
+ *
199
+ * Failure - Mpool error code
200
+ *
201
+ * ARGUMENTS:
202
+ *
203
+ * mp_p <-> Pointer to our memory pool.
204
+ */
205
+extern
206
+int	mpool_close(mpool_t *mp_p);
207
+
208
+/*
209
+ * int mpool_clear
210
+ *
211
+ * DESCRIPTION:
212
+ *
213
+ * Wipe an opened memory pool clean so we can start again.
214
+ *
215
+ * RETURNS:
216
+ *
217
+ * Success - MPOOL_ERROR_NONE
218
+ *
219
+ * Failure - Mpool error code
220
+ *
221
+ * ARGUMENTS:
222
+ *
223
+ * mp_p <-> Pointer to our memory pool.
224
+ */
225
+extern
226
+int	mpool_clear(mpool_t *mp_p);
227
+
228
+/*
229
+ * void *mpool_alloc
230
+ *
231
+ * DESCRIPTION:
232
+ *
233
+ * Allocate space for bytes inside of an already open memory pool.
234
+ *
235
+ * RETURNS:
236
+ *
237
+ * Success - Pointer to the address to use.
238
+ *
239
+ * Failure - NULL
240
+ *
241
+ * ARGUMENTS:
242
+ *
243
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
244
+ * normal malloc.
245
+ *
246
+ * byte_size -> Number of bytes to allocate in the pool.  Must be >0.
247
+ *
248
+ * error_p <- Pointer to integer which, if not NULL, will be set with
249
+ * a mpool error code.
250
+ */
251
+extern
252
+void	*mpool_alloc(mpool_t *mp_p, const unsigned long byte_size,
253
+		     int *error_p);
254
+
255
+/*
256
+ * void *mpool_calloc
257
+ *
258
+ * DESCRIPTION:
259
+ *
260
+ * Allocate space for elements of bytes in the memory pool and zero
261
+ * the space afterwards.
262
+ *
263
+ * RETURNS:
264
+ *
265
+ * Success - Pointer to the address to use.
266
+ *
267
+ * Failure - NULL
268
+ *
269
+ * ARGUMENTS:
270
+ *
271
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
272
+ * normal calloc.
273
+ *
274
+ * ele_n -> Number of elements to allocate.
275
+ *
276
+ * ele_size -> Number of bytes per element being allocated.
277
+ *
278
+ * error_p <- Pointer to integer which, if not NULL, will be set with
279
+ * a mpool error code.
280
+ */
281
+extern
282
+void	*mpool_calloc(mpool_t *mp_p, const unsigned long ele_n,
283
+		      const unsigned long ele_size, int *error_p);
284
+
285
+/*
286
+ * int mpool_free
287
+ *
288
+ * DESCRIPTION:
289
+ *
290
+ * Free an address from a memory pool.
291
+ *
292
+ * RETURNS:
293
+ *
294
+ * Success - MPOOL_ERROR_NONE
295
+ *
296
+ * Failure - Mpool error code
297
+ *
298
+ * ARGUMENTS:
299
+ *
300
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
301
+ * normal free.
302
+ *
303
+ * addr <-> Address to free.
304
+ *
305
+ * size -> Size of the address being freed.
306
+ */
307
+extern
308
+int	mpool_free(mpool_t *mp_p, void *addr);
309
+
310
+/*
311
+ * void *mpool_resize
312
+ *
313
+ * DESCRIPTION:
314
+ *
315
+ * Reallocate an address in a mmeory pool to a new size.  This is
316
+ * different from realloc in that it needs the old address' size.  If
317
+ * you don't have it then you need to allocate new space, copy the
318
+ * data, and free the old pointer yourself.
319
+ *
320
+ * RETURNS:
321
+ *
322
+ * Success - Pointer to the address to use.
323
+ *
324
+ * Failure - NULL
325
+ *
326
+ * ARGUMENTS:
327
+ *
328
+ * mp_p <-> Pointer to the memory pool.  If NULL then it will do a
329
+ * normal realloc.
330
+ *
331
+ * old_addr -> Previously allocated address.
332
+ *
333
+ * old_byte_size -> Size of the old address.  Must be known, cannot be
334
+ * 0.
335
+ *
336
+ * new_byte_size -> New size of the allocation.
337
+ *
338
+ * error_p <- Pointer to integer which, if not NULL, will be set with
339
+ * a mpool error code.
340
+ */
341
+extern
342
+void	*mpool_resize(mpool_t *mp_p, void *old_addr,
343
+		      const unsigned long new_byte_size,
344
+		      int *error_p);
345
+
346
+/*
347
+ * int mpool_stats
348
+ *
349
+ * DESCRIPTION:
350
+ *
351
+ * Return stats from the memory pool.
352
+ *
353
+ * RETURNS:
354
+ *
355
+ * Success - MPOOL_ERROR_NONE
356
+ *
357
+ * Failure - Mpool error code
358
+ *
359
+ * ARGUMENTS:
360
+ *
361
+ * mp_p -> Pointer to the memory pool.
362
+ *
363
+ * page_size_p <- Pointer to an unsigned integer which, if not NULL,
364
+ * will be set to the page-size of the pool.
365
+ *
366
+ * num_alloced_p <- Pointer to an unsigned long which, if not NULL,
367
+ * will be set to the number of pointers currently allocated in pool.
368
+ *
369
+ * user_alloced_p <- Pointer to an unsigned long which, if not NULL,
370
+ * will be set to the number of user bytes allocated in this pool.
371
+ *
372
+ * max_alloced_p <- Pointer to an unsigned long which, if not NULL,
373
+ * will be set to the maximum number of user bytes that have been
374
+ * allocated in this pool.
375
+ *
376
+ * tot_alloced_p <- Pointer to an unsigned long which, if not NULL,
377
+ * will be set to the total amount of space (including administrative
378
+ * overhead) used by the pool.
379
+ */
380
+extern
381
+int	mpool_stats(const mpool_t *mp_p, unsigned int *page_size_p,
382
+		    unsigned long *num_alloced_p,
383
+		    unsigned long *user_alloced_p,
384
+		    unsigned long *max_alloced_p,
385
+		    unsigned long *tot_alloced_p);
386
+
387
+/*
388
+ * int mpool_set_log_func
389
+ *
390
+ * DESCRIPTION:
391
+ *
392
+ * Set a logging callback function to be called whenever there was a
393
+ * memory transaction.  See mpool_log_func_t.
394
+ *
395
+ * RETURNS:
396
+ *
397
+ * Success - MPOOL_ERROR_NONE
398
+ *
399
+ * Failure - Mpool error code
400
+ *
401
+ * ARGUMENTS:
402
+ *
403
+ * mp_p <-> Pointer to the memory pool.
404
+ *
405
+ * log_func -> Log function (defined in mpool.h) which will be called
406
+ * with each mpool transaction.
407
+ */
408
+extern
409
+int	mpool_set_log_func(mpool_t *mp_p, mpool_log_func_t log_func);
410
+
411
+/*
412
+ * int mpool_set_max_pages
413
+ *
414
+ * DESCRIPTION:
415
+ *
416
+ * Set the maximum number of pages that the library will use.  Once it
417
+ * hits the limit it will return MPOOL_ERROR_NO_PAGES.
418
+ *
419
+ * NOTE: if the MPOOL_FLAG_HEAVY_PACKING is set then this max-pages
420
+ * value will include the page with the mpool header structure in it.
421
+ * If the flag is _not_ set then the max-pages will not include this
422
+ * first page.
423
+ *
424
+ * RETURNS:
425
+ *
426
+ * Success - MPOOL_ERROR_NONE
427
+ *
428
+ * Failure - Mpool error code
429
+ *
430
+ * ARGUMENTS:
431
+ *
432
+ * mp_p <-> Pointer to the memory pool.
433
+ *
434
+ * max_pages -> Maximum number of pages used by the library.
435
+ */
436
+extern
437
+int	mpool_set_max_pages(mpool_t *mp_p, const unsigned int max_pages);
438
+
439
+/*
440
+ * const char *mpool_strerror
441
+ *
442
+ * DESCRIPTION:
443
+ *
444
+ * Return the corresponding string for the error number.
445
+ *
446
+ * RETURNS:
447
+ *
448
+ * Success - String equivalient of the error.
449
+ *
450
+ * Failure - String "invalid error code"
451
+ *
452
+ * ARGUMENTS:
453
+ *
454
+ * error -> Error number that we are converting.
455
+ */
456
+extern
457
+const char	*mpool_strerror(const int error);
458
+
459
+/*<<<<<<<<<<   This is end of the auto-generated output from fillproto. */
460
+
461
+#endif /* ! __MPOOL_H__ */
0 462
new file mode 100644
... ...
@@ -0,0 +1,116 @@
0
+/*
1
+ * Memory pool local defines.
2
+ *
3
+ * Copyright 1996 by Gray Watson.
4
+ *
5
+ * This file is part of the mpool package.
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for
8
+ * any purpose and without fee is hereby granted, provided that the
9
+ * above copyright notice and this permission notice appear in all
10
+ * copies, and that the name of Gray Watson not be used in advertising
11
+ * or publicity pertaining to distribution of the document or software
12
+ * without specific, written prior permission.
13
+ *
14
+ * Gray Watson makes no representations about the suitability of the
15
+ * software described herein for any purpose.  It is provided "as is"
16
+ * without express or implied warranty.
17
+ *
18
+ * The author may be reached via http://256.com/gray/
19
+ *
20
+ * $Id: mpool_loc.h,v 1.2 2005/05/20 20:08:54 gray Exp $
21
+ */
22
+
23
+#ifndef __MPOOL_LOC_H__
24
+#define __MPOOL_LOC_H__
25
+
26
+#define MPOOL_MAGIC	0xABACABA		/* magic for struct */
27
+#define BLOCK_MAGIC	0xB1B1007		/* magic for blocks */
28
+#define FENCE_MAGIC0	(unsigned char)(0xFAU)	/* 1st magic mem byte */
29
+#define FENCE_MAGIC1	(unsigned char)(0xD3U)	/* 2nd magic mem byte */
30
+
31
+#define FENCE_SIZE		2		/* fence space */
32
+#define MIN_ALLOCATION		(sizeof(mpool_free_t))	/* min alloc */
33
+#define MAX_FREE_SEARCH		10240		/* max size to search */
34
+#define MAX_FREE_LIST_SEARCH	100		/* max looking for free mem */ 
35
+
36
+/*
37
+ * bitflag tools for Variable and a Flag
38
+ */
39
+#define BIT_FLAG(x)		(1 << (x))
40
+#define BIT_SET(v,f)		(v) |= (f)
41
+#define BIT_CLEAR(v,f)		(v) &= ~(f)
42
+#define BIT_IS_SET(v,f)		((v) & (f))
43
+#define BIT_TOGGLE(v,f)		(v) ^= (f)
44
+
45
+#define SET_POINTER(pnt, val) \
46
+	do { \
47
+	  if ((pnt) != NULL) { \
48
+	    (*(pnt)) = (val); \
49
+          } \
50
+        } while(0)
51
+
52
+#define BLOCK_FLAG_USED		BIT_FLAG(0)		/* block is used */
53
+#define BLOCK_FLAG_FREE		BIT_FLAG(1)		/* block is free */
54
+
55
+#define DEFAULT_PAGE_MULT		16   /* pagesize = this * getpagesize*/
56
+
57
+/* How many pages SIZE bytes resides in.  We add in the block header. */
58
+#define PAGES_IN_SIZE(mp_p, size)	(((size) + sizeof(mpool_block_t) + \
59
+					  (mp_p)->mp_page_size - 1) / \
60
+					 (mp_p)->mp_page_size)
61
+#define SIZE_OF_PAGES(mp_p, page_n)	((page_n) * (mp_p)->mp_page_size)
62
+#define MAX_BITS	30		/* we only can allocate 1gb chunks */
63
+
64
+#define MAX_BLOCK_USER_MEMORY(mp_p)	((mp_p)->mp_page_size - \
65
+					 sizeof(mpool_block_t))
66
+#define FIRST_ADDR_IN_BLOCK(block_p)	(void *)((char *)(block_p) + \
67
+						 sizeof(mpool_block_t))
68
+#define MEMORY_IN_BLOCK(block_p)	((char *)(block_p)->mb_bounds_p - \
69
+					 ((char *)(block_p) + \
70
+					  sizeof(mpool_block_t)))
71
+
72
+typedef struct {
73
+  unsigned int		mp_magic;	/* magic number for struct */
74
+  unsigned int		mp_flags;	/* flags for the struct */
75
+  unsigned long		mp_alloc_c;	/* number of allocations */
76
+  unsigned long		mp_user_alloc;	/* user bytes allocated */
77
+  unsigned long		mp_max_alloc;	/* maximum user bytes allocated */
78
+  unsigned int		mp_page_c;	/* number of pages allocated */
79
+  unsigned int		mp_max_pages;	/* maximum number of pages to use */
80
+  unsigned int		mp_page_size;	/* page-size of our system */
81
+  int			mp_fd;		/* fd for /dev/zero if mmap-ing */
82
+  off_t			mp_top;		/* top of our allocations in fd */ 
83
+  mpool_log_func_t	mp_log_func;	/* log callback function */
84
+  void			*mp_addr;	/* current address for mmaping */
85
+  void			*mp_min_p;	/* min address in pool for checks */
86
+  void			*mp_bounds_p;	/* max address in pool for checks */
87
+  struct mpool_block_st	*mp_first_p;	/* first memory block we are using */
88
+  struct mpool_block_st	*mp_last_p;	/* last memory block we are using */
89
+  struct mpool_block_st	*mp_free[MAX_BITS + 1]; /* free lists based on size */
90
+  unsigned int		mp_magic2;	/* upper magic for overwrite sanity */
91
+} mpool_t;
92
+
93
+/* for debuggers to be able to interrogate the generic type in the .h file */
94
+typedef mpool_t	mpool_ext_t;
95
+
96
+/*
97
+ * Block header structure.  This structure *MUST* be long-word
98
+ * aligned.
99
+ */
100
+typedef struct mpool_block_st {
101
+  unsigned int		mb_magic;	/* magic number for block header */
102
+  void			*mb_bounds_p;	/* block boundary location */
103
+  struct mpool_block_st	*mb_next_p;	/* linked list next pointer */
104
+  unsigned int		mb_magic2;	/* upper magic for overwrite sanity */
105
+} mpool_block_t;
106
+
107
+/*
108
+ * Free list structure.
109
+ */
110
+typedef struct {
111
+  void			*mf_next_p;	/* pointer to the next free address */
112
+  unsigned long		mf_size;	/* size of the free block */
113
+} mpool_free_t;
114
+
115
+#endif /* ! __MPOOL_LOC_H__ */
0 116
new file mode 100644
... ...
@@ -0,0 +1,914 @@
0
+/*
1
+ * Memory pool test program.
2
+ *
3
+ * Copyright 1996 by Gray Watson.
4
+ *
5
+ * This file is part of the mpool package.
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for
8
+ * any purpose and without fee is hereby granted, provided that the
9
+ * above copyright notice and this permission notice appear in all
10
+ * copies, and that the name of Gray Watson not be used in advertising
11
+ * or publicity pertaining to distribution of the document or software
12
+ * without specific, written prior permission.
13
+ *
14
+ * Gray Watson makes no representations about the suitability of the
15
+ * software described herein for any purpose.  It is provided "as is"
16
+ * without express or implied warranty.
17
+ *
18
+ * The author may be reached via http://256.com/gray/
19
+ *
20
+ * $Id: mpool_t.c,v 1.2 2005/05/20 20:08:55 gray Exp $
21
+ */
22
+
23
+/*
24
+ * Test program for the malloc library.  Current it is interactive although
25
+ * should be script based.
26
+ */
27
+
28
+#include <errno.h>
29
+#include <stdio.h>
30
+#include <stdlib.h>
31
+#include <string.h>
32
+#include <time.h>
33
+#include <unistd.h>
34
+
35
+#include "mpool.h"
36
+
37
+#ifdef __GNUC__
38
+#ident "$Id: mpool_t.c,v 1.2 2005/05/20 20:08:55 gray Exp $"
39
+#else
40
+static char *rcs_id = "$Id: mpool_t.c,v 1.2 2005/05/20 20:08:55 gray Exp $";
41
+#endif
42
+
43
+#define DEFAULT_ITERATIONS	10000
44
+#define MAX_POINTERS		1024
45
+#define MAX_ALLOC		(1024 * 1024)
46
+#define MIN_AVAIL		10
47
+
48
+#define RANDOM_VALUE(x)		((random() % ((x) * 10)) / 10)
49
+
50
+/* pointer tracking structure */
51
+struct pnt_info_st {
52
+  long			pi_crc;			/* crc of storage */
53
+  long			pi_size;		/* size of storage */
54
+  void			*pi_pnt;		/* pnt to storage */
55
+  struct pnt_info_st	*pi_next;		/* pnt to next */
56
+};
57
+
58
+typedef struct pnt_info_st pnt_info_t;
59
+
60
+static	pnt_info_t	*pointer_grid;
61
+
62
+/* argument variables */
63
+static	int		best_fit_b = 0;			/* set best fit flag */
64
+static	int		heavy_pack_b = 0;		/* set heavy pack flg*/
65
+static	int		interactive_b = 0;		/* interactive flag */
66
+static	int		log_trxn_b = 0; 		/* log mem trxns */
67
+static	long		max_alloc = MAX_ALLOC;		/* amt of mem to use */
68
+static	int		max_pages_n = 0;		/* max # pages */
69
+static	int		use_malloc_b = 0; 		/* use system alloc */
70
+static	int		max_pointers = MAX_POINTERS;	/* # of pnts to use */
71
+static	int		no_free_b = 0;			/* set no free flag */
72
+static	long		page_size = 0;			/* mpool pagesize */
73
+static	int		use_sbrk_b = 0;			/* use sbrk not mmap */
74
+static	unsigned int	seed_random = 0;		/* random seed */
75
+static	int		default_iter_n = DEFAULT_ITERATIONS; /* # of iters */
76
+static	int		verbose_b = 0;			/* verbose flag */
77
+
78
+/*
79
+ * static long hex_to_long
80
+ *
81
+ * DESCRIPTION:
82
+ *
83
+ * Hexadecimal string to integer translation.
84
+ *
85
+ * RETURNS:
86
+ *
87
+ * Long value of converted hex string.
88
+ *
89
+ * ARGUMENTS:
90
+ *
91
+ * str -> Hex string we are converting.
92
+ */
93
+static	long	hex_to_long(const char *str)
94
+{
95
+  long		ret;
96
+  const char	*str_p = str;
97
+  
98
+  /* strip off spaces */
99
+  for (; *str_p == ' ' || *str_p == '\t'; str_p++) {
100
+  }
101
+  
102
+  /* skip a leading 0[xX] */
103
+  if (*str_p == '0' && (*(str_p + 1) == 'x' || *(str_p + 1) == 'X')) {
104
+    str_p += 2;
105
+  }
106
+  
107
+  for (ret = 0;; str_p++) {
108
+    if (*str_p >= '0' && *str_p <= '9') {
109
+      ret = ret * 16 + (*str_p - '0');
110
+    }
111
+    else if (*str_p >= 'a' && *str_p <= 'f') {
112
+      ret = ret * 16 + (*str_p - 'a' + 10);
113
+    }
114
+    else if (*str_p >= 'A' && *str_p <= 'F') {
115
+      ret = ret * 16 + (*str_p - 'A' + 10);
116
+    }
117
+    else {
118
+      break;
119
+    }
120
+  }
121
+  
122
+  return ret;
123
+}
124
+
125
+/*
126
+ * static void* get_address
127
+ *
128
+ * DESCRIPTION:
129
+ *
130
+ * Read an address from the user.
131
+ *
132
+ * RETURNS:
133
+ *
134
+ * Address read in from user.
135
+ *
136
+ * ARGUMENTS:
137
+ *
138
+ * None.
139
+ */
140
+static	void	*get_address(void)
141
+{
142
+  char	line[80];
143
+  void	*pnt;
144
+  
145
+  do {
146
+    (void)printf("Enter a hex address: ");
147
+    if (fgets(line, sizeof(line), stdin) == NULL) {
148
+      return NULL;
149
+    }
150
+  } while (line[0] == '\0');
151
+  
152
+  pnt = (void *)hex_to_long(line);
153
+  
154
+  return pnt;
155
+}
156
+
157
+/*
158
+ * static void do_random
159
+ *
160
+ * DESCRIPTION:
161
+ *
162
+ * Try ITER_N random program iterations, returns 1 on success else 0
163
+ *
164
+ * RETURNS:
165
+ *
166
+ * None.
167
+ *
168
+ * ARGUMENTS:
169
+ *
170
+ * pool <-> Out memory pool.
171
+ *
172
+ * iter_n -> Number of iterations to run.
173
+ */
174
+static	void	do_random(mpool_t *pool, const int iter_n)
175
+{
176
+  int		iter_c, free_c, ret;
177
+  long		max = max_alloc, amount;
178
+  char		*chunk_p;
179
+  void		*new_pnt;
180
+  pnt_info_t	*free_p, *used_p = NULL;
181
+  pnt_info_t	*pnt_p, *last_p;
182
+  
183
+  if (use_malloc_b) {
184
+    pointer_grid = (pnt_info_t *)malloc(sizeof(pnt_info_t) * max_pointers);
185
+  }
186
+  else {
187
+    pointer_grid = (pnt_info_t *)mpool_alloc(pool,
188
+					     sizeof(pnt_info_t) * max_pointers,
189
+					     &ret);
190
+  }
191
+  if (pointer_grid == NULL) {
192
+    (void)printf("mpool_t: problems allocating %d pointer slots: %s\n",
193
+		 max_pointers, strerror(errno));
194
+    return;
195
+  }
196
+  
197
+  /* initialize free list */
198
+  free_p = pointer_grid;
199
+  for (pnt_p = pointer_grid; pnt_p < pointer_grid + max_pointers; pnt_p++) {
200
+    pnt_p->pi_size = 0;
201
+    pnt_p->pi_pnt = NULL;
202
+    pnt_p->pi_next = pnt_p + 1;
203
+  }
204
+  /* redo the last next pointer */
205
+  (pnt_p - 1)->pi_next = NULL;
206
+  free_c = max_pointers;
207
+  
208
+  for (iter_c = 0; iter_c < iter_n;) {
209
+    int		which;
210
+    
211
+    /* special case when doing non-linear stuff, sbrk took all memory */
212
+    if (max < MIN_AVAIL && free_c == max_pointers) {
213
+      break;
214
+    }
215
+    
216
+    if (free_c < max_pointers && used_p == NULL) {
217
+      (void)fprintf(stderr, "mpool_t: problem with test program free list\n");
218
+      exit(1);
219
+    }
220
+    
221
+    /* decide whether to malloc a new pointer or free/realloc an existing */
222
+    which = RANDOM_VALUE(4);
223
+    
224
+    /*
225
+     * < MIN_AVAIL means alloc as long as we have enough memory and
226
+     * there are free slots we do an allocation, else we free
227
+     */
228
+    if (free_c == max_pointers
229
+	|| (free_c > 0 && which < 3 && max >= MIN_AVAIL)) {
230
+      
231
+      while (1) {
232
+	amount = RANDOM_VALUE(max / 2);
233
+	if (amount > 0) {
234
+	  break;
235
+	}
236
+      }
237
+      which = RANDOM_VALUE(9);
238
+      pnt_p = NULL;
239
+      
240
+      switch (which) {
241
+	
242
+      case 0: case 1: case 2:
243
+	pnt_p = free_p;
244
+	if (use_malloc_b) {
245
+	  pnt_p->pi_pnt = malloc(amount);
246
+	}
247
+	else {
248
+	  pnt_p->pi_pnt = mpool_alloc(pool, amount, &ret);
249
+	}
250
+	
251
+	if (verbose_b) {
252
+	  (void)printf("%d: malloc %ld (max %ld) into slot %d.  got %#lx\n",
253
+		       iter_c + 1, amount, max, pnt_p - pointer_grid,
254
+		       (long)pnt_p->pi_pnt);
255
+	}
256
+	
257
+	if (pnt_p->pi_pnt == NULL) {
258
+	  (void)printf("malloc of %ld failed: %s\n",
259
+		       amount,
260
+		       (use_malloc_b ? strerror(errno) : mpool_strerror(ret)));
261
+	}
262
+	pnt_p->pi_size = amount;
263
+	break;
264
+	
265
+      case 3: case 4: case 5:
266
+	pnt_p = free_p;
267
+	if (use_malloc_b) {
268
+	  pnt_p->pi_pnt = calloc(amount, sizeof(char));
269
+	}
270
+	else {
271
+	  pnt_p->pi_pnt = mpool_calloc(pool, amount, sizeof(char), &ret);
272
+	}
273
+	
274
+	if (verbose_b) {
275
+	  (void)printf("%d: calloc %ld (max %ld) into slot %d.  got %#lx\n",
276
+		       iter_c + 1, amount, max, pnt_p - pointer_grid,
277
+		       (long)pnt_p->pi_pnt);
278
+	}
279
+	
280
+	/* test the returned block to make sure that is has been cleared */
281
+	if (pnt_p->pi_pnt == NULL) {
282
+	  (void)printf("calloc of %ld failed: %s\n",
283
+		       amount,
284
+		       (use_malloc_b ? strerror(errno) : mpool_strerror(ret)));
285
+	}
286
+	else {
287
+	  for (chunk_p = pnt_p->pi_pnt;
288
+	       chunk_p < (char *)pnt_p->pi_pnt + amount;
289
+	       chunk_p++) {
290
+	    if (*chunk_p != '\0') {
291
+	      (void)printf("calloc of %ld not zeroed on iteration #%d\n",
292
+			   amount, iter_c + 1);
293
+	      break;
294
+	    }
295
+	  }
296
+	  pnt_p->pi_size = amount;
297
+	}
298
+	break;
299
+
300
+      case 6: case 7: case 8:
301
+	if (free_c == max_pointers) {
302
+	  continue;
303
+	}
304
+	
305
+	which = RANDOM_VALUE(max_pointers - free_c);
306
+	for (pnt_p = used_p; which > 0; which--) {
307
+	  pnt_p = pnt_p->pi_next;
308
+	}
309
+	
310
+	if (use_malloc_b) {
311
+	  new_pnt = realloc(pnt_p->pi_pnt, amount);
312
+	}
313
+	else {
314
+	  new_pnt = mpool_resize(pool, pnt_p->pi_pnt, amount,
315
+				 &ret);
316
+	}
317
+	
318
+	if (verbose_b) {
319
+	  (void)printf("%d: resize %#lx from %ld to %ld (max %ld) slot %d. "
320
+		       "got %#lx\n",
321
+		       iter_c + 1, (long)pnt_p->pi_pnt, pnt_p->pi_size, amount,
322
+		       max, pnt_p - pointer_grid, (long)new_pnt);
323
+	}
324
+	
325
+	if (new_pnt == NULL) {
326
+	  (void)printf("resize of %#lx old size %ld new size %ld failed: %s\n",
327
+		       (long)pnt_p->pi_pnt, pnt_p->pi_size, amount,
328
+		       (use_malloc_b ? strerror(errno) : mpool_strerror(ret)));
329
+	  pnt_p->pi_pnt = NULL;
330
+	  pnt_p->pi_size = 0;
331
+	}
332
+	else {
333
+	  /* we effectively freed the old memory */
334
+	  max += pnt_p->pi_size;
335
+	  pnt_p->pi_pnt = new_pnt;
336
+	  pnt_p->pi_size = amount;
337
+	}
338
+	break;
339
+	
340
+      default:
341
+	break;
342
+      }
343
+      
344
+      if (pnt_p != NULL && pnt_p->pi_pnt != NULL) {
345
+	if (pnt_p == free_p) {
346
+	  free_p = pnt_p->pi_next;
347
+	  pnt_p->pi_next = used_p;
348
+	  used_p = pnt_p;
349
+	  free_c--;
350
+	}
351
+	
352
+	max -= amount;
353
+	iter_c++;
354
+      }
355
+      continue;
356
+    }
357
+    
358
+    /*
359
+     * choose a rand slot to free and make sure it is not a free-slot
360
+     */
361
+    which = RANDOM_VALUE(max_pointers - free_c);
362
+    /* find pnt in the used list */
363
+    last_p = NULL;
364
+    for (pnt_p = used_p, last_p = NULL;
365
+	 pnt_p != NULL && which > 0;
366
+	 last_p = pnt_p, pnt_p = pnt_p->pi_next, which--) {
367
+    }
368
+    if (pnt_p == NULL) {
369
+      /* huh? error here */
370
+      abort();
371
+    }
372
+    if (last_p == NULL) {
373
+      used_p = pnt_p->pi_next;
374
+    }
375
+    else {
376
+      last_p->pi_next = pnt_p->pi_next;
377
+    }
378
+    
379
+    if (use_malloc_b) {
380
+      free(pnt_p->pi_pnt);
381
+    }
382
+    else {
383
+      ret = mpool_free(pool, pnt_p->pi_pnt);
384
+      if (ret != MPOOL_ERROR_NONE) {
385
+	(void)printf("free error on pointer '%#lx' of size %ld: %s\n",
386
+		     (long)pnt_p->pi_pnt, pnt_p->pi_size,
387
+		     mpool_strerror(ret));
388
+      }
389
+    }
390
+    
391
+    if (verbose_b) {
392
+      (void)printf("%d: free'd %ld bytes from slot %d (%#lx)\n",
393
+		   iter_c + 1, pnt_p->pi_size, pnt_p - pointer_grid,
394
+		   (long)pnt_p->pi_pnt);
395
+    }
396
+    
397
+    pnt_p->pi_pnt = NULL;
398
+    pnt_p->pi_next = free_p;
399
+    free_p = pnt_p;
400
+    free_c++;
401
+    
402
+    max += pnt_p->pi_size;
403
+    iter_c++;
404
+  }
405
+  
406
+  /* free used pointers */
407
+  for (pnt_p = pointer_grid; pnt_p < pointer_grid + max_pointers; pnt_p++) {
408
+    if (pnt_p->pi_pnt != NULL) {
409
+      if (use_malloc_b) {
410
+	free(pnt_p->pi_pnt);
411
+      }
412
+      else {
413
+	ret = mpool_free(pool, pnt_p->pi_pnt);
414
+	if (ret != MPOOL_ERROR_NONE) {
415
+	  (void)printf("free error on pointer '%#lx' of size %ld: %s\n",
416
+		       (long)pnt_p->pi_pnt, pnt_p->pi_size,
417
+		       mpool_strerror(ret));
418
+	}
419
+      }
420
+    }
421
+  }
422
+  
423
+  if (use_malloc_b) {
424
+    free(pointer_grid);
425
+  }
426
+  else {
427
+    ret = mpool_free(pool, pointer_grid);
428
+    if (ret != MPOOL_ERROR_NONE) {
429
+      (void)printf("free error on grid pointer: %s\n", mpool_strerror(ret));
430
+    }
431
+  }
432
+}
433
+
434
+/*
435
+ * static void do_interactive
436
+ *
437
+ * DESCRIPTION:
438
+ *
439
+ * Run the interactive section of the program.
440
+ *
441
+ * RETURNS:
442
+ *
443
+ * None.
444
+ *
445
+ * ARGUMENTS:
446
+ *
447
+ * pool <-> Out memory pool.
448
+ */
449
+static	void	do_interactive(mpool_t *pool)
450
+{
451
+  int		len, ret;
452
+  char		line[128], *line_p;
453
+  void		*pnt, *new_pnt;
454
+  
455
+  (void)printf("Mpool test program.  Type 'help' for assistance.\n");
456
+  
457
+  for (;;) {
458
+    (void)printf("> ");
459
+    if (fgets(line, sizeof(line), stdin) == NULL) {
460
+      break;
461
+    }
462
+    line_p = strchr(line, '\n');
463
+    if (line_p != NULL) {
464
+      *line_p = '\0';
465
+    }
466
+    
467
+    len = strlen(line);
468
+    if (len == 0) {
469
+      continue;
470
+    }
471
+    
472
+    if (strncmp(line, "?", len) == 0
473
+	|| strncmp(line, "help", len) == 0) {
474
+      (void)printf("\thelp      - print this message\n\n");
475
+      
476
+      (void)printf("\tmalloc    - allocate memory\n");
477
+      (void)printf("\tcalloc    - allocate/clear memory\n");
478
+      (void)printf("\tresize    - resize memory\n");
479
+      (void)printf("\tfree      - deallocate memory\n\n");
480
+      
481
+      (void)printf("\tclear     - clear the pool\n");
482
+      (void)printf("\toverwrite - overwrite some memory to test errors\n");
483
+      (void)printf("\trandom    - randomly execute a number of [de] allocs\n");
484
+      
485
+      (void)printf("\tquit      - quit this test program\n");
486
+      continue;
487
+    }
488
+    
489
+    if (strncmp(line, "quit", len) == 0) {
490
+      break;
491
+    }
492
+    
493
+    if (strncmp(line, "malloc", len) == 0) {
494
+      int	size;
495
+      
496
+      (void)printf("How much to malloc: ");
497
+      if (fgets(line, sizeof(line), stdin) == NULL) {
498
+	break;
499
+      }
500
+      size = atoi(line);
501
+      pnt = mpool_alloc(pool, size, &ret);
502
+      if (pnt == NULL) {
503
+	(void)printf("malloc(%d) failed: %s\n", size, mpool_strerror(ret));
504
+      }
505
+      else {
506
+	(void)printf("malloc(%d) returned '%#lx'\n", size, (long)pnt);
507
+      }
508
+      continue;
509
+    }
510
+    
511
+    if (strncmp(line, "calloc", len) == 0) {
512
+      int	size;
513
+      
514
+      (void)printf("How much to calloc: ");
515
+      if (fgets(line, sizeof(line), stdin) == NULL) {
516
+	break;
517
+      }
518
+      size = atoi(line);
519
+      pnt = mpool_calloc(pool, size, sizeof(char), &ret);
520
+      if (pnt == NULL) {
521
+	(void)printf("calloc(%d) failed: %s\n", size, mpool_strerror(ret));
522
+      }
523
+      else {
524
+	(void)printf("calloc(%d) returned '%#lx'\n", size, (long)pnt);
525
+      }
526
+      continue;
527
+    }
528
+    
529
+    if (strncmp(line, "resize", len) == 0) {
530
+      int	size, old_size;
531
+      
532
+      pnt = get_address();
533
+      
534
+      (void)printf("Old size of allocation: ");
535
+      if (fgets(line, sizeof(line), stdin) == NULL) {
536
+	break;
537
+      }
538
+      old_size = atoi(line);
539
+      (void)printf("New size of allocation: ");
540
+      if (fgets(line, sizeof(line), stdin) == NULL) {
541
+	break;
542
+      }
543
+      size = atoi(line);
544
+      
545
+      new_pnt = mpool_resize(pool, pnt, size, &ret);
546
+      if (new_pnt == NULL) {
547
+	(void)printf("resize(%#lx, %d) failed: %s\n",
548
+		     (long)pnt, size, mpool_strerror(ret));
549
+      }
550
+      else {
551
+	(void)printf("resize(%#lx, %d) returned '%#lx'\n",
552
+		     (long)pnt, size, (long)new_pnt);
553
+      }
554
+      continue;
555
+    }
556
+    
557
+    if (strncmp(line, "free", len) == 0) {
558
+      int	old_size;
559
+      
560
+      pnt = get_address();
561
+      
562
+      (void)printf("Old minimum size we are freeing: ");
563
+      if (fgets(line, sizeof(line), stdin) == NULL) {
564
+	break;
565
+      }
566
+      old_size = atoi(line);
567
+      ret = mpool_free(pool, pnt);
568
+      if (ret != MPOOL_ERROR_NONE) {
569
+	(void)fprintf(stderr, "free failed: %s\n", mpool_strerror(ret));
570
+      }
571
+      continue;
572
+    }
573
+    
574
+    if (strncmp(line, "clear", len) == 0) {
575
+      ret = mpool_clear(pool);
576
+      if (ret == MPOOL_ERROR_NONE) {
577
+	(void)fprintf(stderr, "clear succeeded\n");
578
+      }
579
+      else {
580
+	(void)fprintf(stderr, "clear failed: %s\n", mpool_strerror(ret));
581
+      }
582
+      continue;
583
+    }
584
+    
585
+    if (strncmp(line, "overwrite", len) == 0) {
586
+      char	*overwrite = "OVERWRITTEN";
587
+      
588
+      pnt = get_address();
589
+      memcpy((char *)pnt, overwrite, strlen(overwrite));
590
+      (void)printf("Done.\n");
591
+      continue;
592
+    }
593
+    
594
+    /* do random heap hits */
595
+    if (strncmp(line, "random", len) == 0) {
596
+      int	iter_n;
597
+      
598
+      (void)printf("How many iterations[%d]: ", default_iter_n);
599
+      if (fgets(line, sizeof(line), stdin) == NULL) {
600
+	break;
601
+      }
602
+      if (line[0] == '\0' || line[0] == '\n') {
603
+	iter_n = default_iter_n;
604
+      }
605
+      else {
606
+	iter_n = atoi(line);
607
+      }
608
+      
609
+      do_random(pool, iter_n);
610
+      continue;
611
+    }
612
+    
613
+    (void)printf("Unknown command '%s'.  Type 'help' for assistance.\n", line);
614
+  }
615
+}
616
+
617
+/*
618
+ * static void log_func
619
+ *
620
+ * DESCRIPTION:
621
+ *
622
+ * Mpool transaction log function.
623
+ *
624
+ * RETURNS:
625
+ *
626
+ * None.
627
+ *
628
+ * ARGUMENT:
629
+ *
630
+ * mp_p -> Associated mpool address.
631
+ *
632
+ * func_id -> Integer function ID which identifies which mpool
633
+ * function is being called.
634
+ *
635
+ * byte_size -> Optionally specified byte size.
636
+ *
637
+ * ele_n -> Optionally specified element number.  For mpool_calloc
638
+ * only.
639
+ *
640
+ * new_addr -> Optionally specified new address.  For mpool_alloc,
641
+ * mpool_calloc, and mpool_resize only.
642
+ *
643
+ * old_addr -> Optionally specified old address.  For mpool_resize and
644
+ * mpool_free only.
645
+ *
646
+ * old_byte_size -> Optionally specified old byte size.  For
647
+ * mpool_resize only.
648
+ */
649
+static	void	log_func(const void *mp_p, const int func_id,
650
+			 const unsigned long byte_size,
651
+			 const unsigned long ele_n,
652
+			 const void *new_addr, const void *old_addr,
653
+			 const unsigned long old_byte_size)
654
+{
655
+  (void)printf("mp %#lx ", (long)mp_p);
656
+  
657
+  switch (func_id) {
658
+    
659
+  case MPOOL_FUNC_CLOSE:
660
+    (void)printf("close\n");
661
+    break;
662
+    
663
+  case MPOOL_FUNC_CLEAR:
664
+    (void)printf("clear\n");
665
+    break;
666
+    
667
+  case MPOOL_FUNC_ALLOC:
668
+    (void)printf("alloc %lu bytes got %#lx\n",
669
+		 byte_size, (long)new_addr);
670
+    break;
671
+    
672
+  case MPOOL_FUNC_CALLOC:
673
+    (void)printf("calloc %lu ele size, %lu ele number, got %#lx\n",
674
+		 byte_size, ele_n, (long)new_addr);
675
+    break;
676
+    
677
+  case MPOOL_FUNC_FREE:
678
+    (void)printf("free %#lx of %lu bytes\n", (long)old_addr, byte_size);
679
+    break;
680
+    
681
+  case MPOOL_FUNC_RESIZE:
682
+    (void)printf("resize %#lx of %lu bytes to %lu bytes, got %#lx\n",
683
+		 (long)old_addr, old_byte_size, byte_size,
684
+		 (long)new_addr);
685
+    break;
686
+    
687
+  default:
688
+    (void)printf("unknown function %d, %lu bytes\n", func_id, byte_size);
689
+    break;
690
+  }
691
+}
692
+
693
+/*
694
+ * static void usage
695
+ *
696
+ * DESCRIPTION:
697
+ *
698
+ * Print a usage message.
699
+ *
700
+ * RETURNS:
701
+ *
702
+ * None.
703
+ *
704
+ * ARGUMENTS:
705
+ *
706
+ * None.
707
+ */
708
+static	void	usage(void)
709
+{
710
+  (void)fprintf(stderr,
711
+		"Usage: mpool_t [-bhHilMnsv] [-m size] [-p number] "
712
+		"[-P size] [-S seed] [-t times]\n");
713
+  (void)fprintf(stderr,
714
+		"  -b              set MPOOL_FLAG_BEST_FIT\n"
715
+		"  -h              set MPOOL_FLAG_NO_FREE\n"
716
+		"  -H              use system heap not mpool\n"
717
+		"  -i              turn on interactive mode\n"
718
+		"  -l              log memory transactions\n"
719
+		"  -M              max number pages in mpool\n"
720
+		"  -n              set MPOOL_FLAG_NO_FREE\n"
721
+		"  -s              use sbrk instead of mmap\n"
722
+		"  -v              enable verbose messages\n"
723
+		"  -m size         maximum allocation to test\n"
724
+		"  -p max-pnts     number of pointers to test\n"
725
+		"  -S seed-rand    seed for random function\n"
726
+		"  -t interations  number of iterations to run\n");
727
+  exit(1);      
728
+}
729
+
730
+/*
731
+ * static void process_args
732
+ *
733
+ * DESCRIPTION:
734
+ *
735
+ * Process our arguments.
736
+ *
737
+ * RETURNS:
738
+ *
739
+ * None.
740
+ *
741
+ * ARGUMENTS:
742
+ *
743
+ * None.
744
+ */
745
+static	void	process_args(int argc, char ** argv)
746
+{
747
+  argc--, argv++;
748
+  
749
+  /* process the args */
750
+  for (; *argv != NULL; argv++, argc--) {
751
+    if (**argv != '-') {
752
+      continue;
753
+    }
754
+    
755
+    switch (*(*argv + 1)) {
756
+      
757
+    case 'b':
758
+      best_fit_b = 1;
759
+      break;
760
+    case 'h':
761
+      heavy_pack_b = 1;
762
+      break;
763
+    case 'H':
764
+      use_malloc_b = 1;
765
+      break;
766
+    case 'i':
767
+      interactive_b = 1;
768
+      break;
769
+    case 'l':
770
+      log_trxn_b = 1;
771
+      break;
772
+    case 'm':
773
+      argv++, argc--;
774
+      if (argc <= 0) {
775
+	usage();
776
+      }
777
+      max_alloc = atoi(*argv);
778
+      break;
779
+    case 'M':
780
+      max_pages_n = 1;
781
+      break;
782
+    case 'n':
783
+      no_free_b = 1;
784
+      break;
785
+    case 'p':
786
+      argv++, argc--;
787
+      if (argc <= 0) {
788
+	usage();
789
+      }
790
+      max_pointers = atoi(*argv);
791
+      break;
792
+    case 'P':
793
+      argv++, argc--;
794
+      if (argc <= 0) {
795
+	usage();
796
+      }
797
+      page_size = atoi(*argv);
798
+      break;
799
+    case 'S':
800
+      argv++, argc--;
801
+      if (argc <= 0) {
802
+	usage();
803
+      }
804
+      seed_random = atoi(*argv);
805
+      break;
806
+    case 't':
807
+      argv++, argc--;
808
+      if (argc <= 0) {
809
+	usage();
810
+      }
811
+      default_iter_n = atoi(*argv);
812
+      break;
813
+    case 'v':
814
+      verbose_b = 1;
815
+      break;
816
+    default:
817
+      usage();
818
+      break;
819
+    }
820
+  }
821
+}
822
+
823
+/*
824
+ * Main routine
825
+ */
826
+int	main(int argc, char **argv)
827
+{
828
+  int		ret;
829
+  unsigned int	flags = 0, pool_page_size;
830
+  unsigned long	num_alloced, user_alloced, max_alloced, tot_alloced;
831
+  mpool_t	*pool;
832
+  
833
+  process_args(argc, argv);
834
+  
835
+  /* repeat until we get a non 0 seed */
836
+  while (seed_random == 0) {
837
+    seed_random = time(0) ^ getpid();
838
+  }
839
+  (void)srandom(seed_random);
840
+  
841
+  (void)printf("Random seed is %u\n", seed_random);
842
+  
843
+  if (best_fit_b) {
844
+    flags |= MPOOL_FLAG_BEST_FIT;
845
+  }
846
+  if (heavy_pack_b) {
847
+    flags |= MPOOL_FLAG_HEAVY_PACKING;
848
+  }
849
+  if (no_free_b) {
850
+    flags |= MPOOL_FLAG_NO_FREE;
851
+  }
852
+  if (use_sbrk_b) {
853
+    flags |= MPOOL_FLAG_USE_SBRK;
854
+  }
855
+  
856
+  /* open our memory pool */
857
+  pool = mpool_open(flags, page_size, NULL, &ret);
858
+  if (pool == NULL) {
859
+    (void)fprintf(stderr, "Error in mpool_open: %s\n", mpool_strerror(ret));
860
+    exit(1);
861
+  }
862
+  
863
+  /* are we logging transactions */
864
+  if (log_trxn_b) {
865
+    ret = mpool_set_log_func(pool, log_func);
866
+    if (ret != MPOOL_ERROR_NONE) {
867
+      (void)fprintf(stderr, "Error in mpool_set_log_func: %s\n",
868
+		    mpool_strerror(ret));
869
+    }
870
+  }
871
+  
872
+  if (max_pages_n > 0) {
873
+    ret = mpool_set_max_pages(pool, max_pages_n);
874
+    if (ret != MPOOL_ERROR_NONE) {
875
+      (void)fprintf(stderr, "Error in mpool_set_max_pages: %s\n",
876
+		    mpool_strerror(ret));
877
+    }
878
+  }
879
+  
880
+  if (interactive_b) {
881
+    do_interactive(pool);
882
+  }
883
+  else {
884
+    (void)printf("Running %d tests (use -i for interactive)...\n",
885
+		 default_iter_n);
886
+    (void)fflush(stdout);
887
+    
888
+    do_random(pool, default_iter_n);
889
+  }
890
+  
891
+  /* get stats from the pool */
892
+  ret = mpool_stats(pool, &pool_page_size, &num_alloced, &user_alloced,
893
+		    &max_alloced, &tot_alloced);
894
+  if (ret == MPOOL_ERROR_NONE) {
895
+    (void)printf("Pool page size = %d.  Number active allocated = %lu\n",
896
+		 pool_page_size, num_alloced);
897
+    (void)printf("User bytes allocated = %lu.  Max space allocated = %lu\n",
898
+		 user_alloced, max_alloced);
899
+    (void)printf("Total space allocated = %lu\n", tot_alloced);
900
+  }
901
+  else {
902
+    (void)fprintf(stderr, "Error in mpool_stats: %s\n", mpool_strerror(ret));
903
+  }
904
+  
905
+  /* close the pool */
906
+  ret = mpool_close(pool);
907
+  if (ret != MPOOL_ERROR_NONE) {
908
+    (void)fprintf(stderr, "Error in mpool_close: %s\n", mpool_strerror(ret));
909
+    exit(1);
910
+  }
911
+  
912
+  exit(0);
913
+}
... ...
@@ -52,6 +52,10 @@
52 52
 #include "md5.h"
53 53
 #include <assert.h>
54 54
 
55
+#ifdef USE_MPOOL
56
+#include "mpool.h"
57
+#endif
58
+
55 59
 #define DOMAIN_REAL 1
56 60
 #define DOMAIN_DISPLAY 0
57 61
 
... ...
@@ -857,7 +861,11 @@ int phishing_init(struct cl_engine* engine)
857 857
 {
858 858
 	struct phishcheck* pchk;
859 859
 	if(!engine->phishcheck) {
860
+#ifdef USE_MPOOL
861
+		pchk = engine->phishcheck = mpool_alloc(engine->mempool, sizeof(struct phishcheck), NULL);
862
+#else
860 863
 		pchk = engine->phishcheck = cli_malloc(sizeof(struct phishcheck));
864
+#endif
861 865
 		if(!pchk)
862 866
 			return CL_EMEM;
863 867
 		pchk->is_disabled=1;
... ...
@@ -875,7 +883,11 @@ int phishing_init(struct cl_engine* engine)
875 875
 	cli_dbgmsg("Initializing phishcheck module\n");
876 876
 
877 877
 	if(build_regex(&pchk->preg_numeric,numeric_url_regex,1)) {
878
+#ifdef USE_MPOOL
879
+		mpool_free(engine->mempool, pchk);
880
+#else
878 881
 		free(pchk);
882
+#endif
879 883
 		engine->phishcheck = NULL;
880 884
 		return CL_EFORMAT;
881 885
 	}
... ...
@@ -67,6 +67,10 @@
67 67
 #include <stddef.h>
68 68
 #endif
69 69
 
70
+#ifdef USE_MPOOL
71
+#include "mpool.h"
72
+#endif
73
+
70 74
 #ifdef CL_THREAD_SAFE
71 75
 #  include <pthread.h>
72 76
 static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
... ...
@@ -339,14 +343,27 @@ int cli_initengine(struct cl_engine **engine, unsigned int options)
339 339
 
340 340
 	(*engine)->refcount = 1;
341 341
 
342
+#ifdef USE_MPOOL
343
+	if(!((*engine)->mempool = mpool_open(MPOOL_FLAG_BEST_FIT, 0, NULL, NULL))) {
344
+	    cli_errmsg("Can't allocate memory for memory pool!\n");
345
+	    return CL_EMEM;
346
+	}
347
+
348
+	(*engine)->root = mpool_calloc((*engine)->mempool, CLI_MTARGETS, sizeof(struct cli_matcher *), NULL);
349
+#else
342 350
 	(*engine)->root = cli_calloc(CLI_MTARGETS, sizeof(struct cli_matcher *));
351
+#endif
343 352
 	if(!(*engine)->root) {
344 353
 	    /* no need to free previously allocated memory here */
345 354
 	    cli_errmsg("Can't allocate memory for roots!\n");
346 355
 	    return CL_EMEM;
347 356
 	}
348 357
 
358
+#ifdef USE_MPOOL
359
+	(*engine)->dconf = cli_dconf_init((*engine)->mempool);
360
+#else
349 361
 	(*engine)->dconf = cli_dconf_init();
362
+#endif
350 363
 	if(!(*engine)->dconf) {
351 364
 	    cli_errmsg("Can't initialize dynamic configuration\n");
352 365
 	    return CL_EMEM;
... ...
@@ -369,7 +386,12 @@ static int cli_initroots(struct cl_engine *engine, unsigned int options)
369 369
     for(i = 0; i < CLI_MTARGETS; i++) {
370 370
 	if(!engine->root[i]) {
371 371
 	    cli_dbgmsg("Initializing engine->root[%d]\n", i);
372
+#ifdef USE_MPOOL
373
+	    root = engine->root[i] = (struct cli_matcher *) cli_calloc(engine->mempool, 1, sizeof(struct cli_matcher), NULL);
374
+	    root->mempool = engine->mempool;
375
+#else
372 376
 	    root = engine->root[i] = (struct cli_matcher *) cli_calloc(1, sizeof(struct cli_matcher));
377
+#endif
373 378
 	    if(!root) {
374 379
 		cli_errmsg("cli_initroots: Can't allocate memory for cli_matcher\n");
375 380
 		return CL_EMEM;