kdb: Adopt scheduler's task classification
[linux-2.6-microblaze.git] / kernel / debug / kdb / kdb_support.c
index 7507d9a..df2bfac 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/uaccess.h>
 #include <linux/kdb.h>
 #include <linux/slab.h>
+#include <linux/ctype.h>
 #include "kdb_private.h"
 
 /*
@@ -473,82 +474,7 @@ int kdb_putword(unsigned long addr, unsigned long word, size_t size)
        return diag;
 }
 
-/*
- * kdb_task_state_string - Convert a string containing any of the
- *     letters DRSTCZEUIMA to a mask for the process state field and
- *     return the value.  If no argument is supplied, return the mask
- *     that corresponds to environment variable PS, DRSTCZEU by
- *     default.
- * Inputs:
- *     s       String to convert
- * Returns:
- *     Mask for process state.
- * Notes:
- *     The mask folds data from several sources into a single long value, so
- *     be careful not to overlap the bits.  TASK_* bits are in the LSB,
- *     special cases like UNRUNNABLE are in the MSB.  As of 2.6.10-rc1 there
- *     is no overlap between TASK_* and EXIT_* but that may not always be
- *     true, so EXIT_* bits are shifted left 16 bits before being stored in
- *     the mask.
- */
-
-/* unrunnable is < 0 */
-#define UNRUNNABLE     (1UL << (8*sizeof(unsigned long) - 1))
-#define RUNNING                (1UL << (8*sizeof(unsigned long) - 2))
-#define IDLE           (1UL << (8*sizeof(unsigned long) - 3))
-#define DAEMON         (1UL << (8*sizeof(unsigned long) - 4))
 
-unsigned long kdb_task_state_string(const char *s)
-{
-       long res = 0;
-       if (!s) {
-               s = kdbgetenv("PS");
-               if (!s)
-                       s = "DRSTCZEU"; /* default value for ps */
-       }
-       while (*s) {
-               switch (*s) {
-               case 'D':
-                       res |= TASK_UNINTERRUPTIBLE;
-                       break;
-               case 'R':
-                       res |= RUNNING;
-                       break;
-               case 'S':
-                       res |= TASK_INTERRUPTIBLE;
-                       break;
-               case 'T':
-                       res |= TASK_STOPPED;
-                       break;
-               case 'C':
-                       res |= TASK_TRACED;
-                       break;
-               case 'Z':
-                       res |= EXIT_ZOMBIE << 16;
-                       break;
-               case 'E':
-                       res |= EXIT_DEAD << 16;
-                       break;
-               case 'U':
-                       res |= UNRUNNABLE;
-                       break;
-               case 'I':
-                       res |= IDLE;
-                       break;
-               case 'M':
-                       res |= DAEMON;
-                       break;
-               case 'A':
-                       res = ~0UL;
-                       break;
-               default:
-                         kdb_func_printf("unknown flag '%c' ignored\n", *s);
-                         break;
-               }
-               ++s;
-       }
-       return res;
-}
 
 /*
  * kdb_task_state_char - Return the character that represents the task state.
@@ -559,7 +485,6 @@ unsigned long kdb_task_state_string(const char *s)
  */
 char kdb_task_state_char (const struct task_struct *p)
 {
-       unsigned int p_state;
        unsigned long tmp;
        char state;
        int cpu;
@@ -568,25 +493,18 @@ char kdb_task_state_char (const struct task_struct *p)
            copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long)))
                return 'E';
 
-       cpu = kdb_process_cpu(p);
-       p_state = READ_ONCE(p->__state);
-       state = (p_state == 0) ? 'R' :
-               (p_state < 0) ? 'U' :
-               (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
-               (p_state & TASK_STOPPED) ? 'T' :
-               (p_state & TASK_TRACED) ? 'C' :
-               (p->exit_state & EXIT_ZOMBIE) ? 'Z' :
-               (p->exit_state & EXIT_DEAD) ? 'E' :
-               (p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
+       state = task_state_to_char((struct task_struct *) p);
+
        if (is_idle_task(p)) {
                /* Idle task.  Is it really idle, apart from the kdb
                 * interrupt? */
+               cpu = kdb_process_cpu(p);
                if (!kdb_task_has_cpu(p) || kgdb_info[cpu].irq_depth == 1) {
                        if (cpu != kdb_initial_cpu)
-                               state = 'I';    /* idle task */
+                               state = '-';    /* idle task */
                }
-       } else if (!p->mm && state == 'S') {
-               state = 'M';    /* sleeping system daemon */
+       } else if (!p->mm && strchr("IMS", state)) {
+               state = tolower(state);         /* sleeping system daemon */
        }
        return state;
 }
@@ -596,14 +514,28 @@ char kdb_task_state_char (const struct task_struct *p)
  *     given by the mask.
  * Inputs:
  *     p       struct task for the process
- *     mask    mask from kdb_task_state_string to select processes
+ *     mask    set of characters used to select processes; both NULL
+ *             and the empty string mean adopt a default filter, which
+ *             is to suppress sleeping system daemons and the idle tasks
  * Returns:
  *     True if the process matches at least one criteria defined by the mask.
  */
-unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask)
+bool kdb_task_state(const struct task_struct *p, const char *mask)
 {
-       char state[] = { kdb_task_state_char(p), '\0' };
-       return (mask & kdb_task_state_string(state)) != 0;
+       char state = kdb_task_state_char(p);
+
+       /* If there is no mask, then we will filter code that runs when the
+        * scheduler is idling and any system daemons that are currently
+        * sleeping.
+        */
+       if (!mask || mask[0] == '\0')
+               return !strchr("-ims", state);
+
+       /* A is a special case that matches all states */
+       if (strchr(mask, 'A'))
+               return true;
+
+       return strchr(mask, state);
 }
 
 /* Maintain a small stack of kdb_flags to allow recursion without disturbing