xaset_t *xaset_union(pool *work_pool, xaset_t *set1, xaset_t *set2, size_t msize, XASET_MCOPY copyf) { xaset_t *newset; xasetmember_t *setp,*n; xaset_t *setv[3]; xaset_t **setcp; setv[0] = set1; setv[1] = set2; setv[2] = NULL; if (!set1 || !set2 || (!msize && !copyf)) { errno = EINVAL; return NULL; } work_pool = (work_pool ? work_pool : (set1->pool ? set1->pool : set2->pool)); if (!(newset = xaset_create(work_pool, set1->xas_compare))) return NULL; for (setcp = setv; *setcp; setcp++) for (setp = (*setcp)->xas_list; setp; setp=setp->next) { n = copyf ? copyf(setp) : (xasetmember_t*) palloc(work_pool, msize); if (!n) return NULL; /* Could cleanup here */ if (!copyf) memcpy(n, setp, msize); if (xaset_insert_sort(newset, n, 0) == -1) return NULL; } return newset; }
/* This function does the work of iterating through the list of registered * timers, checking to see if their callbacks should be invoked and whether * they should be removed from the registration list. Its return value is * the amount of time remaining on the first timer in the list. */ static int process_timers(int elapsed) { struct timer *t = NULL, *next = NULL; if (!recycled) recycled = xaset_create(timer_pool, NULL); if (!elapsed && !recycled->xas_list) { if (!timers) return 0; return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); } /* Critical code, no interruptions please */ if (_indispatch) return 0; pr_alarms_block(); _indispatch++; if (elapsed) { for (t = (struct timer *) timers->xas_list; t; t = next) { /* If this timer has already been handled, skip */ next = t->next; if (t->remove) { /* Move the timer onto the free_timers chain, for later reuse. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else if ((t->count -= elapsed) <= 0) { /* This timer's interval has elapsed, so trigger its callback. */ pr_trace_msg("timer", 4, "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking " "callback (%p)", t->interval, t->interval != 1 ? "seconds" : "second", t->timerno, t->desc ? t->desc : "<unknown>", t->mod ? t->mod->name : "<none>", t->callback); if (t->callback(t->interval, t->timerno, t->interval - t->count, t->mod) == 0) { /* A return value of zero means this timer is done, and can be * removed. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else { /* A non-zero return value from a timer callback signals that * the timer should be reused/restarted. */ pr_trace_msg("timer", 6, "restarting timer ID %d ('%s'), as per " "callback", t->timerno, t->desc ? t->desc : "<unknown>"); xaset_remove(timers, (xasetmember_t *) t); t->count = t->interval; xaset_insert(recycled, (xasetmember_t *) t); } } } } /* Put the recycled timers back into the main timer list. */ while ((t = (struct timer *) recycled->xas_list) != NULL) { xaset_remove(recycled, (xasetmember_t *) t); xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); } _indispatch--; pr_alarms_unblock(); /* If no active timers remain in the list, there is no reason to set the * SIGALRM handle. */ return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); }
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb, const char *desc) { struct timer *t = NULL; if (seconds <= 0 || cb == NULL || desc == NULL) { errno = EINVAL; return -1; } if (!timers) timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp); /* Check to see that, if specified, the timerno is not already in use. */ if (timerno >= 0) { for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno) { errno = EPERM; return -1; } } } if (!free_timers) free_timers = xaset_create(timer_pool, NULL); /* Try to use an old timer first */ pr_alarms_block(); t = (struct timer *) free_timers->xas_list; if (t != NULL) { xaset_remove(free_timers, (xasetmember_t *) t); } else { if (timer_pool == NULL) { timer_pool = make_sub_pool(permanent_pool); pr_pool_tag(timer_pool, "Timer Pool"); } /* Must allocate a new one */ t = palloc(timer_pool, sizeof(struct timer)); } if (timerno < 0) { /* Dynamic timer */ if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) { dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO; } timerno = dynamic_timerno++; } t->timerno = timerno; t->count = t->interval = seconds; t->callback = cb; t->mod = mod; t->remove = 0; t->desc = desc; /* If called while _indispatch, add to the recycled list to prevent * list corruption */ if (_indispatch) { if (!recycled) recycled = xaset_create(timer_pool, NULL); xaset_insert(recycled, (xasetmember_t *) t); } else { xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); nalarms++; set_sig_alarm(); /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is added. */ handle_alarm(); } pr_alarms_unblock(); pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), " "triggering in %ld %s", t->timerno, t->desc, t->mod ? t->mod->name : "[none]", t->interval, t->interval != 1 ? "seconds" : "second"); return timerno; }
int pr_stash_add_symbol(pr_stash_type_t sym_type, void *data) { struct stash *sym = NULL; unsigned int hash; int idx = 0; xaset_t **symbol_table; size_t sym_namelen = 0; if (data == NULL) { errno = EINVAL; return -1; } switch (sym_type) { case PR_SYM_CONF: sym = sym_alloc(); sym->sym_type = PR_SYM_CONF; sym->sym_name = ((conftable *) data)->directive; sym->sym_module = ((conftable *) data)->m; sym->ptr.sym_conf = data; symbol_table = conf_symbol_table; break; case PR_SYM_CMD: sym = sym_alloc(); sym->sym_type = PR_SYM_CMD; sym->sym_name = ((cmdtable *) data)->command; sym->sym_module = ((cmdtable *) data)->m; sym->ptr.sym_cmd = data; symbol_table = cmd_symbol_table; break; case PR_SYM_AUTH: sym = sym_alloc(); sym->sym_type = PR_SYM_AUTH; sym->sym_name = ((authtable *) data)->name; sym->sym_module = ((authtable *) data)->m; sym->ptr.sym_auth = data; symbol_table = auth_symbol_table; break; case PR_SYM_HOOK: sym = sym_alloc(); sym->sym_type = PR_SYM_HOOK; sym->sym_name = ((cmdtable *) data)->command; sym->sym_module = ((cmdtable *) data)->m; sym->ptr.sym_hook = data; symbol_table = hook_symbol_table; break; default: errno = EINVAL; return -1; } /* XXX Should we check for null sym->sym_module as well? */ if (sym->sym_name == NULL) { destroy_pool(sym->sym_pool); errno = EPERM; return -1; } sym_namelen = strlen(sym->sym_name); if (sym_namelen == 0) { destroy_pool(sym->sym_pool); errno = EPERM; return -1; } /* Don't forget to include one for the terminating NUL. */ sym->sym_namelen = sym_namelen + 1; hash = sym_type_hash(sym_type, sym->sym_name, sym->sym_namelen); idx = hash % PR_TUNABLE_HASH_TABLE_SIZE; sym->sym_hash = hash; if (!symbol_table[idx]) { symbol_table[idx] = xaset_create(symbol_pool, (XASET_COMPARE) sym_cmp); } xaset_insert_sort(symbol_table[idx], (xasetmember_t *) sym, TRUE); return 0; }