extern void dtrace_enable(void);
extern void dtrace_disable(void);
+extern ktime_t dtrace_gethrtime(void);
+extern ktime_t dtrace_getwalltime(void);
+
+typedef enum dtrace_vtime_state {
+ DTRACE_VTIME_INACTIVE = 0,
+ DTRACE_VTIME_ACTIVE
+} dtrace_vtime_state_t;
+
+extern dtrace_vtime_state_t dtrace_vtime_active;
+
+extern void dtrace_vtime_enable(void);
+extern void dtrace_vtime_disable(void);
+extern void dtrace_vtime_switch(struct task_struct *, struct task_struct *);
+
extern int dtrace_invop_add(uint8_t (*func)(struct pt_regs *));
extern void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *));
extern struct task_struct *register_pid_provider(pid_t);
extern void unregister_pid_provider(pid_t);
+extern void dtrace_task_reinit(struct task_struct *);
extern void dtrace_task_init(struct task_struct *);
extern void dtrace_task_fork(struct task_struct *, struct task_struct *);
extern void dtrace_task_cleanup(struct task_struct *);
}
/*---------------------------------------------------------------------------*\
-(* TIME QUERIES *)
+(* TIME SUPPORT FUNCTIONS *)
\*---------------------------------------------------------------------------*/
+dtrace_vtime_state_t dtrace_vtime_active = 0;
+
/*
* Return a high resolution timer value that is guaranteed to always increase.
*/
}
EXPORT_SYMBOL(dtrace_getwalltime);
+void dtrace_vtime_enable(void)
+{
+ dtrace_vtime_state_t old, new;
+
+ do {
+ old = dtrace_vtime_active;
+ if (old == DTRACE_VTIME_ACTIVE) {
+ pr_warn_once("DTrace virtual time already enabled");
+ return;
+ }
+
+ new = DTRACE_VTIME_ACTIVE;
+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old);
+}
+EXPORT_SYMBOL(dtrace_vtime_enable);
+
+void dtrace_vtime_disable(void)
+{
+ int old, new;
+
+ do {
+ old = dtrace_vtime_active;
+ if (old == DTRACE_VTIME_INACTIVE) {
+ pr_warn_once("DTrace virtual time already disabled");
+ return;
+ }
+
+ new = DTRACE_VTIME_INACTIVE;
+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old);
+}
+EXPORT_SYMBOL(dtrace_vtime_disable);
+
+void dtrace_vtime_switch(struct task_struct *prev, struct task_struct *next)
+{
+ ktime_t now = dtrace_gethrtime();
+
+ if (ktime_nz(prev->dtrace_start)) {
+ prev->dtrace_vtime = ktime_add(prev->dtrace_vtime,
+ ktime_sub(now,
+ prev->dtrace_start));
+ prev->dtrace_start = ktime_set(0, 0);
+ }
+
+ next->dtrace_start = now;
+}
+
/*---------------------------------------------------------------------------*\
(* STACK TRACES *)
\*---------------------------------------------------------------------------*/
int (*dtrace_tracepoint_hit)(fasttrap_machtp_t *, struct pt_regs *);
EXPORT_SYMBOL(dtrace_tracepoint_hit);
-void dtrace_task_init(struct task_struct *tsk)
+void dtrace_task_reinit(struct task_struct *tsk)
{
tsk->predcache = 0;
- tsk->dtrace_vtime = ktime_set(0, 0);
- tsk->dtrace_start = ktime_set(0, 0);
tsk->dtrace_stop = 0;
tsk->dtrace_sig = 0;
tsk->dtrace_tp_count = 0;
}
+void dtrace_task_init(struct task_struct *tsk)
+{
+ dtrace_task_reinit(tsk);
+
+ tsk->dtrace_vtime = ktime_set(0, 0);
+ tsk->dtrace_start = ktime_set(0, 0);
+}
+
void dtrace_task_fork(struct task_struct *tsk, struct task_struct *child)
{
if (likely(dtrace_helpers_fork == NULL))
#include <linux/binfmts.h>
#include <linux/context_tracking.h>
#include <linux/compiler.h>
+#include <linux/dtrace_os.h>
#include <asm/switch_to.h>
#include <asm/tlb.h>
rq->prev_mm = NULL;
+#ifdef CONFIG_DTRACE
+ if (dtrace_vtime_active)
+ dtrace_vtime_switch(prev, current);
+#endif
+
/*
* A task struct has one reference for the use as "current".
* If a task dies, then it sets TASK_DEAD in tsk->state and calls