summaryrefslogtreecommitdiffstats
path: root/runtime/task_finder.c
diff options
context:
space:
mode:
authorDavid Smith <dsmith@redhat.com>2008-09-25 16:13:34 -0500
committerDavid Smith <dsmith@redhat.com>2008-09-25 16:14:02 -0500
commitd107fe8044105a30f176d513ae36b91ff82cae9d (patch)
tree60878dd8dfc7af844ab433b44fb55efc58548ec0 /runtime/task_finder.c
parent25a632047a89804ffbfe6bb012af632ad4e6bdc1 (diff)
downloadsystemtap-steved-d107fe8044105a30f176d513ae36b91ff82cae9d.tar.gz
systemtap-steved-d107fe8044105a30f176d513ae36b91ff82cae9d.tar.xz
systemtap-steved-d107fe8044105a30f176d513ae36b91ff82cae9d.zip
New utrace fixes.
2008-09-25 David Smith <dsmith@redhat.com> * task_finder.c (__stp_utrace_attach): Added action flag to know to request the thread to be stopped or not. (stap_utrace_attach): Now just calls __stp_utrace_attach(). (__stp_utrace_task_finder_target_quiesce): Handles utrace_set_events() errors properly. * utrace_compatibility.h (enum utrace_resume_action): Added utrace_resume_action enum. (utrace_control): Added UTRACE_STOP support. (utrace_engine_put): New. (utrace_barrier): New.
Diffstat (limited to 'runtime/task_finder.c')
-rw-r--r--runtime/task_finder.c103
1 files changed, 80 insertions, 23 deletions
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 493ca6f7..75c706ec 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -89,7 +89,7 @@ struct stap_task_finder_target {
size_t pathlen;
/* public: */
- const char *pathname;
+ const char *pathname;
pid_t pid;
stap_task_finder_callback callback;
stap_task_finder_vm_callback vm_callback;
@@ -148,8 +148,8 @@ static int
stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
{
// Since this __stp_task_finder_list is (currently) only
- // written to in one big setup operation before the task
- // finder process is started, we don't need to lock it.
+ // written to in one big setup operation before the task
+ // finder process is started, we don't need to lock it.
struct list_head *node;
struct stap_task_finder_target *tgt = NULL;
int found_node = 0;
@@ -258,6 +258,7 @@ stap_utrace_detach(struct task_struct *tsk,
rc, tsk->pid);
break;
}
+ utrace_engine_put(engine);
}
return rc;
}
@@ -394,9 +395,10 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
: __STP_TASK_VM_BASE_EVENTS)
static int
-stap_utrace_attach(struct task_struct *tsk,
- const struct utrace_engine_ops *ops, void *data,
- unsigned long event_flags)
+__stp_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags,
+ enum utrace_resume_action action)
{
struct utrace_attached_engine *engine;
struct mm_struct *mm;
@@ -428,15 +430,51 @@ stap_utrace_attach(struct task_struct *tsk,
}
else {
rc = utrace_set_events(tsk, engine, event_flags);
- if (rc == 0)
+ if (rc == -EINPROGRESS) {
+ /*
+ * It's running our callback, so we have to
+ * synchronize. We can't keep rcu_read_lock,
+ * so the task pointer might die. But it's
+ * safe to call utrace_barrier() even with a
+ * stale task pointer, if we have an engine
+ * ref.
+ */
+ rc = utrace_barrier(tsk, engine);
+ if (rc != 0)
+ _stp_error("utrace_barrier returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ }
+ if (rc == 0) {
debug_task_finder_attach();
+
+ if (action != UTRACE_RESUME) {
+ rc = utrace_control(tsk, engine, UTRACE_STOP);
+ /* EINPROGRESS means we must wait for
+ * a callback, which is what we want. */
+ if (rc != 0 && rc != -EINPROGRESS)
+ _stp_error("utrace_control returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ else
+ rc = 0;
+ }
+
+ }
else
- _stp_error("utrace_set_events returned error %d on pid %d",
+ _stp_error("utrace_set_events2 returned error %d on pid %d",
rc, (int)tsk->pid);
+ utrace_engine_put(engine);
}
return rc;
}
+static int
+stap_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags)
+{
+ return __stp_utrace_attach(tsk, ops, data, event_flags, UTRACE_RESUME);
+}
+
static inline void
__stp_utrace_attach_match_filename(struct task_struct *tsk,
const char * const filename,
@@ -485,9 +523,10 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
// isn't set, we can go ahead and call the
// callback.
if (register_p) {
- rc = stap_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_ATTACHED_TASK_EVENTS);
+ rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_ATTACHED_TASK_EVENTS,
+ UTRACE_STOP);
if (rc != 0 && rc != EPERM)
break;
cb_tgt->engine_attached = 1;
@@ -601,8 +640,8 @@ __stp_utrace_task_finder_report_clone(enum utrace_resume_action action,
__stp_tf_handler_start();
// On clone, attach to the child.
- rc = stap_utrace_attach(child, engine->ops, 0,
- __STP_TASK_FINDER_EVENTS);
+ rc = __stp_utrace_attach(child, engine->ops, 0,
+ __STP_TASK_FINDER_EVENTS, UTRACE_RESUME);
if (rc != 0 && rc != EPERM) {
__stp_tf_handler_end();
return UTRACE_RESUME;
@@ -757,6 +796,22 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
// Turn off quiesce handling
rc = utrace_set_events(tsk, engine,
__STP_ATTACHED_TASK_BASE_EVENTS(tgt));
+
+ if (rc == -EINPROGRESS) {
+ /*
+ * It's running our callback, so we have to
+ * synchronize. We can't keep rcu_read_lock,
+ * so the task pointer might die. But it's
+ * safe to call utrace_barrier() even with
+ * a stale task pointer, if we have an engine ref.
+ */
+ rc = utrace_barrier(tsk, engine);
+ if (rc != 0)
+ _stp_error("utrace_barrier returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ rc = utrace_set_events(tsk, engine,
+ __STP_ATTACHED_TASK_BASE_EVENTS(tgt));
+ }
if (rc != 0)
_stp_error("utrace_set_events returned error %d on pid %d",
rc, (int)tsk->pid);
@@ -1173,13 +1228,14 @@ stap_start_task_finder(void)
size_t mmpathlen;
struct list_head *tgt_node;
- /* Skip over processes other than that specified with
- stap -c or -x. */
- if (_stp_target && tsk->tgid != _stp_target)
- continue;
+ /* Skip over processes other than that specified with
+ * stap -c or -x. */
+ if (_stp_target && tsk->tgid != _stp_target)
+ continue;
- rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
- __STP_TASK_FINDER_EVENTS);
+ rc = __stp_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
+ __STP_TASK_FINDER_EVENTS,
+ UTRACE_RESUME);
if (rc == EPERM) {
/* Ignore EPERM errors, which mean this wasn't
* a thread we can attach to. */
@@ -1242,16 +1298,17 @@ stap_start_task_finder(void)
continue;
// Set up events we need for attached tasks.
- rc = stap_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_ATTACHED_TASK_EVENTS);
+ rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_ATTACHED_TASK_EVENTS,
+ UTRACE_STOP);
if (rc != 0 && rc != EPERM)
goto stf_err;
cb_tgt->engine_attached = 1;
}
}
} while_each_thread(grp, tsk);
- stf_err:
+stf_err:
rcu_read_unlock();
_stp_kfree(mmpath_buf);