You should use linux/wait.h or similar facilities rather than calling schedule() and wake_up_process() directly. This doesn't have anything to do with utrace, it's just the clean practice for normal kinds of blocking in the kernel, for a variety of reasons. That has to do with how your control thread blocks, which is just the normal set of issues for any thread in kernel code. You are using the lowest-level way of doing things, which is not recommended--that's why various higher-level facilities exist.
The admonition to use utrace facilities for all blocks has to do with when you make a traced thread block. You are on the correct path in that regard. The relevant parts of your scenario match what I described. The race I talked about between your control thread's utrace_control() and tracee callbacks returning UTRACE_STOP explains what you are seeing. Thanks, Roland