X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=libust%2Fmarker.c;h=a497f0664b7a5125ad0ebf43425fdb7b8cebe5d8;hb=HEAD;hp=0149e6804af496adfb5177ac6d05a6ecbd8b0021;hpb=8161463975e218e0833d31ab1577a7ceb9e8e9f3;p=ust.git diff --git a/libust/marker.c b/libust/marker.c index 0149e68..a497f06 100644 --- a/libust/marker.c +++ b/libust/marker.c @@ -19,12 +19,15 @@ #define _LGPL_SOURCE #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -33,42 +36,51 @@ #include "tracercore.h" #include "tracer.h" -__thread long ust_reg_stack[500]; -volatile __thread long *ust_reg_stack_ptr = (long *) 0; - extern struct ust_marker * const __start___ust_marker_ptrs[] __attribute__((visibility("hidden"))); extern struct ust_marker * const __stop___ust_marker_ptrs[] __attribute__((visibility("hidden"))); /* Set to 1 to enable ust_marker debug output */ static const int ust_marker_debug; +static int initialized; +static void (*new_ust_marker_cb)(struct ust_marker *); /* - * ust_marker_mutex nests inside module_mutex. ust_marker mutex protects - * the builtin and module ust_marker and the hash table. + * ust_marker mutex protects the builtin and module ust_marker and the + * hash table, as well as the ust_marker_libs list. */ static DEFINE_MUTEX(ust_marker_mutex); - static CDS_LIST_HEAD(ust_marker_libs); +/* + * Allow nested mutex for mutex listing and nested enable. + */ +static __thread int nested_mutex; void lock_ust_marker(void) { - pthread_mutex_lock(&ust_marker_mutex); + if (!(nested_mutex++)) + pthread_mutex_lock(&ust_marker_mutex); } void unlock_ust_marker(void) { - pthread_mutex_unlock(&ust_marker_mutex); + if (!(--nested_mutex)) + pthread_mutex_unlock(&ust_marker_mutex); } /* * ust_marker hash table, containing the active ust_marker. - * Protected by module_mutex. + * Protected by ust_marker mutex. */ #define UST_MARKER_HASH_BITS 6 #define UST_MARKER_TABLE_SIZE (1 << UST_MARKER_HASH_BITS) static struct cds_hlist_head ust_marker_table[UST_MARKER_TABLE_SIZE]; +struct ust_marker_probe_array { + struct rcu_head rcu; + struct ust_marker_probe_closure c[0]; +}; + /* * Note about RCU : * It is used to make sure every handler has finished using its private @@ -84,11 +96,8 @@ struct ust_marker_entry { /* Probe wrapper */ void (*call)(const struct ust_marker *mdata, void *call_private, ...); struct ust_marker_probe_closure single; - struct ust_marker_probe_closure *multi; + struct ust_marker_probe_array *multi; int refcount; /* Number of times armed. 0 if disarmed. */ - struct rcu_head rcu; - void *oldptr; - int rcu_pending; u16 channel_id; u16 event_id; unsigned char ptype:1; @@ -96,14 +105,6 @@ struct ust_marker_entry { char channel[0]; /* Contains channel'\0'name'\0'format'\0' */ }; -#ifdef CONFIG_UST_MARKER_USERSPACE -static void ust_marker_update_processes(void); -#else -static void ust_marker_update_processes(void) -{ -} -#endif - /** * __ust_marker_empty_function - Empty probe callback * @mdata: ust_marker data @@ -122,7 +123,6 @@ notrace void __ust_marker_empty_function(const struct ust_marker *mdata, void *probe_private, void *call_private, const char *fmt, va_list *args) { } -//ust// EXPORT_SYMBOL_GPL(__ust_marker_empty_function); /* * ust_marker_probe_cb Callback that prepares the variable argument list for probes. @@ -145,7 +145,7 @@ notrace void ust_marker_probe_cb(const struct ust_marker *mdata, * sure the teardown of the callbacks can be done correctly when they * are in modules and they insure RCU read coherency. */ -//ust// rcu_read_lock_sched_notrace(); + rcu_read_lock(); ptype = mdata->ptype; if (likely(!ptype)) { ust_marker_probe_func *func; @@ -161,7 +161,7 @@ notrace void ust_marker_probe_cb(const struct ust_marker *mdata, mdata->format, &args); va_end(args); } else { - struct ust_marker_probe_closure *multi; + struct ust_marker_probe_array *multi; int i; /* * Read mdata->ptype before mdata->multi. @@ -176,16 +176,15 @@ notrace void ust_marker_probe_cb(const struct ust_marker *mdata, * in the fast path, so put the explicit cmm_barrier here. */ cmm_smp_read_barrier_depends(); - for (i = 0; multi[i].func; i++) { + for (i = 0; multi->c[i].func; i++) { va_start(args, call_private); - multi[i].func(mdata, multi[i].probe_private, + multi->c[i].func(mdata, multi->c[i].probe_private, call_private, mdata->format, &args); va_end(args); } } -//ust// rcu_read_unlock_sched_notrace(); + rcu_read_unlock(); } -//ust// EXPORT_SYMBOL_GPL(ust_marker_probe_cb); /* * ust_marker_probe_cb Callback that does not prepare the variable argument list. @@ -201,7 +200,7 @@ static notrace void ust_marker_probe_cb_noarg(const struct ust_marker *mdata, va_list args; /* not initialized */ char ptype; -//ust// rcu_read_lock_sched_notrace(); + rcu_read_lock(); ptype = mdata->ptype; if (likely(!ptype)) { ust_marker_probe_func *func; @@ -215,7 +214,7 @@ static notrace void ust_marker_probe_cb_noarg(const struct ust_marker *mdata, func(mdata, mdata->single.probe_private, call_private, mdata->format, &args); } else { - struct ust_marker_probe_closure *multi; + struct ust_marker_probe_array *multi; int i; /* * Read mdata->ptype before mdata->multi. @@ -230,21 +229,18 @@ static notrace void ust_marker_probe_cb_noarg(const struct ust_marker *mdata, * in the fast path, so put the explicit cmm_barrier here. */ cmm_smp_read_barrier_depends(); - for (i = 0; multi[i].func; i++) - multi[i].func(mdata, multi[i].probe_private, + for (i = 0; multi->c[i].func; i++) + multi->c[i].func(mdata, multi->c[i].probe_private, call_private, mdata->format, &args); } -//ust// rcu_read_unlock_sched_notrace(); + rcu_read_unlock(); } static void free_old_closure(struct rcu_head *head) { - struct ust_marker_entry *entry = _ust_container_of(head, - struct ust_marker_entry, rcu); - free(entry->oldptr); - /* Make sure we free the data before setting the pending flag to 0 */ - cmm_smp_wmb(); - entry->rcu_pending = 0; + struct ust_marker_probe_array *multi = + _ust_container_of(head, struct ust_marker_probe_array, rcu); + free(multi); } static void debug_print_probes(struct ust_marker_entry *entry) @@ -259,19 +255,19 @@ static void debug_print_probes(struct ust_marker_entry *entry) entry->single.func, entry->single.probe_private); } else { - for (i = 0; entry->multi[i].func; i++) + for (i = 0; entry->multi->c[i].func; i++) DBG("Multi probe %d : %p %p", i, - entry->multi[i].func, - entry->multi[i].probe_private); + entry->multi->c[i].func, + entry->multi->c[i].probe_private); } } -static struct ust_marker_probe_closure * +static struct ust_marker_probe_array * ust_marker_entry_add_probe(struct ust_marker_entry *entry, ust_marker_probe_func *probe, void *probe_private) { int nr_probes = 0; - struct ust_marker_probe_closure *old, *new; + struct ust_marker_probe_array *old, *new; WARN_ON(!probe); @@ -296,23 +292,24 @@ ust_marker_entry_add_probe(struct ust_marker_entry *entry, } } else { /* (N -> N+1), (N != 0, 1) probes */ - for (nr_probes = 0; old[nr_probes].func; nr_probes++) - if (old[nr_probes].func == probe - && old[nr_probes].probe_private + for (nr_probes = 0; old->c[nr_probes].func; nr_probes++) + if (old->c[nr_probes].func == probe + && old->c[nr_probes].probe_private == probe_private) return ERR_PTR(-EBUSY); } /* + 2 : one for new probe, one for NULL func */ - new = zmalloc((nr_probes + 2) * sizeof(struct ust_marker_probe_closure)); + new = zmalloc(sizeof(struct ust_marker_probe_array) + + ((nr_probes + 2) * sizeof(struct ust_marker_probe_closure))); if (new == NULL) return ERR_PTR(-ENOMEM); if (!old) - new[0] = entry->single; + new->c[0] = entry->single; else - memcpy(new, old, + memcpy(&new->c[0], &old->c[0], nr_probes * sizeof(struct ust_marker_probe_closure)); - new[nr_probes].func = probe; - new[nr_probes].probe_private = probe_private; + new->c[nr_probes].func = probe; + new->c[nr_probes].probe_private = probe_private; entry->refcount = nr_probes + 1; entry->multi = new; entry->ptype = 1; @@ -320,12 +317,12 @@ ust_marker_entry_add_probe(struct ust_marker_entry *entry, return old; } -static struct ust_marker_probe_closure * +static struct ust_marker_probe_array * ust_marker_entry_remove_probe(struct ust_marker_entry *entry, ust_marker_probe_func *probe, void *probe_private) { int nr_probes = 0, nr_del = 0, i; - struct ust_marker_probe_closure *old, *new; + struct ust_marker_probe_array *old, *new; old = entry->multi; @@ -343,9 +340,9 @@ ust_marker_entry_remove_probe(struct ust_marker_entry *entry, return NULL; } else { /* (N -> M), (N > 1, M >= 0) probes */ - for (nr_probes = 0; old[nr_probes].func; nr_probes++) { - if ((!probe || old[nr_probes].func == probe) - && old[nr_probes].probe_private + for (nr_probes = 0; old->c[nr_probes].func; nr_probes++) { + if ((!probe || old->c[nr_probes].func == probe) + && old->c[nr_probes].probe_private == probe_private) nr_del++; } @@ -358,23 +355,24 @@ ust_marker_entry_remove_probe(struct ust_marker_entry *entry, entry->ptype = 0; } else if (nr_probes - nr_del == 1) { /* N -> 1, (N > 1) */ - for (i = 0; old[i].func; i++) - if ((probe && old[i].func != probe) || - old[i].probe_private != probe_private) - entry->single = old[i]; + for (i = 0; old->c[i].func; i++) + if ((probe && old->c[i].func != probe) || + old->c[i].probe_private != probe_private) + entry->single = old->c[i]; entry->refcount = 1; entry->ptype = 0; } else { int j = 0; /* N -> M, (N > 1, M > 1) */ /* + 1 for NULL */ - new = zmalloc((nr_probes - nr_del + 1) * sizeof(struct ust_marker_probe_closure)); + new = zmalloc(sizeof(struct ust_marker_probe_array) + + ((nr_probes - nr_del + 1) * sizeof(struct ust_marker_probe_closure))); if (new == NULL) return ERR_PTR(-ENOMEM); - for (i = 0; old[i].func; i++) - if ((probe && old[i].func != probe) || - old[i].probe_private != probe_private) - new[j++] = old[i]; + for (i = 0; old->c[i].func; i++) + if ((probe && old->c[i].func != probe) || + old->c[i].probe_private != probe_private) + new->c[j++] = old->c[i]; entry->refcount = nr_probes - nr_del; entry->ptype = 1; entry->multi = new; @@ -462,7 +460,6 @@ static struct ust_marker_entry *add_ust_marker(const char *channel, const char * e->ptype = 0; e->format_allocated = 0; e->refcount = 0; - e->rcu_pending = 0; cds_hlist_add_head(&e->hlist, head); return e; } @@ -499,9 +496,6 @@ static int remove_ust_marker(const char *channel, const char *name) free(e->format); ret = ltt_channels_unregister(e->channel); WARN_ON(ret); - /* Make sure the call_rcu has been executed */ -//ust// if (e->rcu_pending) -//ust// rcu_cmm_barrier_sched(); free(e); return 0; } @@ -589,26 +583,17 @@ static int set_ust_marker(struct ust_marker_entry *entry, struct ust_marker *ele */ if (active) { - /* - * try_module_get should always succeed because we hold - * ust_marker_mutex to get the tp_cb address. - */ -//ust// ret = try_module_get(__module_text_address( -//ust// (unsigned long)elem->tp_cb)); -//ust// BUG_ON(!ret); ret = tracepoint_probe_register_noupdate( elem->tp_name, elem->tp_cb, NULL); } else { - ret = tracepoint_probe_unregister_noupdate( - elem->tp_name, - elem->tp_cb, NULL); /* * tracepoint_probe_update_all() must be called - * before the module containing tp_cb is unloaded. + * before the library containing tp_cb is unloaded. */ -//ust// module_put(__module_text_address( -//ust// (unsigned long)elem->tp_cb)); + ret = tracepoint_probe_unregister_noupdate( + elem->tp_name, + elem->tp_cb, NULL); } } elem->state = active; @@ -620,7 +605,7 @@ static int set_ust_marker(struct ust_marker_entry *entry, struct ust_marker *ele * Disable a ust_marker and its probe callback. * Note: only waiting an RCU period after setting elem->call to the empty * function insures that the original callback is not used anymore. This insured - * by rcu_read_lock_sched around the call site. + * by rcu_read_lock around the call site. */ static void disable_ust_marker(struct ust_marker *elem) { @@ -633,14 +618,13 @@ static void disable_ust_marker(struct ust_marker *elem) * It is ok to directly call the probe registration because type * checking has been done in the __ust_marker_tp() macro. */ - ret = tracepoint_probe_unregister_noupdate(elem->tp_name, - elem->tp_cb, NULL); - WARN_ON(ret); /* * tracepoint_probe_update_all() must be called * before the module containing tp_cb is unloaded. */ -//ust// module_put(__module_text_address((unsigned long)elem->tp_cb)); + ret = tracepoint_probe_unregister_noupdate(elem->tp_name, + elem->tp_cb, NULL); + WARN_ON(ret); } elem->state = 0; elem->single.func = __ust_marker_empty_function; @@ -665,9 +649,9 @@ int is_ust_marker_enabled(const char *channel, const char *name) { struct ust_marker_entry *entry; - pthread_mutex_lock(&ust_marker_mutex); + lock_ust_marker(); entry = get_ust_marker(channel, name); - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); return entry && !!entry->refcount; } @@ -679,13 +663,13 @@ int is_ust_marker_enabled(const char *channel, const char *name) * * Updates the probe callback corresponding to a range of ust_marker. */ +static void ust_marker_update_probe_range(struct ust_marker * const *begin, struct ust_marker * const *end) { struct ust_marker * const *iter; struct ust_marker_entry *mark_entry; - pthread_mutex_lock(&ust_marker_mutex); for (iter = begin; iter < end; iter++) { if (!*iter) continue; /* skip dummy */ @@ -699,19 +683,17 @@ void ust_marker_update_probe_range(struct ust_marker * const *begin, disable_ust_marker(*iter); } } - pthread_mutex_unlock(&ust_marker_mutex); } static void lib_update_ust_marker(void) { struct ust_marker_lib *lib; - /* FIXME: we should probably take a mutex here on libs */ -//ust// pthread_mutex_lock(&module_mutex); + lock_ust_marker(); cds_list_for_each_entry(lib, &ust_marker_libs, list) ust_marker_update_probe_range(lib->ust_marker_start, lib->ust_marker_start + lib->ust_marker_count); -//ust// pthread_mutex_unlock(&module_mutex); + unlock_ust_marker(); } /* @@ -735,7 +717,6 @@ static void ust_marker_update_probes(void) { lib_update_ust_marker(); tracepoint_probe_update_all(); - ust_marker_update_processes(); } /** @@ -756,10 +737,10 @@ int ust_marker_probe_register(const char *channel, const char *name, { struct ust_marker_entry *entry; int ret = 0, ret_err; - struct ust_marker_probe_closure *old; + struct ust_marker_probe_array *old; int first_probe = 0; - pthread_mutex_lock(&ust_marker_mutex); + lock_ust_marker(); entry = get_ust_marker(channel, name); if (!entry) { first_probe = 1; @@ -796,12 +777,6 @@ int ust_marker_probe_register(const char *channel, const char *name, goto end; } - /* - * If we detect that a call_rcu is pending for this ust_marker, - * make sure it's executed now. - */ -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); old = ust_marker_entry_add_probe(entry, probe, probe_private); if (IS_ERR(old)) { ret = PTR_ERR(old); @@ -810,24 +785,16 @@ int ust_marker_probe_register(const char *channel, const char *name, else goto end; } - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); /* Activate ust_marker if necessary */ ust_marker_update_probes(); - pthread_mutex_lock(&ust_marker_mutex); - entry = get_ust_marker(channel, name); - if (!entry) - goto end; -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); - entry->oldptr = old; - entry->rcu_pending = 1; - /* write rcu_pending before calling the RCU callback */ - cmm_smp_wmb(); -//ust// call_rcu_sched(&entry->rcu, free_old_closure); - synchronize_rcu(); free_old_closure(&entry->rcu); - goto end; + if (old) { + synchronize_rcu(); + free_old_closure(&old->rcu); + } + return ret; error_unregister_channel: ret_err = ltt_channels_unregister(channel); @@ -836,10 +803,9 @@ error_remove_ust_marker: ret_err = remove_ust_marker(channel, name); WARN_ON(ret_err); end: - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); return ret; } -//ust// EXPORT_SYMBOL_GPL(ust_marker_probe_register); /** * ust_marker_probe_unregister - Disconnect a probe from a ust_marker @@ -858,42 +824,34 @@ int ust_marker_probe_unregister(const char *channel, const char *name, ust_marker_probe_func *probe, void *probe_private) { struct ust_marker_entry *entry; - struct ust_marker_probe_closure *old; - int ret = -ENOENT; + struct ust_marker_probe_array *old; + int ret = 0; - pthread_mutex_lock(&ust_marker_mutex); + lock_ust_marker(); entry = get_ust_marker(channel, name); - if (!entry) + if (!entry) { + ret = -ENOENT; goto end; -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); + } old = ust_marker_entry_remove_probe(entry, probe, probe_private); - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); ust_marker_update_probes(); - pthread_mutex_lock(&ust_marker_mutex); - entry = get_ust_marker(channel, name); - if (!entry) - goto end; -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); - entry->oldptr = old; - entry->rcu_pending = 1; - /* write rcu_pending before calling the RCU callback */ - cmm_smp_wmb(); -//ust// call_rcu_sched(&entry->rcu, free_old_closure); - synchronize_rcu(); free_old_closure(&entry->rcu); - remove_ust_marker(channel, name); /* Ignore busy error message */ - ret = 0; + if (old) { + synchronize_rcu(); + free_old_closure(&old->rcu); + } + return ret; + end: - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); return ret; } -//ust// EXPORT_SYMBOL_GPL(ust_marker_probe_unregister); static struct ust_marker_entry * -get_ust_marker_from_private_data(ust_marker_probe_func *probe, void *probe_private) +get_ust_marker_from_private_data(ust_marker_probe_func *probe, + void *probe_private) { struct ust_marker_entry *entry; unsigned int i; @@ -909,11 +867,11 @@ get_ust_marker_from_private_data(ust_marker_probe_func *probe, void *probe_priva == probe_private) return entry; } else { - struct ust_marker_probe_closure *closure; + struct ust_marker_probe_array *closure; closure = entry->multi; - for (i = 0; closure[i].func; i++) { - if (closure[i].func == probe && - closure[i].probe_private + for (i = 0; closure->c[i].func; i++) { + if (closure->c[i].func == probe && + closure->c[i].probe_private == probe_private) return entry; } @@ -941,45 +899,37 @@ int ust_marker_probe_unregister_private_data(ust_marker_probe_func *probe, { struct ust_marker_entry *entry; int ret = 0; - struct ust_marker_probe_closure *old; + struct ust_marker_probe_array *old; char *channel = NULL, *name = NULL; - pthread_mutex_lock(&ust_marker_mutex); + lock_ust_marker(); entry = get_ust_marker_from_private_data(probe, probe_private); if (!entry) { ret = -ENOENT; - goto end; + goto unlock; } -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); old = ust_marker_entry_remove_probe(entry, NULL, probe_private); channel = strdup(entry->channel); name = strdup(entry->name); - pthread_mutex_unlock(&ust_marker_mutex); + /* Ignore busy error message */ + remove_ust_marker(channel, name); + unlock_ust_marker(); ust_marker_update_probes(); - pthread_mutex_lock(&ust_marker_mutex); - entry = get_ust_marker(channel, name); - if (!entry) - goto end; -//ust// if (entry->rcu_pending) -//ust// rcu_cmm_barrier_sched(); - entry->oldptr = old; - entry->rcu_pending = 1; - /* write rcu_pending before calling the RCU callback */ - cmm_smp_wmb(); -//ust// call_rcu_sched(&entry->rcu, free_old_closure); - synchronize_rcu(); free_old_closure(&entry->rcu); - /* Ignore busy error message */ - remove_ust_marker(channel, name); + if (old) { + synchronize_rcu(); + free_old_closure(&old->rcu); + } + goto end; + +unlock: + unlock_ust_marker(); end: - pthread_mutex_unlock(&ust_marker_mutex); free(channel); free(name); return ret; } -//ust// EXPORT_SYMBOL_GPL(ust_marker_probe_unregister_private_data); /** * ust_marker_get_private_data - Get a ust_marker's probe private data @@ -1014,14 +964,14 @@ void *ust_marker_get_private_data(const char *channel, const char *name, if (num == 0 && e->single.func == probe) return e->single.probe_private; } else { - struct ust_marker_probe_closure *closure; + struct ust_marker_probe_array *closure; int match = 0; closure = e->multi; - for (i = 0; closure[i].func; i++) { - if (closure[i].func != probe) + for (i = 0; closure->c[i].func; i++) { + if (closure->c[i].func != probe) continue; if (match++ == num) - return closure[i].probe_private; + return closure->c[i].probe_private; } } break; @@ -1029,48 +979,44 @@ void *ust_marker_get_private_data(const char *channel, const char *name, } return ERR_PTR(-ENOENT); } -//ust// EXPORT_SYMBOL_GPL(ust_marker_get_private_data); /** - * ust_marker_compact_event_ids - Compact ust_marker event IDs and reassign channels + * ust_marker_get_iter_range - Get a next ust_marker iterator given a range. + * @ust_marker: current ust_marker (in), next ust_marker (out) + * @begin: beginning of the range + * @end: end of the range * - * Called when no channel users are active by the channel infrastructure. - * Called with lock_ust_marker() and channel mutex held. + * Returns whether a next ust_marker has been found (1) or not (0). + * Will return the first ust_marker in the range if the input ust_marker is NULL. + * Called with markers mutex held. */ -//ust// void ust_marker_compact_event_ids(void) -//ust// { -//ust// struct ust_marker_entry *entry; -//ust// unsigned int i; -//ust// struct hlist_head *head; -//ust// struct hlist_node *node; -//ust// int ret; -//ust// -//ust// for (i = 0; i < UST_MARKER_TABLE_SIZE; i++) { -//ust// head = &ust_marker_table[i]; -//ust// hlist_for_each_entry(entry, node, head, hlist) { -//ust// ret = ltt_channels_get_index_from_name(entry->channel); -//ust// WARN_ON(ret < 0); -//ust// entry->channel_id = ret; -//ust// ret = _ltt_channels_get_event_id(entry->channel, -//ust// entry->name); -//ust// WARN_ON(ret < 0); -//ust// entry->event_id = ret; -//ust// } -//ust// } -//ust// } - -//ust//#ifdef CONFIG_MODULES +static +int ust_marker_get_iter_range(struct ust_marker * const **ust_marker, + struct ust_marker * const *begin, + struct ust_marker * const *end) +{ + if (!*ust_marker && begin != end) + *ust_marker = begin; + while (*ust_marker >= begin && *ust_marker < end) { + if (!**ust_marker) + (*ust_marker)++; /* skip dummy */ + else + return 1; + } + return 0; +} /* * Returns 0 if current not found. * Returns 1 if current found. + * Called with markers mutex held. */ +static int lib_get_iter_ust_marker(struct ust_marker_iter *iter) { struct ust_marker_lib *iter_lib; int found = 0; -//ust// pthread_mutex_lock(&module_mutex); cds_list_for_each_entry(iter_lib, &ust_marker_libs, list) { if (iter_lib < iter->lib) continue; @@ -1084,35 +1030,10 @@ int lib_get_iter_ust_marker(struct ust_marker_iter *iter) break; } } -//ust// pthread_mutex_unlock(&module_mutex); return found; } -/** - * ust_marker_get_iter_range - Get a next ust_marker iterator given a range. - * @ust_marker: current ust_marker (in), next ust_marker (out) - * @begin: beginning of the range - * @end: end of the range - * - * Returns whether a next ust_marker has been found (1) or not (0). - * Will return the first ust_marker in the range if the input ust_marker is NULL. - */ -int ust_marker_get_iter_range(struct ust_marker * const **ust_marker, - struct ust_marker * const *begin, - struct ust_marker * const *end) -{ - if (!*ust_marker && begin != end) - *ust_marker = begin; - while (*ust_marker >= begin && *ust_marker < end) { - if (!**ust_marker) - (*ust_marker)++; /* skip dummy */ - else - return 1; - } - return 0; -} -//ust// EXPORT_SYMBOL_GPL(ust_marker_get_iter_range); - +/* Called with markers mutex held. */ static void ust_marker_get_iter(struct ust_marker_iter *iter) { int found = 0; @@ -1124,10 +1045,11 @@ static void ust_marker_get_iter(struct ust_marker_iter *iter) void ust_marker_iter_start(struct ust_marker_iter *iter) { + lock_ust_marker(); ust_marker_get_iter(iter); } -//ust// EXPORT_SYMBOL_GPL(ust_marker_iter_start); +/* Called with markers mutex held. */ void ust_marker_iter_next(struct ust_marker_iter *iter) { iter->ust_marker++; @@ -1138,147 +1060,17 @@ void ust_marker_iter_next(struct ust_marker_iter *iter) */ ust_marker_get_iter(iter); } -//ust// EXPORT_SYMBOL_GPL(ust_marker_iter_next); void ust_marker_iter_stop(struct ust_marker_iter *iter) { + unlock_ust_marker(); } -//ust// EXPORT_SYMBOL_GPL(ust_marker_iter_stop); void ust_marker_iter_reset(struct ust_marker_iter *iter) { iter->lib = NULL; iter->ust_marker = NULL; } -//ust// EXPORT_SYMBOL_GPL(ust_marker_iter_reset); - -#ifdef CONFIG_UST_MARKER_USERSPACE -/* - * must be called with current->user_ust_marker_mutex held - */ -static void free_user_ust_marker(char __user *state, struct cds_hlist_head *head) -{ - struct user_ust_marker *umark; - struct cds_hlist_node *pos, *n; - - cds_hlist_for_each_entry_safe(umark, pos, n, head, hlist) { - if (umark->state == state) { - cds_hlist_del(&umark->hlist); - free(umark); - } - } -} - -/* - * Update current process. - * Note that we have to wait a whole scheduler period before we are sure that - * every running userspace threads have their ust_marker updated. - * (synchronize_sched() can be used to insure this). - */ -//ust// void ust_marker_update_process(void) -//ust// { -//ust// struct user_ust_marker *umark; -//ust// struct hlist_node *pos; -//ust// struct ust_marker_entry *entry; -//ust// -//ust// pthread_mutex_lock(&ust_marker_mutex); -//ust// pthread_mutex_lock(¤t->group_leader->user_ust_marker_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_ust_marker, hlist) { -//ust// DBG("Updating ust_marker %s in %s", umark->name, current->comm); -//ust// entry = get_ust_marker("userspace", umark->name); -//ust// if (entry) { -//ust// if (entry->format && -//ust// strcmp(entry->format, umark->format) != 0) { -//ust// WARN("error, wrong format in process %s", -//ust// current->comm); -//ust// break; -//ust// } -//ust// if (put_user(!!entry->refcount, umark->state)) { -//ust// WARN("ust_marker in %s caused a fault", -//ust// current->comm); -//ust// break; -//ust// } -//ust// } else { -//ust// if (put_user(0, umark->state)) { -//ust// WARN("ust_marker in %s caused a fault", current->comm); -//ust// break; -//ust// } -//ust// } -//ust// } -//ust// clear_thread_flag(TIF_UST_MARKER_PENDING); -//ust// pthread_mutex_unlock(¤t->group_leader->user_ust_marker_mutex); -//ust// pthread_mutex_unlock(&ust_marker_mutex); -//ust// } - -/* - * Called at process exit and upon do_execve(). - * We assume that when the leader exits, no more references can be done to the - * leader structure by the other threads. - */ -void exit_user_ust_marker(struct task_struct *p) -{ - struct user_ust_marker *umark; - struct cds_hlist_node *pos, *n; - - if (thread_group_leader(p)) { - pthread_mutex_lock(&ust_marker_mutex); - pthread_mutex_lock(&p->user_ust_marker_mutex); - cds_hlist_for_each_entry_safe(umark, pos, n, &p->user_ust_marker, - hlist) - free(umark); - INIT_HLIST_HEAD(&p->user_ust_marker); - p->user_ust_marker_sequence++; - pthread_mutex_unlock(&p->user_ust_marker_mutex); - pthread_mutex_unlock(&ust_marker_mutex); - } -} - -int is_ust_marker_enabled(const char *channel, const char *name) -{ - struct ust_marker_entry *entry; - - pthread_mutex_lock(&ust_marker_mutex); - entry = get_ust_marker(channel, name); - pthread_mutex_unlock(&ust_marker_mutex); - - return entry && !!entry->refcount; -} -//ust// #endif - -int ust_marker_module_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - struct module *mod = data; - - switch (val) { - case MODULE_STATE_COMING: - ust_marker_update_probe_range(mod->ust_marker, - mod->ust_marker + mod->num_ust_marker); - break; - case MODULE_STATE_GOING: - ust_marker_update_probe_range(mod->ust_marker, - mod->ust_marker + mod->num_ust_marker); - break; - } - return 0; -} - -struct notifier_block ust_marker_module_nb = { - .notifier_call = ust_marker_module_notify, - .priority = 0, -}; - -//ust// static int init_ust_marker(void) -//ust// { -//ust// return register_module_notifier(&ust_marker_module_nb); -//ust// } -//ust// __initcall(init_ust_marker); -/* TODO: call ust_marker_module_nb() when a library is linked at runtime (dlopen)? */ - -#endif /* CONFIG_MODULES */ void ltt_dump_ust_marker_state(struct ust_trace *trace) { @@ -1288,7 +1080,7 @@ void ltt_dump_ust_marker_state(struct ust_trace *trace) struct cds_hlist_node *node; unsigned int i; - pthread_mutex_lock(&ust_marker_mutex); + lock_ust_marker(); call_data.trace = trace; call_data.serializer = NULL; @@ -1316,30 +1108,29 @@ void ltt_dump_ust_marker_state(struct ust_trace *trace) entry->format); } } - pthread_mutex_unlock(&ust_marker_mutex); + unlock_ust_marker(); } -//ust// EXPORT_SYMBOL_GPL(ltt_dump_ust_marker_state); - -static void (*new_ust_marker_cb)(struct ust_marker *) = NULL; void ust_marker_set_new_ust_marker_cb(void (*cb)(struct ust_marker *)) { new_ust_marker_cb = cb; } -static void new_ust_marker(struct ust_marker * const *start, struct ust_marker * const *end) +static void new_ust_marker(struct ust_marker * const *start, + struct ust_marker * const *end) { if (new_ust_marker_cb) { struct ust_marker * const *m; - for(m = start; m < end; m++) { + for (m = start; m < end; m++) { if (*m) new_ust_marker_cb(*m); } } } -int ust_marker_register_lib(struct ust_marker * const *ust_marker_start, int ust_marker_count) +int ust_marker_register_lib(struct ust_marker * const *ust_marker_start, + int ust_marker_count) { struct ust_marker_lib *pl, *iter; @@ -1348,7 +1139,6 @@ int ust_marker_register_lib(struct ust_marker * const *ust_marker_start, int ust pl->ust_marker_start = ust_marker_start; pl->ust_marker_count = ust_marker_count; - /* FIXME: maybe protect this with its own mutex? */ lock_ust_marker(); /* @@ -1369,7 +1159,7 @@ lib_added: new_ust_marker(ust_marker_start, ust_marker_start + ust_marker_count); - /* FIXME: update just the loaded lib */ + /* TODO: update just the loaded lib */ lib_update_ust_marker(); DBG("just registered a ust_marker section from %p and having %d ust_marker (minus dummy ust_marker)", ust_marker_start, ust_marker_count); @@ -1381,13 +1171,7 @@ int ust_marker_unregister_lib(struct ust_marker * const *ust_marker_start) { struct ust_marker_lib *lib; - /*FIXME: implement; but before implementing, ust_marker_register_lib must - have appropriate locking. */ - lock_ust_marker(); - - /* FIXME: we should probably take a mutex here on libs */ -//ust// pthread_mutex_lock(&module_mutex); cds_list_for_each_entry(lib, &ust_marker_libs, list) { if(lib->ust_marker_start == ust_marker_start) { struct ust_marker_lib *lib2free = lib; @@ -1396,17 +1180,15 @@ int ust_marker_unregister_lib(struct ust_marker * const *ust_marker_start) break; } } - unlock_ust_marker(); return 0; } -static int initialized = 0; - void __attribute__((constructor)) init_ust_marker(void) { if (!initialized) { + init_tracepoint(); ust_marker_register_lib(__start___ust_marker_ptrs, __stop___ust_marker_ptrs - __start___ust_marker_ptrs);