+/*
+ * The pidlist_* routines support the functions in this file that
+ * walk lists of processes applying filters and callouts to the
+ * elements of the list.
+ *
+ * A prior implementation used a single linear array, which can be
+ * tricky to allocate on large systems. This implementation creates
+ * an SLIST of modestly sized arrays of PIDS_PER_ENTRY elements.
+ *
+ * The array should be sized large enough to keep the overhead of
+ * walking the list low, but small enough that blocking allocations of
+ * pidlist_entry_t structures always succeed.
+ */
+
+#define PIDS_PER_ENTRY 1021
+
+typedef struct pidlist_entry {
+ SLIST_ENTRY(pidlist_entry) pe_link;
+ u_int pe_nused;
+ pid_t pe_pid[PIDS_PER_ENTRY];
+} pidlist_entry_t;
+
+typedef struct {
+ SLIST_HEAD(, pidlist_entry) pl_head;
+ struct pidlist_entry *pl_active;
+ u_int pl_nalloc;
+} pidlist_t;
+
+static __inline__ pidlist_t *
+pidlist_init(pidlist_t *pl)
+{
+ SLIST_INIT(&pl->pl_head);
+ pl->pl_active = NULL;
+ pl->pl_nalloc = 0;
+ return pl;
+}
+
+static u_int
+pidlist_alloc(pidlist_t *pl, u_int needed)
+{
+ while (pl->pl_nalloc < needed) {
+ pidlist_entry_t *pe = kalloc(sizeof(*pe));
+ if (NULL == pe) {
+ panic("no space for pidlist entry");
+ }
+ pe->pe_nused = 0;
+ SLIST_INSERT_HEAD(&pl->pl_head, pe, pe_link);
+ pl->pl_nalloc += (sizeof(pe->pe_pid) / sizeof(pe->pe_pid[0]));
+ }
+ return pl->pl_nalloc;
+}
+
+static void
+pidlist_free(pidlist_t *pl)
+{
+ pidlist_entry_t *pe;
+ while (NULL != (pe = SLIST_FIRST(&pl->pl_head))) {
+ SLIST_FIRST(&pl->pl_head) = SLIST_NEXT(pe, pe_link);
+ kfree(pe, sizeof(*pe));
+ }
+ pl->pl_nalloc = 0;
+}
+
+static __inline__ void
+pidlist_set_active(pidlist_t *pl)
+{
+ pl->pl_active = SLIST_FIRST(&pl->pl_head);
+ assert(pl->pl_active);
+}
+
+static void
+pidlist_add_pid(pidlist_t *pl, pid_t pid)
+{
+ pidlist_entry_t *pe = pl->pl_active;
+ if (pe->pe_nused >= sizeof(pe->pe_pid) / sizeof(pe->pe_pid[0])) {
+ if (NULL == (pe = SLIST_NEXT(pe, pe_link))) {
+ panic("pidlist allocation exhausted");
+ }
+ pl->pl_active = pe;
+ }
+ pe->pe_pid[pe->pe_nused++] = pid;
+}
+
+static __inline__ u_int
+pidlist_nalloc(const pidlist_t *pl)
+{
+ return pl->pl_nalloc;
+}
+