+};
+
+union Tab{
+ struct process p;
+ struct user u;
+};
+
+typedef union Tab cell;
+
+int (*cmp)(); /* compares 2 cells; set to appropriate func */
+cell *enter();
+struct user *finduser();
+struct user *wasuser();
+
+/*
+ * Table elements are keyed by the name of the file exec'ed.
+ * Because on large systems, many files can be exec'ed,
+ * a static table size may grow to be too large.
+ *
+ * Table elements are allocated in chunks dynamically, linked
+ * together so that they may be retrieved sequentially.
+ *
+ * An index into the table structure is provided by hashing through
+ * a seperate hash table.
+ * The hash table is segmented, and dynamically extendable.
+ * Realize that the hash table and accounting information is kept
+ * in different segments!
+ *
+ * We have a linked list of hash table segments; within each
+ * segment we use a quadratic rehash that touches no more than 1/2
+ * of the buckets in the hash table when probing.
+ * If the probe does not find the desired symbol, it moves to the
+ * next segment, or allocates a new segment.
+ *
+ * Hash table segments are kept on the linked list with the first
+ * segment always first (that will probably contain the
+ * most frequently executed commands) and
+ * the last added segment immediately after the first segment,
+ * to hopefully gain something by locality of reference.
+ *
+ * We store the per user information in the same structure as
+ * the per exec'ed file information. This allows us to use the
+ * same managers for both, as the number of user id's may be very
+ * large.
+ * User information is keyed by the first character in the name
+ * being a '\001', followed by four bytes of (long extended)
+ * user id number, followed by a null byte.
+ * The actual user names are kept in a seperate field of the
+ * user structure, and is filled in upon demand later.
+ * Iteration through all users by low user id to high user id
+ * is done by just probing the table, which is gross.
+ */
+#define USERKEY '\001'
+#define ISPROCESS(tp) (tp->p.name[0] && (tp->p.name[0] != USERKEY))
+#define ISUSER(tp) (tp->p.name[0] && (tp->p.name[0] == USERKEY))
+
+#define TABDALLOP 500
+struct allocbox{
+ struct allocbox *nextalloc;
+ cell tabslots[TABDALLOP];
+};
+
+struct allocbox *allochead; /*head of chunk list*/
+struct allocbox *alloctail; /*tail*/
+struct allocbox *newbox; /*for creating a new chunk*/
+cell *nexttab; /*next table element that is free*/
+int tabsleft; /*slots left in current chunk*/
+int ntabs;
+/*
+ * Iterate through all symbols in the symbol table in declaration
+ * order.
+ * struct allocbox *allocwalk;
+ * cell *sp, *ub;
+ *
+ * sp points to the desired item, allocwalk and ub are there
+ * to make the iteration go.
+ */
+
+#define DECLITERATE(allocwalk, walkpointer, ubpointer) \
+ for(allocwalk = allochead; \
+ allocwalk != 0; \
+ allocwalk = allocwalk->nextalloc) \
+ for (walkpointer = &allocwalk->tabslots[0],\
+ ubpointer = &allocwalk->tabslots[TABDALLOP], \
+ ubpointer = ubpointer > ( (cell *)alloctail) \
+ ? nexttab : ubpointer ;\
+ walkpointer < ubpointer; \
+ walkpointer++ )
+
+#define TABCHUNKS(allocwalk, tabptr, size) \
+ for (allocwalk = allochead; \
+ allocwalk != 0; \
+ allocwalk = allocwalk->nextalloc) \
+ if ( \
+ (tabptr = &allocwalk->tabslots[0]), \
+ (size = \
+ ( (&allocwalk->tabslots[TABDALLOP]) \
+ > ((cell *)alloctail) \
+ ) \
+ ? (nexttab - tabptr) : TABDALLOP \
+ ), \
+ 1 \
+ )
+#define PROCESSITERATE(allocwalk, walkpointer, ubpointer) \
+ DECLITERATE(allocwalk, walkpointer, ubpointer) \
+ if (ISPROCESS(walkpointer))
+
+#define USERITERATE(allocwalk, walkpointer, ubpointer) \
+ DECLITERATE(allocwalk, walkpointer, ubpointer) \
+ if (ISUSER(walkpointer))
+/*
+ * When we have to sort the segmented accounting table, we
+ * create a vector of sorted queues that is merged
+ * to sort the entire accounting table.
+ */
+struct chunkdesc {
+ cell *chunk_tp;
+ int chunk_n;
+};
+
+/*
+ * Hash table segments and manager
+ */
+#define NHASH 1103
+struct hashdallop {
+ int h_nused;
+ struct hashdallop *h_next;
+ cell *h_tab[NHASH];
+};
+struct hashdallop *htab; /* head of the list */
+int htabinstall; /* install the symbol */