--- /dev/null
+/* -*- linux-c -*-
+ * Dyninst Timer Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _STAPDYN_TIMER_C_
+#define _STAPDYN_TIMER_C_
+
+#include <signal.h>
+#include <time.h>
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC 1000000000L
+#endif
+
+struct stap_hrtimer_probe {
+ struct sigevent sigev;
+ timer_t timer_id;
+ struct itimerspec its;
+ struct stap_probe * const probe;
+ int64_t intrv;
+ int64_t rnd;
+};
+
+
+static void _stp_hrtimer_init(void)
+{
+ return;
+}
+
+
+static int
+_stp_hrtimer_create(struct stap_hrtimer_probe *shp, void (*function)(sigval_t))
+{
+ int rc;
+
+ /* Create the timer. */
+ shp->sigev.sigev_notify = SIGEV_THREAD;
+ shp->sigev.sigev_value.sival_ptr = shp;
+ shp->sigev.sigev_notify_function = function;
+ shp->sigev.sigev_notify_attributes = NULL;
+ rc = timer_create(CLOCK_MONOTONIC, &shp->sigev, &shp->timer_id);
+ if (rc) {
+ return rc;
+ }
+
+ /* Specify a timer with the correct initial value (possibly
+ * randomized a bit).
+ *
+ * If this isn't a randomized timer probe, go ahead and set
+ * up the repeating interval values.
+ *
+ * The probe's interval is in nanoseconds,
+ * but in a int64_t. So, break it down into seconds and
+ * (leftover) nanoseconds so it will fit in a 'struct
+ * timespec'.
+ */
+
+ if (shp->rnd == 0) {
+ shp->its.it_value.tv_sec = (shp->its.it_interval.tv_sec \
+ = shp->intrv / NSEC_PER_SEC);
+ shp->its.it_value.tv_nsec = (shp->its.it_interval.tv_nsec \
+ = shp->intrv % NSEC_PER_SEC);
+ }
+ else {
+ int64_t i = shp->intrv + _stp_random_u(shp->rnd);
+ shp->its.it_value.tv_sec = i / NSEC_PER_SEC;
+ shp->its.it_value.tv_nsec = i % NSEC_PER_SEC;
+ }
+ rc = timer_settime(shp->timer_id, 0, &shp->its, NULL);
+ return rc;
+}
+
+
+static void _stp_hrtimer_update(struct stap_hrtimer_probe *shp)
+{
+ int64_t i = shp->intrv;
+
+ /* The timer only needs updating if this is a randomized timer
+ * probe */
+ if (shp->rnd == 0)
+ return;
+
+ /* The probe's interval is in nanoseconds, but in a
+ * int64_t. So, break it down into seconds and (leftover)
+ * nanoseconds.
+ */
+ i += _stp_random_u(shp->rnd);
+ shp->its.it_value.tv_sec = i / NSEC_PER_SEC;
+ shp->its.it_value.tv_nsec = i % NSEC_PER_SEC;
+ timer_settime(shp->timer_id, 0, &shp->its, NULL);
+}
+
+
+static void _stp_hrtimer_cancel(struct stap_hrtimer_probe *shp)
+{
+ (void) timer_delete(shp->timer_id);
+}
+
+#endif /* _STAPDYN_TIMER_C_ */
--- /dev/null
+/* -*- linux-c -*-
+ * Dyninst Timer Functions
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _LINUX_TIMER_C_
+#define _LINUX_TIMER_C_
+
+// If we're on kernels >= 2.6.17, use hrtimers.
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+
+static unsigned long stap_hrtimer_resolution = 0;
+
+struct stap_hrtimer_probe {
+ struct hrtimer hrtimer;
+ struct stap_probe * const probe;
+ int64_t intrv;
+ int64_t rnd;
+};
+
+// autoconf: add get/set expires if missing (pre 2.6.28-rc1)
+#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES
+#define hrtimer_get_expires(timer) ((timer)->expires)
+#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))
+#endif
+
+// autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21
+#ifdef STAPCONF_HRTIMER_REL
+#define HRTIMER_MODE_REL HRTIMER_REL
+#endif
+
+
+static void _stp_hrtimer_init(void)
+{
+ struct timespec res;
+ hrtimer_get_res (CLOCK_MONOTONIC, &res);
+ stap_hrtimer_resolution = timespec_to_ns(&res);
+}
+
+
+static inline ktime_t _stp_hrtimer_get_interval(struct stap_hrtimer_probe *stp)
+{
+ unsigned long nsecs;
+ uint64_t i = stp->intrv;
+
+ if (stp->rnd != 0) {
+#if 1
+ // XXX: why not use stp_random_pm instead of this?
+ int64_t r;
+ get_random_bytes(&r, sizeof(r));
+
+ // ensure that r is positive
+ r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;
+ r = _stp_mod64(NULL, r, (2*stp->rnd+1));
+ r -= stp->rnd;
+ i += r;
+#else
+ i += _stp_random_pm(stp->rnd);
+#endif
+ }
+ if (unlikely(i < stap_hrtimer_resolution))
+ i = stap_hrtimer_resolution;
+ nsecs = do_div(i, NSEC_PER_SEC);
+ return ktime_set(i, nsecs);
+}
+
+
+static inline void _stp_hrtimer_update(struct stap_hrtimer_probe *stp)
+{
+ ktime_t time;
+
+ time = ktime_add(hrtimer_get_expires(&stp->hrtimer),
+ _stp_hrtimer_get_interval(stp));
+ hrtimer_set_expires(&stp->hrtimer, time);
+}
+
+
+static int
+_stp_hrtimer_create(struct stap_hrtimer_probe *stp,
+ enum hrtimer_restart (*function)(struct hrtimer *))
+{
+ hrtimer_init(&stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ stp->hrtimer.function = function;
+ (void)hrtimer_start(&stp->hrtimer, _stp_hrtimer_get_interval(stp),
+ HRTIMER_MODE_REL);
+ return 0;
+}
+
+
+static void
+_stp_hrtimer_cancel(struct stap_hrtimer_probe *stp)
+{
+ hrtimer_cancel(&stp->hrtimer);
+}
+
+#else /* kernel version < 2.6.17 */
+
+#error "not implemented"
+
+#endif /* kernel version < 2.6.17 */
+
+#endif /* _LINUX_TIMER_C_ */
struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
{
- void emit_interval (translator_output* o);
public:
void emit_module_decls (systemtap_session& s);
void emit_module_init (systemtap_session& s);
}
-void
-hrtimer_derived_probe_group::emit_interval (translator_output* o)
-{
- o->line() << "({";
- o->newline(1) << "unsigned long nsecs;";
- o->newline() << "uint64_t i = stp->intrv;";
- o->newline() << "if (stp->rnd != 0) {";
- // XXX: why not use stp_random_pm instead of this?
- o->newline(1) << "int64_t r;";
- o->newline() << "get_random_bytes(&r, sizeof(r));";
- // ensure that r is positive
- o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;";
- o->newline() << "r = _stp_mod64(NULL, r, (2*stp->rnd+1));";
- o->newline() << "r -= stp->rnd;";
- o->newline() << "i += r;";
- o->newline(-1) << "}";
- o->newline() << "if (unlikely(i < stap_hrtimer_resolution))";
- o->newline(1) << "i = stap_hrtimer_resolution;";
- o->indent(-1);
- o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);";
- o->newline() << "ktime_set(i, nsecs);";
- o->newline(-1) << "})";
-}
-
-
void
hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
{
if (probes.empty()) return;
s.op->newline() << "/* ---- hrtimer probes ---- */";
+ s.op->newline() << "#include \"timer.c\"";
+ s.op->newline() << "static struct stap_hrtimer_probe stap_hrtimer_probes [" << probes.size() << "] = {";
- s.op->newline() << "static unsigned long stap_hrtimer_resolution;"; // init later
- s.op->newline() << "static struct stap_hrtimer_probe {";
- s.op->newline(1) << "struct hrtimer hrtimer;";
- s.op->newline() << "struct stap_probe * const probe;";
- s.op->newline() << "int64_t intrv, rnd;";
- s.op->newline(-1) << "} stap_hrtimer_probes [" << probes.size() << "] = {";
s.op->indent(1);
for (unsigned i=0; i < probes.size(); i++)
{
s.op->newline(-1) << "};";
s.op->newline();
- // autoconf: add get/set expires if missing (pre 2.6.28-rc1)
- s.op->newline() << "#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES";
- s.op->newline() << "#define hrtimer_get_expires(timer) ((timer)->expires)";
- s.op->newline() << "#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))";
- s.op->newline() << "#endif";
-
- // autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "#define HRTIMER_MODE_REL HRTIMER_REL";
- s.op->newline() << "#endif";
-
- // The function signature changed in 2.6.21.
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "static int ";
- s.op->newline() << "#else";
- s.op->newline() << "static enum hrtimer_restart ";
- s.op->newline() << "#endif";
- s.op->newline() << "enter_hrtimer_probe (struct hrtimer *timer) {";
-
- s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
- s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
- s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
- s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
- // Compute next trigger time
- s.op->newline(1) << "hrtimer_set_expires(timer, ktime_add (hrtimer_get_expires(timer),";
- emit_interval (s.op);
- s.op->line() << "));";
- s.op->newline() << "rc = HRTIMER_RESTART;";
- s.op->newline(-1) << "}";
- s.op->newline() << "{";
- s.op->indent(1);
- common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
- "stp_probe_type_hrtimer");
- s.op->newline() << "(*stp->probe->ph) (c);";
- common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
- s.op->newline(-1) << "}";
- s.op->newline() << "return rc;";
- s.op->newline(-1) << "}";
+ if (!s.runtime_usermode_p())
+ {
+ // The function signature changed in 2.6.21.
+ s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
+ s.op->newline() << "static int ";
+ s.op->newline() << "#else";
+ s.op->newline() << "static enum hrtimer_restart ";
+ s.op->newline() << "#endif";
+ s.op->newline() << "_stp_hrtimer_notify_function (struct hrtimer *timer) {";
+
+ s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
+ s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
+
+ // Update the timer with the next trigger time
+ s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
+ s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
+ s.op->newline(1) << "_stp_hrtimer_update(stp);";
+ s.op->newline() << "rc = HRTIMER_RESTART;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "{";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
+ "stp_probe_type_hrtimer");
+ s.op->newline() << "(*stp->probe->ph) (c);";
+ common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
+ s.op->newline(-1) << "}";
+ s.op->newline() << "return rc;";
+ s.op->newline(-1) << "}";
+ }
+ else
+ {
+ s.op->newline() << "void _stp_hrtimer_notify_function (sigval_t value)";
+ s.op->newline(1) << "{";
+ s.op->newline() << "struct stap_hrtimer_probe *stp = value.sival_ptr;";
+
+ // Update the timer with the next trigger time
+ s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
+ s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
+ s.op->newline(1) << "_stp_hrtimer_update(stp);";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "{";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
+ "stp_probe_type_hrtimer");
+ s.op->newline() << "(*stp->probe->ph) (c);";
+ common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+ }
}
{
if (probes.empty()) return;
- s.op->newline() << "{";
- s.op->newline(1) << "struct timespec res;";
- s.op->newline() << "hrtimer_get_res (CLOCK_MONOTONIC, &res);";
- s.op->newline() << "stap_hrtimer_resolution = timespec_to_ns (&res);";
- s.op->newline(-1) << "}";
-
+ s.op->newline() << "_stp_hrtimer_init();";
s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
s.op->newline() << "probe_point = stp->probe->pp;";
- s.op->newline() << "hrtimer_init (& stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);";
- s.op->newline() << "stp->hrtimer.function = & enter_hrtimer_probe;";
- // There is no hrtimer field to identify *this* (i-th) probe handler
- // callback. So instead we'll deduce it at entry time.
- s.op->newline() << "(void) hrtimer_start (& stp->hrtimer, ";
- emit_interval (s.op);
- s.op->line() << ", HRTIMER_MODE_REL);";
- // Note: no partial failure rollback is needed: hrtimer_start only
- // "fails" if the timer was already active, which cannot be.
+
+ // Note: no partial failure rollback is needed for kernel hrtimer
+ // probes (hrtimer_start only "fails" if the timer was already
+ // active, which cannot be). But, stapdyn timer probes need a
+ // rollback, and it won't hurt the kernel hrtimers.
+ s.op->newline() << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
+ s.op->newline() << "if (rc) {";
+ s.op->indent(1);
+ s.op->newline() << "for (j=i-1; j>=0; j--)"; // partial rollback
+ s.op->newline(1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
+ s.op->newline(-1) << "break;"; // don't attempt to register any more
+ s.op->newline(-1) << "}";
s.op->newline(-1) << "}"; // for loop
}
if (probes.empty()) return;
s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "hrtimer_cancel (& stap_hrtimer_probes[i].hrtimer);";
+ s.op->indent(1);
+ s.op->newline() << "_stp_hrtimer_cancel(& stap_hrtimer_probes[i]);";
s.op->indent(-1);
}
if (has_null_param(parameters, "profile"))
{
+ if (sess.runtime_usermode_p())
+ throw semantic_error (_("profile timer probes not available with the dyninst runtime"));
+
sess.unwindsym_modules.insert ("kernel");
finished_results.push_back
(new profile_derived_probe(sess, base, location));
if (get_param(parameters, "jiffies", period))
{
+ if (sess.runtime_usermode_p())
+ throw semantic_error (_("jiffies timer probes not available with the dyninst runtime"));
+
// always use basic timers for jiffies
finished_results.push_back
(new timer_derived_probe(base, location, period, rand, false));
->bind_privilege(pr_all)
->bind(builder);
- // Not ok for unprivileged users, because register_timer_hook only allows a
- // single attached callback. No resource-sharing -> no unprivileged access.
- root->bind("profile")
- ->bind(builder);
+ // Not ok for unprivileged users, because register_timer_hook only
+ // allows a single attached callback. No resource-sharing -> no
+ // unprivileged access.
+ //
+ // Sigh, but for dyninst users, we want a semantic error that
+ // profile probes aren't supported (which will come from
+ // timer_builder::build()), not a privilege error. So, we'll fake
+ // it so that profile probes are allowed for all.
+ if (!s.runtime_usermode_p()) {
+ root->bind("profile")
+ ->bind(builder);
+ }
+ else {
+ root->bind("profile")
+ ->bind_privilege(pr_all)
+ ->bind(builder);
+ }
}
buildok/fortyfive.stp -
buildok/fortysix.stp -
buildok/fortytwo.stp -
+ buildok/fourteen-plus.stp -
+ buildok/fourteen.stp -
buildok/guru.stp -
+ buildok/histogram_operator_in.stp -
buildok/hwbkpt.stp -
buildok/inet_sock-embedded.stp -
buildok/ioblock-all-probes.stp -
buildok/ipmib-all-probes.stp -
buildok/ipmib-detailed.stp -
buildok/ipmib-embedded.stp -
+ buildok/iterate_histogram_buckets.stp -
buildok/kprocess-all-probes.stp -
buildok/kprocess-detailed.stp -
buildok/kprocess-embedded.stp -
buildok/pr10678.stp -
buildok/pr13284.stp -
buildok/pretty.stp -
+ buildok/print_histogram_entry.stp -
+ buildok/print_histograms.stp -
buildok/proc_mem-embedded.stp -
buildok/process_test.stp -
buildok/procfs01.stp -
buildok/scheduler-detailed.stp -
buildok/scheduler-embedded.stp -
buildok/scsi-all-probes.stp -
+ buildok/scsi-detailed.stp -
buildok/scsi-embedded.stp -
buildok/seven.stp -
buildok/seventeen.stp -
buildok/syscalls-arch-detailed.stp -
buildok/syscalls-detailed.stp -
buildok/syscalls2-detailed.stp -
+ buildok/systemtap_privilege.stp -
buildok/tcp-all-probes.stp -
buildok/tcp-detailed.stp -
buildok/tcp-embedded.stp -
# - buildok/context-embedded.stp
# - buildok/context-symbols-embedded.stp
# - buildok/context-unwind-embedded.stp
- # - buildok/fourteen-plus.stp - no timer probes
- # - buildok/fourteen.stp - no timer probes
# - buildok/gtod_init.stp - no gettimeofday
# - buildok/gtod_noinit.stp - ditto
- # - buildok/histogram_operator_in.stp - no timer probes
- # - buildok/indent.stp - missing 'execname'
- # - buildok/iterate_histogram_buckets.stp - no timer probes
# - buildok/per-process-syscall.stp - process.syscall
# probes implementable?
- # - buildok/print_histogram_entry.stp - no timer probes
- # - buildok/print_histograms.stp - no timer probes
- # - buildok/printf.stp
- # - buildok/stat_extract.stp - missing timer probes
# - buildok/string-embedded.stp
# - buildok/system-embedded.stp
# - buildok/task-embedded.stp - should these functions