Add a new do_list_no_hash() function which is similar to do_list() but
without the hash_table overhead and without the LIST_ALLOCATE.
This function will be useful for faster and lower overhead list
enumeration, especially for the "list" command.

Signed-off-by: Dave Wysochanski <[email protected]>
---
 defs.h  |   1 +
 tools.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 190 insertions(+)

diff --git a/defs.h b/defs.h
index b05aecc..3ab295a 100644
--- a/defs.h
+++ b/defs.h
@@ -4944,6 +4944,7 @@ char *shift_string_right(char *, int);
 int bracketed(char *, char *, int);
 void backspace(int);
 int do_list(struct list_data *);
+int do_list_no_hash(struct list_data *);
 struct radix_tree_ops {
        void (*entry)(ulong node, ulong slot, const char *path,
                      ulong index, void *private);
diff --git a/tools.c b/tools.c
index 1a83643..a642d60 100644
--- a/tools.c
+++ b/tools.c
@@ -3863,6 +3863,195 @@ do_list(struct list_data *ld)
 }
 
 /*
+ * Similar to do_list() but without the hash_table or LIST_ALLOCATE.
+ * Useful for the 'list' command and other callers needing faster list
+ * enumeration.
+ */
+int
+do_list_no_hash(struct list_data *ld)
+{
+       ulong next, last, first, offset;
+       ulong searchfor, readflag;
+       int i, count, others;
+       unsigned int radix;
+       struct req_entry **e = NULL;
+
+       if (CRASHDEBUG(1)) {
+               others = 0;
+               console("             flags: %lx (", ld->flags);
+               if (ld->flags & VERBOSE)
+                       console("%sVERBOSE", others++ ? "|" : "");
+               if (ld->flags & LIST_OFFSET_ENTERED)
+                       console("%sLIST_OFFSET_ENTERED", others++ ? "|" : "");
+               if (ld->flags & LIST_START_ENTERED)
+                       console("%sLIST_START_ENTERED", others++ ? "|" : "");
+               if (ld->flags & LIST_HEAD_FORMAT)
+                       console("%sLIST_HEAD_FORMAT", others++ ? "|" : "");
+               if (ld->flags & LIST_HEAD_POINTER)
+                       console("%sLIST_HEAD_POINTER", others++ ? "|" : "");
+               if (ld->flags & RETURN_ON_DUPLICATE)
+                       console("%sRETURN_ON_DUPLICATE", others++ ? "|" : "");
+               if (ld->flags & RETURN_ON_LIST_ERROR)
+                       console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
+               if (ld->flags & RETURN_ON_LIST_ERROR)
+                       console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : "");
+               if (ld->flags & LIST_STRUCT_RADIX_10)
+                       console("%sLIST_STRUCT_RADIX_10", others++ ? "|" : "");
+               if (ld->flags & LIST_STRUCT_RADIX_16)
+                       console("%sLIST_STRUCT_RADIX_16", others++ ? "|" : "");
+               if (ld->flags & LIST_ALLOCATE)
+                       console("%sLIST_ALLOCATE", others++ ? "|" : "");
+               if (ld->flags & LIST_CALLBACK)
+                       console("%sLIST_CALLBACK", others++ ? "|" : "");
+               if (ld->flags & CALLBACK_RETURN)
+                       console("%sCALLBACK_RETURN", others++ ? "|" : "");
+               console(")\n");
+               console("             start: %lx\n", ld->start);
+               console("     member_offset: %ld\n", ld->member_offset);
+               console("  list_head_offset: %ld\n", ld->list_head_offset);
+               console("               end: %lx\n", ld->end);
+               console("         searchfor: %lx\n", ld->searchfor);
+               console("   structname_args: %lx\n", ld->structname_args);
+               if (!ld->structname_args)
+                       console("        structname: (unused)\n");
+               for (i = 0; i < ld->structname_args; i++)
+                       console("     structname[%d]: %s\n", i, 
ld->structname[i]);
+               console("            header: %s\n", ld->header);
+               console("          list_ptr: %lx\n", (ulong)ld->list_ptr);
+               console("     callback_func: %lx\n", (ulong)ld->callback_func);
+               console("     callback_data: %lx\n", (ulong)ld->callback_data);
+               console("struct_list_offset: %lx\n", ld->struct_list_offset);
+       }
+
+       count = 0;
+       searchfor = ld->searchfor;
+       ld->searchfor = 0;
+       if (ld->flags & LIST_STRUCT_RADIX_10)
+               radix = 10;
+       else if (ld->flags & LIST_STRUCT_RADIX_16)
+               radix = 16;
+       else
+               radix = 0;
+       next = ld->start;
+
+       readflag = ld->flags & RETURN_ON_LIST_ERROR ?
+               (RETURN_ON_ERROR|QUIET) : FAULT_ON_ERROR;
+
+       if (!readmem(next + ld->member_offset, KVADDR, &first, sizeof(void *),
+            "first list entry", readflag)) {
+                error(INFO, "\ninvalid list entry: %lx\n", next);
+               return -1;
+       }
+
+       if (ld->header)
+               fprintf(fp, "%s", ld->header);
+
+       offset = ld->list_head_offset + ld->struct_list_offset;
+
+       if (ld->structname && (ld->flags & LIST_READ_MEMBER)) {
+               e = (struct req_entry **)GETBUF(sizeof(*e) * 
ld->structname_args);
+               for (i = 0; i < ld->structname_args; i++)
+                       e[i] = fill_member_offsets(ld->structname[i]);
+       }
+
+       while (1) {
+               if (ld->flags & VERBOSE) {
+                       fprintf(fp, "%lx\n", next - ld->list_head_offset);
+
+                       if (ld->structname) {
+                               for (i = 0; i < ld->structname_args; i++) {
+                                       switch (count_chars(ld->structname[i], 
'.'))
+                                       {
+                                       case 0:
+                                               dump_struct(ld->structname[i],
+                                                       next - offset, radix);
+                                               break;
+                                       default:
+                                               if (ld->flags & 
LIST_PARSE_MEMBER)
+                                                       dump_struct_members(ld, 
i, next);
+                                               else if (ld->flags & 
LIST_READ_MEMBER)
+                                                       
dump_struct_members_fast(e[i],
+                                                               radix, next - 
offset);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+                if (next && 0) { /* FIXME - duplicate detection */
+                       if (ld->flags &
+                           (RETURN_ON_DUPLICATE|RETURN_ON_LIST_ERROR)) {
+                               error(INFO, "\nduplicate list entry: %lx\n",
+                                       next);
+                               return -1;
+                       }
+                        error(FATAL, "\nduplicate list entry: %lx\n", next);
+               }
+
+               if ((searchfor == next) ||
+                   (searchfor == (next - ld->list_head_offset)))
+                       ld->searchfor = searchfor;
+
+               count++;
+                last = next;
+
+               if ((ld->flags & LIST_CALLBACK) &&
+                   ld->callback_func((void *)(next - ld->list_head_offset),
+                   ld->callback_data) && (ld->flags & CALLBACK_RETURN))
+                       break;
+
+                if (!readmem(next + ld->member_offset, KVADDR, &next,
+                   sizeof(void *), "list entry", readflag)) {
+                       error(INFO, "\ninvalid list entry: %lx\n", next);
+                       return -1;
+               }
+
+               if (next == 0) {
+                       if (ld->flags & LIST_HEAD_FORMAT) {
+                               error(INFO, "\ninvalid list entry: 0\n");
+                               return -1;
+                       }
+                       if (CRASHDEBUG(1))
+                               console("do_list end: next:%lx\n", next);
+                       break;
+               }
+
+               if (next == ld->end) {
+                       if (CRASHDEBUG(1))
+                               console("do_list end: next:%lx == end:%lx\n",
+                                       next, ld->end);
+                       break;
+               }
+
+               if (next == ld->start) {
+                       if (CRASHDEBUG(1))
+                               console("do_list end: next:%lx == start:%lx\n",
+                                       next, ld->start);
+                       break;
+               }
+
+               if (next == last) {
+                       if (CRASHDEBUG(1))
+                               console("do_list end: next:%lx == last:%lx\n",
+                                       next, last);
+                       break;
+               }
+
+               if ((next == first) && (count != 1)) {
+                       if (CRASHDEBUG(1))
+                     console("do_list end: next:%lx == first:%lx (count %d)\n",
+                               next, last, count);
+                       break;
+               }
+       }
+
+       if (CRASHDEBUG(1))
+               console("do_list count: %d\n", count);
+
+       return count;
+}
+
+/*
  *  Issue a dump_struct_member() call for one or more structure
  *  members.  Multiple members are passed in a comma-separated
  *  list using the the format:  
-- 
1.8.3.1

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to