summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2007-10-02 17:44:25 +0000
committerfche <fche>2007-10-02 17:44:25 +0000
commit65aeaea0bc47637030ebe4c2d3a103e1fddaa8d8 (patch)
tree863f412bbf4a1f97af6fa02028bbdbbbf51a4770
parente59475742dc0363828f05a92979d5f6fa9588dee (diff)
downloadsystemtap-steved-65aeaea0bc47637030ebe4c2d3a103e1fddaa8d8.tar.gz
systemtap-steved-65aeaea0bc47637030ebe4c2d3a103e1fddaa8d8.tar.xz
systemtap-steved-65aeaea0bc47637030ebe4c2d3a103e1fddaa8d8.zip
2007-10-02 Frank Ch. Eigler <fche@redhat.com>
PR 5078 * tapsets.cxx (be_derived_probe): Rework to add error probe support. Emit probe description array in C for traversal by generated code. * register_standard_tapsets: Add error probes. * stapprobes.5.in: Document. * translate.cxx (emit_module_init): Handle errors that may occur during begin probes. (emit_module_exit): Use schedule() rather than cpu_relax() during shutdown synchronization wait loop. * staptree.cxx (probe::printsig): Put multiple probe points on same line. 2007-10-02 Frank Ch. Eigler <fche@redhat.com> PR 5078 * semok/twentysix.stp, systemtap.base/beginenderror.*: New tests.
-rw-r--r--ChangeLog14
-rw-r--r--stapprobes.5.in12
-rw-r--r--staptree.cxx2
-rw-r--r--tapsets.cxx123
-rw-r--r--testsuite/ChangeLog5
-rw-r--r--testsuite/semok/twentysix.stp4
-rw-r--r--testsuite/systemtap.base/beginenderror.exp22
-rw-r--r--testsuite/systemtap.base/beginenderror.stp5
-rw-r--r--translate.cxx45
9 files changed, 172 insertions, 60 deletions
diff --git a/ChangeLog b/ChangeLog
index a855e857..8aa93076 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2007-10-02 Frank Ch. Eigler <fche@redhat.com>
+
+ PR 5078
+ * tapsets.cxx (be_derived_probe): Rework to add error probe support.
+ Emit probe description array in C for traversal by generated code.
+ * register_standard_tapsets: Add error probes.
+ * stapprobes.5.in: Document.
+ * translate.cxx (emit_module_init): Handle errors that may occur
+ during begin probes.
+ (emit_module_exit): Use schedule() rather than cpu_relax() during
+ shutdown synchronization wait loop.
+ * staptree.cxx (probe::printsig): Put multiple probe points on same
+ line.
+
2007-09-28 Frank Ch. Eigler <fche@elastic.org>
* Makefile.in: Regenerated from Jim Keniston's uprobes Makefile.am
diff --git a/stapprobes.5.in b/stapprobes.5.in
index efefc1bf..536991ec 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -53,7 +53,7 @@ wildcards or aliases), and all them are then probed. A probe
declaration may also contain several comma-separated specifications,
all of which are probed.
-.SS BEGIN/END
+.SS BEGIN/END/ERROR
The probe points
.IR begin " and " end
@@ -80,6 +80,16 @@ increasing order, and the order between handlers with the same sequence
number is unspecified. When "begin" or "end" are given without a
sequence, they are effectively sequence zero.
+The
+.IR error
+probe point is similar to the
+.IR end
+probe, except that each such probe handler run when the session and
+after errors having occurred. In such cases, "end" probes are
+skipped, but each "error" prober is still attempted. This kind of
+probe can be used to clean up or emit a final gasp message. It may
+also be numerically parametrized to set a sequence.
+
.SS NEVER
The probe point
.IR never
diff --git a/staptree.cxx b/staptree.cxx
index a1a8211b..ccfc8a8d 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -879,7 +879,7 @@ void probe::printsig (ostream& o) const
{
for (unsigned i=0; i<locations.size(); i++)
{
- if (i > 0) o << "," << endl;
+ if (i > 0) o << ",";
locations[i]->print (o);
}
}
diff --git a/tapsets.cxx b/tapsets.cxx
index 1943b8af..c4d6962e 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -69,24 +69,31 @@ public:
// ------------------------------------------------------------------------
-// begin/end probes are run right during registration / deregistration
+// begin/end/error probes are run right during registration / deregistration
// ------------------------------------------------------------------------
+enum be_t { BEGIN, END, ERROR };
+
struct be_derived_probe: public derived_probe
{
- bool begin;
+ be_t type;
int64_t priority;
- be_derived_probe (probe* p, bool b, int64_t pr):
- derived_probe (p), begin (b), priority (pr) {}
- be_derived_probe (probe* p, probe_point* l, bool b, int64_t pr):
- derived_probe (p, l), begin (b), priority (pr) {}
+ be_derived_probe (probe* p, be_t t, int64_t pr):
+ derived_probe (p), type (t), priority (pr) {}
+ be_derived_probe (probe* p, probe_point* l, be_t t, int64_t pr):
+ derived_probe (p, l), type (t), priority (pr) {}
void join_group (systemtap_session& s);
static inline bool comp(be_derived_probe const *a,
be_derived_probe const *b)
- { return a->priority < b->priority; }
+ {
+ // This allows the BEGIN/END/ERROR probes to intermingle.
+ // But that's OK - they're always treversed with a nested
+ // "if (type==FOO)" conditional.
+ return a->priority < b->priority;
+ }
bool needs_global_locks () { return false; }
// begin/end probes don't need locks around global variables, since
@@ -105,8 +112,10 @@ public:
struct be_builder: public derived_probe_builder
{
- bool begin;
- be_builder(bool b) : begin(b) {}
+ be_t type;
+
+ be_builder(be_t t) : type(t) {}
+
virtual void build(systemtap_session &,
probe * base,
probe_point * location,
@@ -114,11 +123,12 @@ struct be_builder: public derived_probe_builder
vector<derived_probe *> & finished_results)
{
int64_t priority;
- if ((begin && !get_param(parameters, "begin", priority))
- || (!begin && !get_param(parameters, "end", priority)))
+ if ((type == BEGIN && !get_param(parameters, "begin", priority)) ||
+ (type == END && !get_param(parameters, "end", priority)) ||
+ (type == ERROR && !get_param(parameters, "error", priority)))
priority = 0;
finished_results.push_back(
- new be_derived_probe(base, location, begin, priority));
+ new be_derived_probe(base, location, type, priority));
}
};
@@ -293,20 +303,52 @@ be_derived_probe_group::emit_module_decls (systemtap_session& s)
if (probes.empty()) return;
s.op->newline() << "/* ---- begin/end probes ---- */";
- s.op->newline() << "void enter_begin_probe (void (*fn)(struct context*)) {";
+ s.op->newline() << "void enter_begin_probe (void (*fn)(struct context*), const char* pp) {";
s.op->indent(1);
common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", false, true);
- s.op->newline() << "c->probe_point = \"begin\";";
+ s.op->newline() << "c->probe_point = pp;";
s.op->newline() << "(*fn) (c);";
common_probe_entryfn_epilogue (s.op, false, true);
s.op->newline(-1) << "}";
- s.op->newline() << "void enter_end_probe (void (*fn)(struct context*)) {";
+
+ s.op->newline() << "void enter_end_probe (void (*fn)(struct context*), const char* pp) {";
s.op->indent(1);
common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", false, true);
- s.op->newline() << "c->probe_point = \"end\";";
+ s.op->newline() << "c->probe_point = pp;";
+ s.op->newline() << "(*fn) (c);";
+ common_probe_entryfn_epilogue (s.op, false, true);
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "void enter_error_probe (void (*fn)(struct context*), const char* pp) {";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", false, true);
+ s.op->newline() << "c->probe_point = pp;";
s.op->newline() << "(*fn) (c);";
common_probe_entryfn_epilogue (s.op, false, true);
s.op->newline(-1) << "}";
+
+ s.op->newline() << "struct stap_be_probe {";
+ s.op->newline(1) << "void (*ph)(struct context*);";
+ s.op->newline() << "const char* pp;";
+ s.op->newline() << "int type;";
+ s.op->newline(-1) << "} stap_be_probes[] = {";
+ s.op->indent(1);
+
+ // NB: We emit the table in sorted order here, so we don't have to
+ // store the priority numbers as integers and sort at run time.
+
+ sort(probes.begin(), probes.end(), be_derived_probe::comp);
+
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .pp="
+ << lex_cast_qstring (*probes[i]->sole_location()) << ",";
+ s.op->line() << " .ph=&" << probes[i]->name << ",";
+ s.op->line() << " .type=" << probes[i]->type;
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
}
void
@@ -314,19 +356,17 @@ be_derived_probe_group::emit_module_init (systemtap_session& s)
{
if (probes.empty()) return;
- bool have_begin_probes = false;
- sort(probes.begin(), probes.end(), be_derived_probe::comp);
- for (unsigned i=0; i < probes.size (); i++)
- if (probes[i]->begin)
- {
- have_begin_probes = true;
- s.op->newline() << "enter_begin_probe (& " << probes[i]->name << ");";
- }
-
- // If any of the begin probes signaled an error, indicate
- // failure to the rest of systemtap_module_init.
- if (have_begin_probes)
- s.op->newline() << "rc = (atomic_read (&session_state) == STAP_SESSION_ERROR);";
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type != " << BEGIN << ") continue;";
+ s.op->newline() << "enter_begin_probe (stp->ph, stp->pp);";
+ s.op->newline() << "/* rc = 0; */";
+ // NB: begin probes that cause errors do not constitute registration
+ // failures. An error message will probably get printed and if
+ // MAXERRORS was left at 1, we'll get an stp_exit. The
+ // error-handling probes will be run during the ordinary
+ // unregistration phase.
+ s.op->newline(-1) << "}";
}
void
@@ -334,10 +374,17 @@ be_derived_probe_group::emit_module_exit (systemtap_session& s)
{
if (probes.empty()) return;
- sort(probes.begin(), probes.end(), be_derived_probe::comp);
- for (unsigned i=0; i < probes.size (); i++)
- if (! probes[i]->begin) // note polarity
- s.op->newline() << "enter_end_probe (& " << probes[i]->name << ");";
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type != " << END << ") continue;";
+ s.op->newline() << "enter_end_probe (stp->ph, stp->pp);";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type != " << ERROR << ") continue;";
+ s.op->newline() << "enter_error_probe (stp->ph, stp->pp);";
+ s.op->newline(-1) << "}";
}
@@ -6246,10 +6293,12 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o)
void
register_standard_tapsets(systemtap_session & s)
{
- s.pattern_root->bind("begin")->bind(new be_builder(true));
- s.pattern_root->bind_num("begin")->bind(new be_builder(true));
- s.pattern_root->bind("end")->bind(new be_builder(false));
- s.pattern_root->bind_num("end")->bind(new be_builder(false));
+ s.pattern_root->bind("begin")->bind(new be_builder(BEGIN));
+ s.pattern_root->bind_num("begin")->bind(new be_builder(BEGIN));
+ s.pattern_root->bind("end")->bind(new be_builder(END));
+ s.pattern_root->bind_num("end")->bind(new be_builder(END));
+ s.pattern_root->bind("error")->bind(new be_builder(ERROR));
+ s.pattern_root->bind_num("error")->bind(new be_builder(ERROR));
s.pattern_root->bind("never")->bind(new never_builder());
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index a9f4488f..270b2caf 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-10-02 Frank Ch. Eigler <fche@redhat.com>
+
+ PR 5078
+ * semok/twentysix.stp, systemtap.base/beginenderror.*: New tests.
+
2007-10-02 William Cohen <wcohen@redhat.com>
* systemtap.syscall/signal.c:
diff --git a/testsuite/semok/twentysix.stp b/testsuite/semok/twentysix.stp
new file mode 100644
index 00000000..b18a490d
--- /dev/null
+++ b/testsuite/semok/twentysix.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+probe begin,begin(10),end,end(10),error,error(10)
+{ println (pp()) }
diff --git a/testsuite/systemtap.base/beginenderror.exp b/testsuite/systemtap.base/beginenderror.exp
new file mode 100644
index 00000000..9ad596cb
--- /dev/null
+++ b/testsuite/systemtap.base/beginenderror.exp
@@ -0,0 +1,22 @@
+set test "beginenderror"
+
+if {![installtest_p]} {untested $test; return}
+
+spawn stap $srcdir/$subdir/beginenderror.stp
+set ok1 0
+set ok2 0
+set ko 0
+expect {
+ -re {^ERROR:[^\r\n]*\r\n} { incr ok1; exp_continue }
+ -re {^WARNING:[^\r\n]*\r\n} { incr ok1; exp_continue }
+ -re {^ok[^\r\n]*\r\n} { incr ok2; exp_continue }
+ -re {^ko[^\r\n]*\r\n} { incr ko; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+wait
+if {$ok1 == 4 && $ok2 == 3 && $ko == 0} then {
+ pass "$test ($ok1 $ok2 $ko)"
+} else {
+ fail "$test ($ok1 $ok2 $ko)"
+}
diff --git a/testsuite/systemtap.base/beginenderror.stp b/testsuite/systemtap.base/beginenderror.stp
new file mode 100644
index 00000000..8d0772cd
--- /dev/null
+++ b/testsuite/systemtap.base/beginenderror.stp
@@ -0,0 +1,5 @@
+probe begin { println ("ok ".pp()) println (1/0) println ("ko ".pp()) } # handler should unwind before seemenot message
+probe begin(10) { println ("ko ".pp()) } # this late begin probe shouldn't run, ERROR
+probe end, end(10) { println ("ko ".pp()) } # end probes won't be run due to ERROR state
+probe error, error(10) { println ("ok ".pp()) } # these handlers should be run
+probe error(20),error(30) { println (1/0) println ("ko ".pp()) } # likewise
diff --git a/translate.cxx b/translate.cxx
index 7ff2bae6..f2351b9f 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -1144,23 +1144,6 @@ c_unparser::emit_module_init ()
}
o->newline() << "#endif";
- for (unsigned i=0; i<g.size(); i++)
- {
- g[i]->emit_module_init (*session);
- // NB: this gives O(N**2) amount of code, but luckily there
- // are only seven or eight derived_probe_groups, so it's ok.
- o->newline() << "if (rc) {";
- o->newline(1) << "_stp_error (\"probe %s registration error (rc %d)\", probe_point, rc);";
- // NB: we need to be in the error state so timers can shutdown cleanly,
- // and so end probes don't run.
- o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);";
- if (i>0)
- for (int j=i-1; j>=0; j--)
- g[j]->emit_module_exit (*session);
- o->newline() << "goto out;";
- o->newline(-1) << "}";
- }
-
// Print a message to the kernel log about this module. This is
// intended to help debug problems with systemtap modules.
o->newline() << "printk (KERN_DEBUG \"%s: "
@@ -1179,9 +1162,30 @@ c_unparser::emit_module_init ()
<< ", (unsigned long) _stp_allocated_memory"
<< ");";
+ // Run all probe registrations. This actually runs begin probes.
+
+ for (unsigned i=0; i<g.size(); i++)
+ {
+ g[i]->emit_module_init (*session);
+ // NB: this gives O(N**2) amount of code, but luckily there
+ // are only seven or eight derived_probe_groups, so it's ok.
+ o->newline() << "if (rc) {";
+ o->newline(1) << "_stp_error (\"probe %s registration error (rc %d)\", probe_point, rc);";
+ // NB: we need to be in the error state so timers can shutdown cleanly,
+ // and so end probes don't run. OTOH, error probes can run.
+ o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);";
+ if (i>0)
+ for (int j=i-1; j>=0; j--)
+ g[j]->emit_module_exit (*session);
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
+ }
+
// All registrations were successful. Consider the system started.
- o->newline() << "atomic_set (&session_state, STAP_SESSION_RUNNING);";
- o->newline() << "return 0;";
+ o->newline() << "if (atomic_read (&session_state) == STAP_SESSION_STARTING)";
+ // NB: only other valid state value is ERROR, in which case we don't
+ o->newline(1) << "atomic_set (&session_state, STAP_SESSION_RUNNING);";
+ o->newline(-1) << "return 0;";
// Error handling path; by now all partially registered probe groups
// have been unregistered.
@@ -1237,8 +1241,7 @@ c_unparser::emit_module_exit ()
o->newline(1) << "if (cpu_possible (i) && "
<< "atomic_read (& ((struct context *)per_cpu_ptr(contexts, i))->busy)) "
<< "holdon = 1;";
- o->newline () << "cpu_relax ();";
- // o->newline(-1) << "if (holdon) msleep (5);";
+ o->newline () << "schedule ();";
o->newline(-1) << "} while (holdon);";
o->newline(-1);
// XXX: might like to have an escape hatch, in case some probe is