X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=libust%2Fmarker.c;h=b1e457e7fbb9c05f12e6829bf4380afee3f9174e;hb=b73a4c471dc987ea8548632dffb3c7050de77dd0;hp=0a318ac038f9d3b07c977ce067875bc3bcbe85dc;hpb=769d015768372ce7f68ff12bbc55aa339c3a6bcd;p=ust.git diff --git a/libust/marker.c b/libust/marker.c index 0a318ac..b1e457e 100644 --- a/libust/marker.c +++ b/libust/marker.c @@ -1,19 +1,19 @@ /* * Copyright (C) 2007 Mathieu Desnoyers * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //ust// #include //ust// #include @@ -31,16 +31,19 @@ //ust// #include #define _LGPL_SOURCE -#include +#include -#include "kernelcompat.h" +#include -#include "marker.h" +#include #include "usterr.h" #include "channels.h" #include "tracercore.h" #include "tracer.h" +__thread long ust_reg_stack[500]; +volatile __thread long *ust_reg_stack_ptr = (long *) 0; + extern struct marker __start___markers[] __attribute__((visibility("hidden"))); extern struct marker __stop___markers[] __attribute__((visibility("hidden"))); @@ -53,6 +56,9 @@ static const int marker_debug; */ static DEFINE_MUTEX(markers_mutex); +static LIST_HEAD(libs); + + void lock_markers(void) { mutex_lock(&markers_mutex); @@ -84,7 +90,7 @@ struct marker_entry { char *format; char *name; /* Probe wrapper */ - void (*call)(const struct marker *mdata, void *call_private, ...); + void (*call)(const struct marker *mdata, void *call_private, struct registers *regs, ...); struct marker_probe_closure single; struct marker_probe_closure *multi; int refcount; /* Number of times armed. 0 if disarmed. */ @@ -120,7 +126,7 @@ static void marker_update_processes(void) * operations that modifies the execution flow of preemptible code. */ notrace void __mark_empty_function(const struct marker *mdata, - void *probe_private, void *call_private, const char *fmt, va_list *args) + void *probe_private, struct registers *regs, void *call_private, const char *fmt, va_list *args) { } //ust// EXPORT_SYMBOL_GPL(__mark_empty_function); @@ -136,7 +142,7 @@ notrace void __mark_empty_function(const struct marker *mdata, * rcu_dereference() for the pointer read. */ notrace void marker_probe_cb(const struct marker *mdata, - void *call_private, ...) + void *call_private, struct registers *regs, ...) { va_list args; char ptype; @@ -157,8 +163,8 @@ notrace void marker_probe_cb(const struct marker *mdata, /* Must read the ptr before private data. They are not data * dependant, so we put an explicit smp_rmb() here. */ smp_rmb(); - va_start(args, call_private); - func(mdata, mdata->single.probe_private, call_private, + va_start(args, regs); + func(mdata, mdata->single.probe_private, regs, call_private, mdata->format, &args); va_end(args); } else { @@ -178,9 +184,9 @@ notrace void marker_probe_cb(const struct marker *mdata, */ smp_read_barrier_depends(); for (i = 0; multi[i].func; i++) { - va_start(args, call_private); + va_start(args, regs); multi[i].func(mdata, multi[i].probe_private, - call_private, mdata->format, &args); + regs, call_private, mdata->format, &args); va_end(args); } } @@ -197,7 +203,7 @@ notrace void marker_probe_cb(const struct marker *mdata, * Should be connected to markers "MARK_NOARGS". */ static notrace void marker_probe_cb_noarg(const struct marker *mdata, - void *call_private, ...) + void *call_private, struct registers *regs, ...) { va_list args; /* not initialized */ char ptype; @@ -213,7 +219,7 @@ static notrace void marker_probe_cb_noarg(const struct marker *mdata, /* Must read the ptr before private data. They are not data * dependant, so we put an explicit smp_rmb() here. */ smp_rmb(); - func(mdata, mdata->single.probe_private, call_private, + func(mdata, mdata->single.probe_private, regs, call_private, mdata->format, &args); } else { struct marker_probe_closure *multi; @@ -232,7 +238,7 @@ static notrace void marker_probe_cb_noarg(const struct marker *mdata, */ smp_read_barrier_depends(); for (i = 0; multi[i].func; i++) - multi[i].func(mdata, multi[i].probe_private, + multi[i].func(mdata, multi[i].probe_private, regs, call_private, mdata->format, &args); } //ust// rcu_read_unlock_sched_notrace(); @@ -256,12 +262,12 @@ static void debug_print_probes(struct marker_entry *entry) return; if (!entry->ptype) { - printk(KERN_DEBUG "Single probe : %p %p\n", + DBG("Single probe : %p %p", entry->single.func, entry->single.probe_private); } else { for (i = 0; entry->multi[i].func; i++) - printk(KERN_DEBUG "Multi probe %d : %p %p\n", i, + DBG("Multi probe %d : %p %p", i, entry->multi[i].func, entry->multi[i].probe_private); } @@ -430,8 +436,7 @@ static struct marker_entry *add_marker(const char *channel, const char *name, head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(channel, e->channel) && !strcmp(name, e->name)) { - printk(KERN_NOTICE - "Marker %s.%s busy\n", channel, name); + DBG("Marker %s.%s busy", channel, name); return ERR_PTR(-EBUSY); /* Already there */ } } @@ -538,9 +543,7 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, if (entry->format) { if (strcmp(entry->format, elem->format) != 0) { - printk(KERN_NOTICE - "Format mismatch for probe %s " - "(%s), marker (%s)\n", + DBG("Format mismatch for probe %s (%s), marker (%s)", entry->name, entry->format, elem->format); @@ -631,9 +634,9 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, */ static void disable_marker(struct marker *elem) { - int ret; - - /* leave "call" as is. It is known statically. */ +//ust// int ret; +//ust// +//ust// /* leave "call" as is. It is known statically. */ //ust// if (elem->tp_name && _imv_read(elem->state)) { //ust// WARN_ON(!elem->tp_cb); //ust// /* @@ -661,6 +664,24 @@ static void disable_marker(struct marker *elem) */ } +/* + * is_marker_enabled - Check if a marker is enabled + * @channel: channel name + * @name: marker name + * + * Returns 1 if the marker is enabled, 0 if disabled. + */ +int is_marker_enabled(const char *channel, const char *name) +{ + struct marker_entry *entry; + + mutex_lock(&markers_mutex); + entry = get_marker(channel, name); + mutex_unlock(&markers_mutex); + + return entry && !!entry->refcount; +} + /** * marker_update_probe_range - Update a probe range * @begin: beginning of the range @@ -703,6 +724,18 @@ void marker_update_probe_range(struct marker *begin, mutex_unlock(&markers_mutex); } +static void lib_update_markers(void) +{ + struct lib *lib; + + /* FIXME: we should probably take a mutex here on libs */ +//ust// mutex_lock(&module_mutex); + list_for_each_entry(lib, &libs, list) + marker_update_probe_range(lib->markers_start, + lib->markers_start + lib->markers_count); +//ust// mutex_unlock(&module_mutex); +} + /* * Update probes, removing the faulty probes. * @@ -808,6 +841,7 @@ int marker_probe_register(const char *channel, const char *name, } mutex_unlock(&markers_mutex); + /* Activate marker if necessary */ marker_update_probes(); mutex_lock(&markers_mutex); @@ -1056,6 +1090,33 @@ void *marker_get_private_data(const char *channel, const char *name, //ust//#ifdef CONFIG_MODULES +/* + * Returns 0 if current not found. + * Returns 1 if current found. + */ +int lib_get_iter_markers(struct marker_iter *iter) +{ + struct lib *iter_lib; + int found = 0; + +//ust// mutex_lock(&module_mutex); + list_for_each_entry(iter_lib, &libs, list) { + if (iter_lib < iter->lib) + continue; + else if (iter_lib > iter->lib) + iter->marker = NULL; + found = marker_get_iter_range(&iter->marker, + iter_lib->markers_start, + iter_lib->markers_start + iter_lib->markers_count); + if (found) { + iter->lib = iter_lib; + break; + } + } +//ust// mutex_unlock(&module_mutex); + return found; +} + /** * marker_get_iter_range - Get a next marker iterator given a range. * @marker: current markers (in), next marker (out) @@ -1144,191 +1205,50 @@ static void free_user_marker(char __user *state, struct hlist_head *head) } } -//ust// asmlinkage long sys_marker(char __user *name, char __user *format, -//ust// char __user *state, int reg) +/* + * Update current process. + * Note that we have to wait a whole scheduler period before we are sure that + * every running userspace threads have their markers updated. + * (synchronize_sched() can be used to insure this). + */ +//ust// void marker_update_process(void) //ust// { //ust// struct user_marker *umark; -//ust// long len; +//ust// struct hlist_node *pos; //ust// struct marker_entry *entry; -//ust// int ret = 0; //ust// -//ust// printk(KERN_DEBUG "Program %s %s marker [%p, %p]\n", -//ust// current->comm, reg ? "registers" : "unregisters", -//ust// name, state); -//ust// if (reg) { -//ust// umark = kmalloc(sizeof(struct user_marker), GFP_KERNEL); -//ust// umark->name[MAX_USER_MARKER_NAME_LEN - 1] = '\0'; -//ust// umark->format[MAX_USER_MARKER_FORMAT_LEN - 1] = '\0'; -//ust// umark->state = state; -//ust// len = strncpy_from_user(umark->name, name, -//ust// MAX_USER_MARKER_NAME_LEN - 1); -//ust// if (len < 0) { -//ust// ret = -EFAULT; -//ust// goto error; -//ust// } -//ust// len = strncpy_from_user(umark->format, format, -//ust// MAX_USER_MARKER_FORMAT_LEN - 1); -//ust// if (len < 0) { -//ust// ret = -EFAULT; -//ust// goto error; -//ust// } -//ust// printk(KERN_DEBUG "Marker name : %s, format : %s", umark->name, -//ust// umark->format); -//ust// mutex_lock(&markers_mutex); +//ust// mutex_lock(&markers_mutex); +//ust// mutex_lock(¤t->group_leader->user_markers_mutex); +//ust// if (strcmp(current->comm, "testprog") == 0) +//ust// DBG("do update pending for testprog"); +//ust// hlist_for_each_entry(umark, pos, +//ust// ¤t->group_leader->user_markers, hlist) { +//ust// DBG("Updating marker %s in %s", umark->name, current->comm); //ust// entry = get_marker("userspace", umark->name); //ust// if (entry) { //ust// if (entry->format && //ust// strcmp(entry->format, umark->format) != 0) { -//ust// printk(" error, wrong format in process %s", +//ust// WARN("error, wrong format in process %s", //ust// current->comm); -//ust// ret = -EPERM; -//ust// goto error_unlock; +//ust// break; //ust// } -//ust// printk(" %s", !!entry->refcount -//ust// ? "enabled" : "disabled"); -//ust// if (put_user(!!entry->refcount, state)) { -//ust// ret = -EFAULT; -//ust// goto error_unlock; +//ust// if (put_user(!!entry->refcount, umark->state)) { +//ust// WARN("Marker in %s caused a fault", +//ust// current->comm); +//ust// break; //ust// } -//ust// printk("\n"); //ust// } else { -//ust// printk(" disabled\n"); //ust// if (put_user(0, umark->state)) { -//ust// printk(KERN_WARNING -//ust// "Marker in %s caused a fault\n", -//ust// current->comm); -//ust// goto error_unlock; +//ust// WARN("Marker in %s caused a fault", current->comm); +//ust// break; //ust// } //ust// } -//ust// mutex_lock(¤t->group_leader->user_markers_mutex); -//ust// hlist_add_head(&umark->hlist, -//ust// ¤t->group_leader->user_markers); -//ust// current->group_leader->user_markers_sequence++; -//ust// mutex_unlock(¤t->group_leader->user_markers_mutex); -//ust// mutex_unlock(&markers_mutex); -//ust// } else { -//ust// mutex_lock(¤t->group_leader->user_markers_mutex); -//ust// free_user_marker(state, -//ust// ¤t->group_leader->user_markers); -//ust// current->group_leader->user_markers_sequence++; -//ust// mutex_unlock(¤t->group_leader->user_markers_mutex); //ust// } -//ust// goto end; -//ust// error_unlock: -//ust// mutex_unlock(&markers_mutex); -//ust// error: -//ust// kfree(umark); -//ust// end: -//ust// return ret; -//ust// } -//ust// -//ust// /* -//ust// * Types : -//ust// * string : 0 -//ust// */ -//ust// asmlinkage long sys_trace(int type, uint16_t id, -//ust// char __user *ubuf) -//ust// { -//ust// long ret = -EPERM; -//ust// char *page; -//ust// int len; -//ust// -//ust// switch (type) { -//ust// case 0: /* String */ -//ust// ret = -ENOMEM; -//ust// page = (char *)__get_free_page(GFP_TEMPORARY); -//ust// if (!page) -//ust// goto string_out; -//ust// len = strncpy_from_user(page, ubuf, PAGE_SIZE); -//ust// if (len < 0) { -//ust// ret = -EFAULT; -//ust// goto string_err; -//ust// } -//ust// trace_mark(userspace, string, "string %s", page); -//ust// string_err: -//ust// free_page((unsigned long) page); -//ust// string_out: -//ust// break; -//ust// default: -//ust// break; -//ust// } -//ust// return ret; -//ust// } - -//ust// static void marker_update_processes(void) -//ust// { -//ust// struct task_struct *g, *t; -//ust// -//ust// /* -//ust// * markers_mutex is taken to protect the p->user_markers read. -//ust// */ -//ust// mutex_lock(&markers_mutex); -//ust// read_lock(&tasklist_lock); -//ust// for_each_process(g) { -//ust// WARN_ON(!thread_group_leader(g)); -//ust// if (hlist_empty(&g->user_markers)) -//ust// continue; -//ust// if (strcmp(g->comm, "testprog") == 0) -//ust// printk(KERN_DEBUG "set update pending for testprog\n"); -//ust// t = g; -//ust// do { -//ust// /* TODO : implement this thread flag in each arch. */ -//ust// set_tsk_thread_flag(t, TIF_MARKER_PENDING); -//ust// } while ((t = next_thread(t)) != g); -//ust// } -//ust// read_unlock(&tasklist_lock); +//ust// clear_thread_flag(TIF_MARKER_PENDING); +//ust// mutex_unlock(¤t->group_leader->user_markers_mutex); //ust// mutex_unlock(&markers_mutex); //ust// } -/* - * Update current process. - * Note that we have to wait a whole scheduler period before we are sure that - * every running userspace threads have their markers updated. - * (synchronize_sched() can be used to insure this). - */ -void marker_update_process(void) -{ - struct user_marker *umark; - struct hlist_node *pos; - struct marker_entry *entry; - - mutex_lock(&markers_mutex); - mutex_lock(¤t->group_leader->user_markers_mutex); - if (strcmp(current->comm, "testprog") == 0) - printk(KERN_DEBUG "do update pending for testprog\n"); - hlist_for_each_entry(umark, pos, - ¤t->group_leader->user_markers, hlist) { - printk(KERN_DEBUG "Updating marker %s in %s\n", - umark->name, current->comm); - entry = get_marker("userspace", umark->name); - if (entry) { - if (entry->format && - strcmp(entry->format, umark->format) != 0) { - printk(KERN_WARNING - " error, wrong format in process %s\n", - current->comm); - break; - } - if (put_user(!!entry->refcount, umark->state)) { - printk(KERN_WARNING - "Marker in %s caused a fault\n", - current->comm); - break; - } - } else { - if (put_user(0, umark->state)) { - printk(KERN_WARNING - "Marker in %s caused a fault\n", - current->comm); - break; - } - } - } - clear_thread_flag(TIF_MARKER_PENDING); - mutex_unlock(¤t->group_leader->user_markers_mutex); - mutex_unlock(&markers_mutex); -} - /* * Called at process exit and upon do_execve(). * We assume that when the leader exits, no more references can be done to the @@ -1396,86 +1316,45 @@ struct notifier_block marker_module_nb = { #endif /* CONFIG_MODULES */ -void ltt_dump_marker_state(struct ltt_trace_struct *trace) +void ltt_dump_marker_state(struct ust_trace *trace) { - struct marker_iter iter; + struct marker_entry *entry; struct ltt_probe_private_data call_data; - const char *channel; + struct hlist_head *head; + struct hlist_node *node; + unsigned int i; + mutex_lock(&markers_mutex); call_data.trace = trace; call_data.serializer = NULL; - marker_iter_reset(&iter); - marker_iter_start(&iter); - for (; iter.marker != NULL; marker_iter_next(&iter)) { - if (!_imv_read(iter.marker->state)) - continue; - channel = ltt_channels_get_name_from_index( - iter.marker->channel_id); - __trace_mark(0, metadata, core_marker_id, - &call_data, - "channel %s name %s event_id %hu " - "int #1u%zu long #1u%zu pointer #1u%zu " - "size_t #1u%zu alignment #1u%u", - channel, - iter.marker->name, - iter.marker->event_id, - sizeof(int), sizeof(long), - sizeof(void *), sizeof(size_t), - ltt_get_alignment()); - if (iter.marker->format) - __trace_mark(0, metadata, - core_marker_format, + for (i = 0; i < MARKER_TABLE_SIZE; i++) { + head = &marker_table[i]; + hlist_for_each_entry(entry, node, head, hlist) { + __trace_mark(0, metadata, core_marker_id, &call_data, - "channel %s name %s format %s", - channel, - iter.marker->name, - iter.marker->format); - } - marker_iter_stop(&iter); -} -//ust// EXPORT_SYMBOL_GPL(ltt_dump_marker_state); - - -static LIST_HEAD(libs); - -/* - * Returns 0 if current not found. - * Returns 1 if current found. - */ -int lib_get_iter_markers(struct marker_iter *iter) -{ - struct lib *iter_lib; - int found = 0; - -//ust// mutex_lock(&module_mutex); - list_for_each_entry(iter_lib, &libs, list) { - if (iter_lib < iter->lib) - continue; - else if (iter_lib > iter->lib) - iter->marker = NULL; - found = marker_get_iter_range(&iter->marker, - iter_lib->markers_start, - iter_lib->markers_start + iter_lib->markers_count); - if (found) { - iter->lib = iter_lib; - break; + "channel %s name %s event_id %hu " + "int #1u%zu long #1u%zu pointer #1u%zu " + "size_t #1u%zu alignment #1u%u", + entry->channel, + entry->name, + entry->event_id, + sizeof(int), sizeof(long), + sizeof(void *), sizeof(size_t), + ltt_get_alignment()); + if (entry->format) + __trace_mark(0, metadata, + core_marker_format, + &call_data, + "channel %s name %s format %s", + entry->channel, + entry->name, + entry->format); } } -//ust// mutex_unlock(&module_mutex); - return found; -} - -void lib_update_markers(void) -{ - struct lib *lib; - -//ust// mutex_lock(&module_mutex); - list_for_each_entry(lib, &libs, list) - marker_update_probe_range(lib->markers_start, - lib->markers_start + lib->markers_count); -//ust// mutex_unlock(&module_mutex); + mutex_unlock(&markers_mutex); } +//ust// EXPORT_SYMBOL_GPL(ltt_dump_marker_state); static void (*new_marker_cb)(struct marker *) = NULL; @@ -1497,6 +1376,7 @@ static void new_markers(struct marker *start, struct marker *end) int marker_register_lib(struct marker *markers_start, int markers_count) { struct lib *pl; + struct marker_addr *addr; pl = (struct lib *) malloc(sizeof(struct lib)); @@ -1532,7 +1412,7 @@ void __attribute__((constructor)) init_markers(void) { if(!initialized) { marker_register_lib(__start___markers, (((long)__stop___markers)-((long)__start___markers))/sizeof(struct marker)); - printf("markers_start: %p, markers_stop: %p\n", __start___markers, __stop___markers); + //DBG("markers_start: %p, markers_stop: %p\n", __start___markers, __stop___markers); initialized = 1; } }