0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <ndrx_config.h>
0037 #include <string.h>
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <pthread.h>
0041 #include <sys_primitives.h> /**< spin locks for MacOS */
0042 #include <ndrstandard.h>
0043 #include <fpalloc.h>
0044 #include <thlock.h>
0045 #include <errno.h>
0046 #include <nstdutil.h>
0047 #include <userlog.h>
0048 #include <nstd_int.h>
0049
0050 #include "ndebug.h"
0051
0052
0053
0054
0055 #define NDRX_FP_GETSIZE 1
0056 #define NDRX_FP_GETMODE 2
0057 #define NDRX_FP_USEMALLOC 3
0058 #define NDRX_FP_USENUMBL 4
0059
0060
0061
0062 #define NDRX_FPDEBUG(fmt, ...)
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 exprivate ndrx_fpapool_t M_fpa_pools[NDRX_FPA_MAX] =
0074 {
0075
0076 {NDRX_FPA_0_SIZE, NDRX_FPNOFLAG, NDRX_FPA_0_DNUM}
0077 ,{NDRX_FPA_1_SIZE, NDRX_FPNOFLAG, NDRX_FPA_1_DNUM}
0078 ,{NDRX_FPA_2_SIZE, NDRX_FPNOFLAG, NDRX_FPA_2_DNUM}
0079 ,{NDRX_FPA_3_SIZE, NDRX_FPNOFLAG, NDRX_FPA_3_DNUM}
0080 ,{NDRX_FPA_4_SIZE, NDRX_FPNOFLAG, NDRX_FPA_4_DNUM}
0081 ,{NDRX_FPA_5_SIZE, NDRX_FPNOFLAG, NDRX_FPA_5_DNUM}
0082 ,{NDRX_FPA_SIZE_SYSBUF, NDRX_FPSYSBUF, NDRX_FPA_SYSBUF_DNUM}
0083 };
0084
0085
0086 exprivate MUTEX_LOCKDECL(M_initlock);
0087 exprivate volatile int M_init_first = EXTRUE;
0088 exprivate int M_malloc_all = EXFALSE;
0089 exprivate char *M_opts = NULL;
0090
0091
0092
0093
0094
0095
0096
0097
0098 expublic void ndrx_fpstats(int poolno, ndrx_fpapool_t *p_stats)
0099 {
0100
0101 NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0102 memcpy((char *)p_stats, (char *)&M_fpa_pools[poolno], sizeof(ndrx_fpapool_t));
0103 NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0104 }
0105
0106
0107
0108
0109 expublic void ndrx_fpuninit(void)
0110 {
0111 int i;
0112 volatile ndrx_fpablock_t *freebl;
0113
0114
0115 if (M_init_first)
0116 {
0117
0118 return;
0119 }
0120
0121
0122 for (i=0; i<N_DIM(M_fpa_pools); i++)
0123 {
0124 do
0125 {
0126 freebl = NULL;
0127
0128 NDRX_SPIN_LOCK_V(M_fpa_pools[i].spinlock);
0129
0130 freebl = M_fpa_pools[i].stack;
0131
0132 if (NULL!=freebl)
0133 {
0134 M_fpa_pools[i].stack = freebl->next;
0135 }
0136
0137 NDRX_SPIN_UNLOCK_V(M_fpa_pools[i].spinlock);
0138
0139 if (NULL!=freebl)
0140 {
0141 NDRX_FREE((void *)freebl);
0142 }
0143
0144 }
0145 while (NULL!=freebl);
0146 }
0147
0148 M_init_first=EXTRUE;
0149 }
0150
0151
0152
0153
0154
0155
0156 exprivate int ndrx_fpinit(void)
0157 {
0158 int ret = EXSUCCEED;
0159 int i, state, blocksz, bnum, found, len, multiplier;
0160 char settings[1024];
0161 char *bconf, *bopt, *saveptr1, *saveptr2;
0162
0163 for (i=0; i<N_DIM(M_fpa_pools); i++)
0164 {
0165 M_fpa_pools[i].cur_blocks = 0;
0166 M_fpa_pools[i].stack = NULL;
0167 M_fpa_pools[i].allocs = 0;
0168 NDRX_SPIN_INIT_V(M_fpa_pools[i].spinlock);
0169 }
0170
0171
0172 M_opts=getenv(CONF_NDRX_FPAOPTS);
0173
0174 if (NULL!=M_opts)
0175 {
0176 NDRX_FPDEBUG("Loading config: [%s]", M_opts);
0177
0178 NDRX_STRCPY_SAFE(settings, M_opts);
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 for (bconf=strtok_r(settings, ",", &saveptr1); NULL!=bconf; bconf=strtok_r(NULL, ",", &saveptr1))
0195 {
0196
0197
0198 NDRX_FPDEBUG("Parsing block: [%s]", bconf);
0199
0200 state = NDRX_FP_GETSIZE;
0201 bnum=EXFAIL;
0202 for (bopt=strtok_r(bconf, ":", &saveptr2); NULL!=bopt; bopt=strtok_r(NULL, ":", &saveptr2))
0203 {
0204 NDRX_FPDEBUG("Parsing option: [%s]", bopt);
0205
0206 switch (state)
0207 {
0208 case NDRX_FP_GETSIZE:
0209
0210 if (0==strcmp(bopt, "D"))
0211 {
0212 blocksz = NDRX_FPA_SIZE_DEFAULT;
0213 }
0214 else if (0==strcmp(bopt, "S"))
0215 {
0216 blocksz = NDRX_FPA_SIZE_SYSBUF;
0217 }
0218 else
0219 {
0220 len = strlen(bopt);
0221 multiplier=1;
0222
0223 if (len > 0)
0224 {
0225 if (bopt[len-1]=='K')
0226 {
0227 multiplier=1024;
0228 bopt[len-1]=EXEOS;
0229 }
0230 else if (bopt[len-1]<'0' || bopt[len-1]>'9')
0231 {
0232 userlog("%s: Invalid 'size' size multiplier "
0233 "[%c] for token [%s] in [%s] ",
0234 CONF_NDRX_FPAOPTS, bopt[len-1], bopt, M_opts);
0235 EXFAIL_OUT(ret);
0236 }
0237 }
0238
0239 if (!ndrx_is_numberic(bopt))
0240 {
0241 userlog("%s: Invalid 'size' token [%s] in [%s]",
0242 CONF_NDRX_FPAOPTS, bopt, M_opts);
0243 EXFAIL_OUT(ret);
0244 }
0245
0246 blocksz = atoi(bopt)*multiplier;
0247 }
0248
0249 state = NDRX_FP_GETMODE;
0250 break;
0251 case NDRX_FP_GETMODE:
0252
0253 if (0==strcmp(bopt, "M"))
0254 {
0255 NDRX_FPDEBUG("Use Malloc for size %d", blocksz);
0256
0257 state = NDRX_FP_USEMALLOC;
0258 }
0259 else
0260 {
0261 if (!ndrx_is_numberic(bopt))
0262 {
0263 userlog("%s: Invalid 'bnum' token [%s] in [%s]",
0264 CONF_NDRX_FPAOPTS, bopt, M_opts);
0265 EXFAIL_OUT(ret);
0266 }
0267
0268 bnum = atoi(bopt);
0269
0270 if (bnum < 1)
0271 {
0272 userlog("%s: Invalid 'bnum' token (<1) [%s] in [%s]",
0273 CONF_NDRX_FPAOPTS, bopt, M_opts);
0274 EXFAIL_OUT(ret);
0275 }
0276
0277 state=NDRX_FP_USENUMBL;
0278 NDRX_FPDEBUG("bnum=%d", bnum);
0279 }
0280 break;
0281 case NDRX_FP_USEMALLOC:
0282
0283 userlog("%s: Invalid argument for 'M' token [%s] in [%s]",
0284 CONF_NDRX_FPAOPTS, bopt, M_opts);
0285 EXFAIL_OUT(ret);
0286 break;
0287 case NDRX_FP_USENUMBL:
0288 userlog("%s: Token not expected [%s] in [%s]",
0289 CONF_NDRX_FPAOPTS, bopt, M_opts);
0290 EXFAIL_OUT(ret);
0291 break;
0292 }
0293 }
0294
0295 if (NDRX_FP_USEMALLOC > state)
0296 {
0297 userlog("%s: Missing mode/min for block size %d in [%s]",
0298 CONF_NDRX_FPAOPTS, (int)blocksz, M_opts);
0299 EXFAIL_OUT(ret);
0300 }
0301
0302
0303 found=EXFALSE;
0304 for (i=0; i<N_DIM(M_fpa_pools); i++)
0305 {
0306 if (NDRX_FPA_SIZE_DEFAULT==blocksz ||
0307 blocksz==M_fpa_pools[i].bsize)
0308 {
0309
0310 if (NDRX_FP_USEMALLOC==state)
0311 {
0312 M_fpa_pools[i].flags|=NDRX_FPNOPOOL;
0313 NDRX_FPDEBUG("Pool %d flags set to: [%d]",
0314 i, M_fpa_pools[i].flags);
0315 found=EXTRUE;
0316
0317 if (blocksz==M_fpa_pools[i].bsize)
0318 {
0319 break;
0320 }
0321 }
0322 else
0323 {
0324 if (EXFAIL!=bnum)
0325 {
0326 M_fpa_pools[i].num_blocks=bnum;
0327 }
0328
0329 found=EXTRUE;
0330
0331 if (blocksz==M_fpa_pools[i].bsize)
0332 {
0333 break;
0334 }
0335 }
0336 }
0337 }
0338
0339 if (!found)
0340 {
0341 userlog("%s: Block size %d not supported in [%s]",
0342 CONF_NDRX_FPAOPTS, blocksz, M_opts);
0343 }
0344 }
0345
0346
0347 M_malloc_all = EXTRUE;
0348 for (i=0; i<N_DIM(M_fpa_pools); i++)
0349 {
0350 if (!(M_fpa_pools[i].flags & NDRX_FPNOPOOL))
0351 {
0352 NDRX_FPDEBUG("Not malloc all due to [%d]", i);
0353 M_malloc_all = EXFALSE;
0354 break;
0355 }
0356 }
0357 }
0358
0359 M_init_first=EXFALSE;
0360
0361 out:
0362
0363 if (EXSUCCEED!=ret)
0364 {
0365 errno=EINVAL;
0366 }
0367
0368 return ret;
0369 }
0370
0371
0372
0373
0374 #define DO_BIN_SEARCH \
0375 do {\
0376 \
0377 int low=0, mid, high=NDRX_FPA_DYN_MAX-1;\
0378 \
0379 while(low <= high)\
0380 {\
0381 mid = (low + high) / 2;\
0382 \
0383 if (M_fpa_pools[mid].bsize > size)\
0384 {\
0385 high = mid - 1;\
0386 }\
0387 else if (M_fpa_pools[mid].bsize < size)\
0388 {\
0389 low = mid + 1;\
0390 }\
0391 else\
0392 {\
0393 poolno = mid;\
0394 break;\
0395 }\
0396 }\
0397 \
0398 if (EXFAIL==poolno && high < NDRX_FPA_DYN_MAX-2)\
0399 {\
0400 \
0401 poolno = high+1;\
0402 }\
0403 }\
0404 while (0)
0405
0406
0407
0408
0409
0410
0411
0412 expublic NDRX_API void *ndrx_fpmalloc(size_t size, int flags)
0413 {
0414 volatile ndrx_fpablock_t *addr = NULL;
0415 int poolno=EXFAIL;
0416
0417
0418 if (NDRX_UNLIKELY(M_init_first))
0419 {
0420 MUTEX_LOCK_V(M_initlock);
0421
0422 if (M_init_first)
0423 {
0424 if (EXSUCCEED!=ndrx_fpinit())
0425 {
0426 MUTEX_UNLOCK_V(M_initlock);
0427 return NULL;
0428 }
0429 }
0430 MUTEX_UNLOCK_V(M_initlock);
0431 }
0432
0433
0434 if (NDRX_UNLIKELY(M_malloc_all))
0435 {
0436 addr=malloc(size);
0437 NDRX_FPDEBUG("all malloc %p", addr);
0438 return (void *)addr;
0439 }
0440
0441
0442 if (flags & NDRX_FPSYSBUF)
0443 {
0444 poolno = NDRX_FPA_MAX-1;
0445 }
0446 else
0447 {
0448 DO_BIN_SEARCH;
0449 }
0450
0451 if (NDRX_UNLIKELY(EXFAIL==poolno))
0452 {
0453
0454 addr = (ndrx_fpablock_t *)NDRX_MALLOC(size+sizeof(ndrx_fpablock_t));
0455
0456 NDRX_FPDEBUG("Arb size alloc %p", addr);
0457
0458 if (NULL==addr)
0459 {
0460 goto out_err;
0461 }
0462 addr->flags=NDRX_FPABRSIZE;
0463 addr->magic = NDRX_FPA_MAGIC;
0464 addr->next = NULL;
0465 addr->poolno = EXFAIL;
0466 }
0467 else
0468 {
0469
0470 if (M_fpa_pools[poolno].flags & NDRX_FPNOPOOL)
0471 {
0472
0473 addr = (ndrx_fpablock_t *)NDRX_MALLOC(M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0474 NDRX_FPDEBUG("no-pool block for %d alloc %p", poolno, addr);
0475
0476 if (NULL==addr)
0477 {
0478 goto out_err;
0479 }
0480
0481 addr->poolno = poolno;
0482 addr->flags=NDRX_FPNOPOOL;
0483 addr->magic = NDRX_FPA_MAGIC;
0484 addr->next = NULL;
0485 }
0486
0487
0488 NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0489
0490 if (NULL!=M_fpa_pools[poolno].stack)
0491 {
0492 addr = M_fpa_pools[poolno].stack;
0493 M_fpa_pools[poolno].stack=M_fpa_pools[poolno].stack->next;
0494
0495 M_fpa_pools[poolno].cur_blocks--;
0496 }
0497 #ifdef NDRX_FPA_STATS
0498 else
0499 {
0500 M_fpa_pools[poolno].allocs++;
0501 }
0502 #endif
0503
0504 NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0505
0506 if (NULL==addr)
0507 {
0508
0509 if (NDRX_FPA_SIZE_SYSBUF==M_fpa_pools[poolno].bsize)
0510 {
0511
0512 addr = (ndrx_fpablock_t *)NDRX_MALLOC(size+sizeof(ndrx_fpablock_t));
0513 NDRX_FPDEBUG("Pool %d sysbuf alloc %p", poolno, addr);
0514 }
0515 else
0516 {
0517 addr = (ndrx_fpablock_t *)NDRX_MALLOC(M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0518 NDRX_FPDEBUG("Pool %d block alloc %p", poolno, addr);
0519 }
0520 if (NULL==addr)
0521 {
0522 goto out_err;
0523 }
0524 addr->flags=0;
0525 addr->magic = NDRX_FPA_MAGIC;
0526 addr->next = NULL;
0527 addr->poolno = poolno;
0528 }
0529 else
0530 {
0531 NDRX_FPDEBUG("Got from pool %d addr %p", poolno, addr);
0532 }
0533 }
0534
0535 out:
0536
0537 return (void *) (((char *)addr) + sizeof(ndrx_fpablock_t));
0538
0539 out_err:
0540 return NULL;
0541 }
0542
0543
0544
0545
0546
0547 expublic NDRX_API void ndrx_fpfree(void *ptr)
0548 {
0549 ndrx_fpablock_t *addr = (ndrx_fpablock_t *)(((char *)ptr)-sizeof(ndrx_fpablock_t));
0550 int poolno;
0551 int action_free = EXFALSE;
0552 #ifdef NDRX_FPA_STATS
0553 static int callnum=0;
0554 static MUTEX_LOCKDECL(callnum_lock);
0555 #endif
0556
0557 if (NDRX_UNLIKELY(M_malloc_all))
0558 {
0559
0560 NDRX_FPDEBUG("M_alloc_all free %p", ptr);
0561 NDRX_FREE(ptr);
0562 goto out;
0563 }
0564
0565 if (NDRX_UNLIKELY(addr->magic!=NDRX_FPA_MAGIC))
0566 {
0567 ssize_t wret;
0568
0569 #define ERR_MSG1 "***************************************************\n"
0570 #define ERR_MSG2 "* INVALID FPA FREE: Invalid magic *\n"
0571 #define ERR_MSG3 "***************************************************\n"
0572
0573 wret=write(STDERR_FILENO, ERR_MSG1, strlen(ERR_MSG1));
0574 wret=write(STDERR_FILENO, ERR_MSG2, strlen(ERR_MSG2));
0575 wret=write(STDERR_FILENO, ERR_MSG3, strlen(ERR_MSG3));
0576 abort();
0577 }
0578
0579
0580 if (NDRX_UNLIKELY(addr->flags & NDRX_FPABRSIZE))
0581 {
0582 NDRX_FPDEBUG("Arb/nopool free %p", addr);
0583 NDRX_FREE(addr);
0584 goto out;
0585 }
0586
0587
0588 poolno = addr->poolno;
0589
0590 if (M_fpa_pools[poolno].flags & NDRX_FPNOPOOL)
0591 {
0592 NDRX_FPDEBUG("fpnopool %d free %p", poolno, addr);
0593 NDRX_FREE(addr);
0594 goto out;
0595 }
0596
0597 NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0598
0599
0600
0601 if (M_fpa_pools[poolno].cur_blocks >= M_fpa_pools[poolno].num_blocks)
0602 {
0603 action_free = EXTRUE;
0604 NDRX_FPDEBUG("No space or hits in pool free up %p cur_hist=0", addr);
0605 }
0606 else
0607 {
0608
0609 addr->next = M_fpa_pools[poolno].stack;
0610 M_fpa_pools[poolno].stack = addr;
0611 M_fpa_pools[poolno].cur_blocks++;
0612 NDRX_FPDEBUG("Add to pool %d: %p", poolno, addr);
0613 }
0614
0615 NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0616
0617 #ifdef NDRX_FPA_STATS
0618 MUTEX_LOCK_V(callnum_lock);
0619 callnum++;
0620
0621 if ( callnum > 100)
0622 {
0623 int i;
0624 for (i=0; i<N_DIM(M_fpa_pools); i++)
0625 {
0626 userlog("bsize %d allocs: %d", M_fpa_pools[i].bsize, M_fpa_pools[i].allocs);
0627 }
0628 callnum=0;
0629 }
0630 MUTEX_UNLOCK_V(callnum_lock);
0631 #endif
0632
0633 if (action_free)
0634 {
0635 NDRX_FPDEBUG("Action free %p", addr);
0636 NDRX_FREE(addr);
0637 }
0638 out:
0639 return;
0640 }
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650 expublic void *ndrx_fprealloc(void *ptr, size_t size)
0651 {
0652 int poolno=EXFAIL;
0653 ndrx_fpablock_t *addr;
0654
0655 if (NULL==ptr)
0656 {
0657 addr=ndrx_fpmalloc(size, 0);
0658 NDRX_FPDEBUG("ndrx_fprealloc ret %p", ret);
0659 return addr;
0660 }
0661
0662 if (NDRX_UNLIKELY(M_malloc_all))
0663 {
0664
0665 NDRX_FPDEBUG("M_alloc_all realloc ptr=%p %size=zu", ptr, size);
0666 addr=(ndrx_fpablock_t *)NDRX_REALLOC(ptr, size);
0667 return (void *)addr;
0668 }
0669
0670 addr = (ndrx_fpablock_t *)(((char *)ptr)-sizeof(ndrx_fpablock_t));
0671
0672
0673
0674
0675
0676
0677
0678
0679 DO_BIN_SEARCH;
0680
0681
0682
0683 if (EXFAIL!=poolno)
0684 {
0685 if (addr->poolno==poolno)
0686 {
0687 NDRX_FPDEBUG("No pool changed %d", poolno);
0688 goto out;
0689 }
0690 else
0691 {
0692 NDRX_FPDEBUG("Change pool from %d to %d", addr->poolno, poolno);
0693
0694 addr=(ndrx_fpablock_t *)NDRX_REALLOC(addr, M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0695 if (NULL==addr)
0696 {
0697 goto out_err;
0698 }
0699 addr->poolno=poolno;
0700 addr->flags=0;
0701 }
0702 }
0703 else
0704 {
0705
0706 NDRX_FPDEBUG("Realloc to arb size (old pool: %d)", addr->poolno);
0707 addr=(ndrx_fpablock_t *)NDRX_REALLOC(addr, size+sizeof(ndrx_fpablock_t));
0708 if (NULL==addr)
0709 {
0710 goto out_err;
0711 }
0712
0713 addr->flags=NDRX_FPABRSIZE;
0714 addr->poolno=EXFAIL;
0715 goto out;
0716 }
0717
0718 out:
0719 return (void *) (((char *)addr) + sizeof(ndrx_fpablock_t));
0720
0721 out_err:
0722 return NULL;
0723
0724 }
0725
0726