Dear Roland, dear utrace developers,

I have now a complete patch that seems to be quite stable.
At least Kmview have passed through the tests without getting stuck randomly 
for the race condition.

All the other comments about utrace&virtualization (see my message of Feb 04) 
are already pending
1- Virtual Machines may need to change the system call
2- UTRACE_SYSCALL_ABORT: is it really useful as a return value for
report_syscall_entry?
3- Nesting, is it really useful to run all the reports in a row and
(eventually) stop and the end waiting for all the engines?
4- report_syscall_entry engines evaluation order should be reversed

ciao
        renzo
----
--- linux-2.6.29-rc4-utrace/kernel/utrace.c.mcgrath     2009-02-13 
18:28:25.000000000 +0100
+++ linux-2.6.29-rc4-utrace/kernel/utrace.c     2009-02-13 19:14:18.000000000 
+0100
@@ -491,6 +491,13 @@
 #define DEAD_FLAGS_MASK        (UTRACE_EVENT(REAP))
 #define LIVE_FLAGS_MASK        (~0UL)
 
+static void mark_engine_wants_stop(struct utrace_attached_engine *engine);
+static void clear_engine_wants_stop(struct utrace_attached_engine *engine);
+static bool engine_wants_stop(struct utrace_attached_engine *engine);
+static void mark_engine_wants_resume(struct utrace_attached_engine *engine);
+static void clear_engine_wants_resume(struct utrace_attached_engine *engine);
+static bool engine_wants_resume(struct utrace_attached_engine *engine);
+
 /*
  * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up.
  * @task == current, @utrace == current->utrace, which is not locked.
@@ -500,6 +507,7 @@
 static bool utrace_stop(struct task_struct *task, struct utrace *utrace)
 {
        bool killed;
+       struct utrace_attached_engine *engine, *next;
 
        /*
         * @utrace->stopped is the flag that says we are safely
@@ -521,6 +529,23 @@
                return true;
        }
 
+       /* final check: it is really needed to stop? */
+       list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
+               if ((engine->ops != &utrace_detached_ops) && 
engine_wants_stop(engine)) {
+                       if (engine_wants_resume(engine)) {
+                               clear_engine_wants_stop(engine);
+                               clear_engine_wants_resume(engine);
+                       }
+                       else
+                               utrace->stopped = 1;
+               }
+       }
+       if (unlikely(!utrace->stopped)) {
+               spin_unlock_irq(&task->sighand->siglock);
+               spin_unlock(&utrace->lock);
+               return false;
+       }
+
        utrace->stopped = 1;
        __set_current_state(TASK_TRACED);
 
@@ -784,6 +809,7 @@
  * to record whether the engine is keeping the target thread stopped.
  */
 #define ENGINE_STOP            (1UL << _UTRACE_NEVENTS)
+#define ENGINE_RESUME          (1UL << (_UTRACE_NEVENTS+1))
 
 static void mark_engine_wants_stop(struct utrace_attached_engine *engine)
 {
@@ -800,6 +826,21 @@
        return (engine->flags & ENGINE_STOP) != 0;
 }
 
+static void mark_engine_wants_resume(struct utrace_attached_engine *engine)
+{
+       engine->flags |= ENGINE_RESUME;
+}
+
+static void clear_engine_wants_resume(struct utrace_attached_engine *engine)
+{
+       engine->flags &= ~ENGINE_RESUME;
+}
+
+static bool engine_wants_resume(struct utrace_attached_engine *engine)
+{
+       return (engine->flags & ENGINE_RESUME) != 0;
+}
+
 /**
  * utrace_set_events - choose which event reports a tracing engine gets
  * @target:            thread to affect
@@ -1050,6 +1091,10 @@
                        list_move(&engine->entry, &detached);
                } else {
                        flags |= engine->flags | UTRACE_EVENT(REAP);
+                       if (engine_wants_resume(engine)) {
+                               clear_engine_wants_stop(engine);
+                               clear_engine_wants_resume(engine);
+                       }
                        wake = wake && !engine_wants_stop(engine);
                }
        }
@@ -1282,6 +1327,7 @@
                 * There might not be another report before it just
                 * resumes, so make sure single-step is not left set.
                 */
+               mark_engine_wants_resume(engine);
                if (likely(resume))
                        user_disable_single_step(target);
                break;

Reply via email to