#include <sys/wait.h>
#include <limits.h>
#include <string.h>
+#include <time.h>
#include "debugger.h"
+#if 0
#define USLEEP (1000000 / 2)
+#endif
+#define TIMEOUT_SECS 20
+/* LOOPS_MIN is a safety as QEMU clock time sucks.
+ 100000 is 4s natively and 53s in QEMU. */
+#define LOOPS_MIN 500000
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
{
/* Separate the valid `1 << enum state' and `enum state' ranges. */
STATE_FIRST = 4,
+ STATE_INSTABLE,
STATE_ENOENT,
STATE_SLEEPING,
STATE_RUNNING,
STATE_STOPPED,
STATE_PTRACED,
STATE_ZOMBIE,
+ STATE_DEAD,
STATE_LAST
};
{
switch (state)
{
+ case STATE_INSTABLE: return "STATE_INSTABLE";
case STATE_ENOENT: return "STATE_ENOENT";
case STATE_SLEEPING: return "STATE_SLEEPING";
case STATE_RUNNING: return "STATE_RUNNING";
case STATE_STOPPED: return "STATE_STOPPED";
case STATE_PTRACED: return "STATE_PTRACED";
case STATE_ZOMBIE: return "STATE_ZOMBIE";
+ case STATE_DEAD: return "STATE_DEAD";
default: crash ();
}
/* NOTREACHED */
crash ();
}
-#define STATE(pid, expect_mask) state ((pid), (expect_mask), #expect_mask )
-
-static enum state state (pid_t pid, unsigned expect_mask, const char *expect_mask_string)
+static enum state state_get (pid_t pid)
{
char status_name[32];
char line[LINE_MAX];
delay ();
- /* Sanity check `1 << enum state' was not misplaced with `enum state'. */
- assert (1 << (STATE_FIRST + 1) >= STATE_LAST);
- assert (expect_mask != 0);
-#define MASK_UNDER_EXCLUSIVE(bit) ((1 << (bit)) - 1)
-#define MASK_ABOVE_INCLUSIVE(bit) (~MASK_UNDER_EXCLUSIVE (bit))
- assert ((expect_mask & MASK_UNDER_EXCLUSIVE (STATE_FIRST + 1)) == 0);
- assert ((expect_mask & MASK_ABOVE_INCLUSIVE (STATE_LAST)) == 0);
-#undef MASK_ABOVE_INCLUSIVE
-#undef MASK_UNDER_EXCLUSIVE
-
snprintf (status_name, sizeof (status_name), "/proc/%d/status", (int) pid);
f = fopen (status_name, "r");
if (f == NULL && errno == ENOENT)
found = STATE_ENOENT;
else if (f == NULL)
- crash ();
+ {
+ fprintf (stderr, "errno = %d\n", errno);
+ crash ();
+ }
else
{
int i;
- found = STATE_ENOENT;
+ found = STATE_INSTABLE;
while (errno = 0, fgets (line, sizeof (line), f) != NULL)
{
const char *const string = "State:\t";
found = STATE_PTRACED;
else if (strcmp (line + length, "Z (zombie)\n") == 0)
found = STATE_ZOMBIE;
+ /* FIXME: What does it mean? */
+ else if (strcmp (line + length, "X (dead)\n") == 0)
+ found = STATE_DEAD;
else
{
fprintf (stderr, "Found an unknown state: %s", line + length);
crash ();
}
}
- assert (found != STATE_ENOENT);
+ assert (found != STATE_INSTABLE || errno == ESRCH);
i = fclose (f);
assert (i == 0);
}
- if (((1 << found) & expect_mask) == 0)
+ return found;
+}
+
+#define STATE(pid, expect_mask) state ((pid), (expect_mask), #expect_mask )
+
+static enum state state (pid_t pid, unsigned expect_mask, const char *expect_mask_string)
+{
+ enum state found;
+ time_t timeout = time (NULL) + TIMEOUT_SECS;
+ unsigned loops = 0;
+
+ /* Sanity check `1 << enum state' was not misplaced with `enum state'. */
+ assert (1 << (STATE_FIRST + 1) >= STATE_LAST);
+ assert (expect_mask != 0);
+#define MASK_UNDER_EXCLUSIVE(bit) ((1 << (bit)) - 1)
+#define MASK_ABOVE_INCLUSIVE(bit) (~MASK_UNDER_EXCLUSIVE (bit))
+ assert ((expect_mask & MASK_UNDER_EXCLUSIVE (STATE_FIRST + 1)) == 0);
+ assert ((expect_mask & MASK_ABOVE_INCLUSIVE (STATE_LAST)) == 0);
+#undef MASK_ABOVE_INCLUSIVE
+#undef MASK_UNDER_EXCLUSIVE
+
+ do
{
- fprintf (stderr, "Found for PID %d state %s but expecting (%s)\n",
- (int) pid, state_to_name (found), expect_mask_string);
- crash ();
+ found = state_get (pid);
+
+ if (((1 << found) & expect_mask) != 0)
+ return found;
}
- return found;
+ while (loops++ < LOOPS_MIN || time (NULL) < timeout);
+
+ fprintf (stderr, "Found for PID %d state %s but expecting (%s)\n",
+ (int) pid, state_to_name (found), expect_mask_string);
+ crash ();
}
/* Debugging only: Number of signal needing redelivery on PTRACE_ATTACH. */