static int
-_stp_hrtimer_create(struct stap_hrtimer_probe *shp, void (*function)(sigval_t))
+_stp_hrtimer_start(struct stap_hrtimer_probe *shp)
{
- 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).
*
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;
+ return timer_settime(shp->timer_id, 0, &shp->its, NULL);
+}
+
+
+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;
+ return timer_create(CLOCK_MONOTONIC, &shp->sigev, &shp->timer_id);
}
static void _stp_hrtimer_cancel(struct stap_hrtimer_probe *shp)
+{
+ shp->its.it_value.tv_sec = 0;
+ shp->its.it_value.tv_nsec = 0;
+ timer_settime(shp->timer_id, 0, &shp->its, NULL);
+}
+
+static void _stp_hrtimer_delete(struct stap_hrtimer_probe *shp)
{
(void) timer_delete(shp->timer_id);
}
struct stap_hrtimer_probe {
struct hrtimer hrtimer;
- const struct stap_probe * const probe;
+ const struct stap_probe * probe;
int64_t intrv;
int64_t rnd;
+ unsigned enabled;
};
// The function signature changed in 2.6.21.
}
+static int
+_stp_hrtimer_start(struct stap_hrtimer_probe *stp)
+{
+ (void)hrtimer_start(&stp->hrtimer, _stp_hrtimer_get_interval(stp),
+ HRTIMER_MODE_REL);
+ return 0;
+}
+
static int
_stp_hrtimer_create(struct stap_hrtimer_probe *stp,
hrtimer_return_t (*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;
}
+// For kernel-mode, there is no difference between cancel/delete.
static void
_stp_hrtimer_cancel(struct stap_hrtimer_probe *stp)
hrtimer_cancel(&stp->hrtimer);
}
+static void
+_stp_hrtimer_delete(struct stap_hrtimer_probe *stp)
+{
+ _stp_hrtimer_cancel(stp);
+}
+
#else /* kernel version < 2.6.17 */
#error "not implemented"
// unprivileged users.
void emit_privilege_assertion (translator_output*) {}
void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
+ bool on_the_fly_supported () { return true; }
};
public:
void emit_module_decls (systemtap_session& s);
void emit_module_init (systemtap_session& s);
+ void emit_module_refresh (systemtap_session& s);
void emit_module_exit (systemtap_session& s);
};
{
if (probes.empty()) return;
- 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( 0) << "_stp_hrtimer_init();";
+ s.op->newline( 0) << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(+1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
+ s.op->newline( 0) << "probe_point = stp->probe->pp;";
// 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( 0) << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
+ s.op->newline( 0) << "if (rc) {";
+ s.op->newline(+1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
+ s.op->newline(+1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
+ s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+ s.op->newline( 0) << "stap_hrtimer_probes[j].enabled = 0;";
+ s.op->newline( 0) << "#endif";
+ s.op->newline(-1) << "}";
+ s.op->newline( 0) << "break;"; // don't attempt to register any more
+ s.op->newline(-1) << "}";
+
+ // If the probe condition is off, then don't bother starting the timer
+ s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+ s.op->newline( 0) << "if (!stp->probe->cond_enabled) {";
+ s.op->newline(+1) << "dbug_otf(\"not starting (hrtimer) pidx %zu\\n\", stp->probe->index);";
+ s.op->newline( 0) << "continue;";
+ s.op->newline(-1) << "}";
+ s.op->newline( 0) << "#endif";
+
+ // Start the timer (with rollback on failure)
+ s.op->newline( 0) << "rc = _stp_hrtimer_start(stp);";
+ s.op->newline( 0) << "if (rc) {";
+ s.op->newline(+1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
+ s.op->newline(+1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
+ s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+ s.op->newline( 0) << "stap_hrtimer_probes[j].enabled = 0;";
+ s.op->newline( 0) << "#endif";
+ s.op->newline(-1) << "}";
+ s.op->newline( 0) << "break;"; // don't attempt to register any more
+ s.op->newline(-1) << "}";
+
+ // Mark as enabled since we successfully started the timer
+ s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+ s.op->newline( 0) << "stp->enabled = 1;";
+ s.op->newline( 0) << "#endif";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+void
+hrtimer_derived_probe_group::emit_module_refresh (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ // Check if we need to enable/disable any timers
+ s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+
+ s.op->newline( 0) << "for (i=0; i <" << probes.size() << "; i++) {";
+ s.op->newline(+1) << "struct stap_hrtimer_probe* stp = &stap_hrtimer_probes[i];";
+ // timer disabled, but condition says enabled?
+ s.op->newline( 0) << "if (!stp->enabled && stp->probe->cond_enabled) {";
+ s.op->newline(+1) << "dbug_otf(\"enabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
+ s.op->newline( 0) << "_stp_hrtimer_start(stp);";
+ // timer enabled, but condition says disabled?
+ s.op->newline(-1) << "} else if (stp->enabled && !stp->probe->cond_enabled) {";
+ s.op->newline(+1) << "dbug_otf(\"disabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
+ s.op->newline( 0) << "_stp_hrtimer_cancel(stp);";
+ s.op->newline(-1) << "}";
+ s.op->newline( 0) << "stp->enabled = stp->probe->cond_enabled;";
s.op->newline(-1) << "}";
- s.op->newline(-1) << "}"; // for loop
+
+ s.op->newline( 0) << "#endif";
}
s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
s.op->indent(1);
- s.op->newline() << "_stp_hrtimer_cancel(& stap_hrtimer_probes[i]);";
+ s.op->newline() << "_stp_hrtimer_delete(& stap_hrtimer_probes[i]);";
s.op->indent(-1);
}