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;