EXPORT struct sttask * stpool_task_new(stpool_t *pool, const char *name, void (*run)(struct sttask *ptask), void (*err_handler)(struct sttask *ptask, long reasons), void *arg) { int e; ctask_t *ptask; /** * Does the pool support the Waitable tasks ? */ if (pool && !(eFUNC_F_TASK_EX & pool->efuncs)) { MSG_log(M_POOL, LOG_ERR, "Only ROUTINE tasks are supported by this pool(%s/%p) efuncs(%p).\n", pool->desc, pool, pool->efuncs); return NULL; } if (!(ptask = __stpool_cache_get(NULL))) return NULL; __stpool_task_INIT(ptask, name, run, err_handler, arg); if (pool && (e = __stpool_task_set_p(ptask, pool))) { MSG_log2(M_POOL, LOG_ERR, "__task_set_p: code(%d).", e); return NULL; } return TASK_CAST_UP(ptask); }
int objpool_ctor2(objpool_t *p, const char *name, size_t objlen, size_t nreserved, int nlimit_cache, OSPX_pthread_mutex_t *cache_lock) { /** * A block must can store at least 20 objects */ int n = 20, page_size = 4096, dummy = 50; if (objlen >= 256) { n = 8; page_size = 8096; } p->objlen = objlen; p->blocks = NULL; p->iblocks = p->ialloc = 0; p->block_size = (n + sizeof(obj_block_t) + dummy + page_size - 1) / page_size * page_size; p->block_nobjs = (p->block_size - sizeof(obj_block_t)) / objlen; p->ntotal = p->nput = 0; MSG_log(M_FOBJP, LOG_INFO, "Initializing fast objpool(\"%s\"/%p) ...\n", name, p); /** * Initialize the cache object */ if (smcache_init2(&p->smc, name, !nlimit_cache ? p->block_nobjs : nlimit_cache, cache_lock, CACHE_F_LOCK_CREATER, p, objpool_get, objpool_put, FUNC_ALWAYS_NEED_DESTROY)) { MSG_log2(M_FOBJP, LOG_ERR, "cache_init error"); return -1; } /** * Reserve some objects for the app if it has been * requested by user */ if (nreserved > 0) smcache_reserve(&p->smc, nreserved); return 0; }
static void * objpool_get(void *opaque) { size_t i = 0, n = 0, n_inc = 0; objpool_t *p = opaque; smlink_q_t *putq; void *m0 = NULL, *m1; /** * Scan the free queue of the blocks */ if (p->nput) { assert (p->ntotal >= p->nput); for (i=0; i<p->iblocks && p->nput && n_inc < 5; i++) { putq = &p->blocks[i].putq; /** * If there are free objects existing in the * blocks, we add some few of them into the * cache again */ if (!smlink_q_empty(putq)) { n = smlink_q_size(putq); p->nput -= n; assert (n < p->block_nobjs); if (!m0) { m0 = smlink_q_pop(putq); n -= 1; } if (n) { n_inc += n; smcache_add_ql(&p->smc, putq); INIT_SMLINK_Q(putq); } } } assert (m0); return m0; } /** * If we can not get any task objects from the * free queue, we try to create a new block to * get more task objects */ if (!(m0 = calloc(1, p->block_size))) { MSG_log2(M_FOBJP, LOG_ERR, "obj_create2: no memory."); return NULL; } /** * Allocate a memory to store the block */ if (p->ialloc == p->iblocks) { n_inc = 3; if (p->iblocks) m1 = realloc(p->blocks, sizeof(obj_block_t) *(p->iblocks + n_inc)); else m1 = malloc(sizeof(obj_block_t) * n_inc); if (!m1) { MSG_log2(M_FOBJP, LOG_ERR, "obj_create2: no memory."); free(m0); return NULL; } p->ialloc += n_inc; p->blocks = m1; } /** * Sort the block according to its objects address */ if (p->iblocks) { size_t l = 0, r = p->iblocks -1; for (;r>l;) { if ((char *)m0 < p->blocks[(l+r)/2].begin) r = (l+r)/2 - 1; else l = (l+r)/2 + 1; } /** * Be carefull: overflow */ assert (l >= 0 && (r < 0 || r <= (p->iblocks - 1))); if ((char *)m0 > p->blocks[l].begin) l += 1; if (l <= p->iblocks - 1) memmove(p->blocks + l + 1, p->blocks + l, (p->iblocks - l) * sizeof(obj_block_t)); i = l; } /** * Initialize the block */ { obj_block_t *ob = &p->blocks[i]; ob->begin = m0; ob->end = (char *)m0 + p->block_nobjs * p->objlen; putq = &ob->putq; INIT_SMLINK_Q(putq); assert (i==0 || p->blocks[i].begin >= p->blocks[i-1].begin); /** * Add the objects into the cache */ if (p->block_nobjs > 1) { for (i=1; i<p->block_nobjs; i++) smlink_q_push(putq, ob->begin + i * p->objlen ); smcache_add_ql(&p->smc, putq); INIT_SMLINK_Q(putq); } } assert (p->blocks[p->iblocks].begin != 0 && p->blocks[p->iblocks].end > p->blocks[p->iblocks].begin); ++ p->iblocks; p->ntotal += p->block_nobjs; return m0; }
EXPORT stpool_t * stpool_create(const char *desc, long eCAPs, int maxthreads, int minthreads, int suspend, int pri_q_num) { cpool_t *pool = NULL; long elibCAPs; int nfuncs; const char *fac_desc; const cpool_factory_t *fac; char eCAPs_buffer[400]; struct fac_candidate { const char *fac_desc; int nfuncs; long eCAPs; const cpool_factory_t *fac; } fac_sel[20]; int idx, sel_idx = 0; /** * It does not need to load the ospx library since * we do not call any APIs who must use the TLS datas. */ MSG_log(M_POOL, LOG_INFO, "Request creating a pool(\"%s\") efuncs(%s) ...\n", desc, __eCAPs_desc(eCAPs, eCAPs_buffer)); /** * Select the best templates to create the pool */ for (fac=first_factory(&fac_desc); fac; fac=next_factory(&fac_desc)) { elibCAPs = __enum_CAPs(fac, &nfuncs); if ((elibCAPs & eCAPs) == eCAPs) { MSG_log(M_POOL, LOG_DEBUG, "Find a Factory(\"%s\" scores(%d), nfuns(%d)): %s\n\n", fac_desc, fac->scores, nfuncs, __eCAPs_desc(elibCAPs, eCAPs_buffer)); /** * We skip it if the entry is full */ if (sel_idx == sizeof(fac_sel)/sizeof(*fac_sel)) continue; /** * Add the factory into our candidate entries */ for (idx=0; idx<sel_idx; idx++) { if (fac->scores > fac_sel[idx].fac->scores || (fac->scores == fac_sel[idx].fac->scores && nfuncs > fac_sel[idx].nfuncs)) { memmove(fac_sel + idx + 1, fac_sel + idx, (sel_idx - idx) * sizeof(struct fac_candidate)); break; } } fac_sel[idx].fac_desc = fac_desc; fac_sel[idx].nfuncs = nfuncs; fac_sel[idx].eCAPs = elibCAPs; fac_sel[idx].fac = fac; ++ sel_idx; } } if (!sel_idx) { MSG_log(M_POOL, LOG_ERR, "Can not find any pool template to satify user. eCAPs(%p) (%s)\n", eCAPs, stpool_version()); return NULL; } for (idx=0; idx<sel_idx; idx++) { MSG_log(M_POOL, LOG_INFO, "Factory(\"%s\" scores(%d) nfuns(%d)) try to service us. lib_eCAPs(%p) user_eCAPs(%p)\n", fac_sel[idx].fac_desc, fac_sel[idx].fac->scores, fac_sel[idx].nfuncs, fac_sel[idx].eCAPs, eCAPs); if ((pool = fac_sel[idx].fac->create(desc, maxthreads, minthreads, pri_q_num, suspend))) break; MSG_log2(M_POOL, LOG_ERR, "Failed to create the pool: Factory(\"%s\"/%p).", fac_sel[idx].fac_desc, fac_sel[idx].fac); } if (idx != sel_idx && ME_HAS(pool, atexit)) ME_CALL(pool, atexit)(pool->ins, __stpool_atexit, pool); return pool; }