+++ /dev/null
-/*
- * ltt/ltt-channels.c
- *
- * (C) Copyright 2008 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
- *
- * LTTng channel management.
- *
- * Author:
- * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#include <stdlib.h>
-#include <ust/marker.h>
-#include <ust/marker-internal.h>
-#include "channels.h"
-#include "usterr_signal_safe.h"
-
-/*
- * ltt_channel_mutex may be nested inside the LTT trace mutex.
- * ltt_channel_mutex mutex may be nested inside markers mutex.
- */
-static DEFINE_MUTEX(ltt_channel_mutex);
-static CDS_LIST_HEAD(ltt_channels);
-/*
- * Index of next channel in array. Makes sure that as long as a trace channel is
- * allocated, no array index will be re-used when a channel is freed and then
- * another channel is allocated. This index is cleared and the array indexeds
- * get reassigned when the index_urcu_ref goes back to 0, which indicates that no
- * more trace channels are allocated.
- */
-static unsigned int free_index;
-static struct urcu_ref index_urcu_ref; /* Keeps track of allocated trace channels */
-
-int ust_channels_overwrite_by_default = 0;
-int ust_channels_request_collection_by_default = 1;
-
-static struct ltt_channel_setting *lookup_channel(const char *name)
-{
- struct ltt_channel_setting *iter;
-
- cds_list_for_each_entry(iter, <t_channels, list)
- if (strcmp(name, iter->name) == 0)
- return iter;
- return NULL;
-}
-
-/*
- * Must be called when channel refcount falls to 0 _and_ also when the last
- * trace is freed. This function is responsible for compacting the channel and
- * event IDs when no users are active.
- *
- * Called with lock_markers() and channels mutex held.
- */
-static void release_channel_setting(struct urcu_ref *urcu_ref)
-{
- struct ltt_channel_setting *setting = _ust_container_of(urcu_ref,
- struct ltt_channel_setting, urcu_ref);
- struct ltt_channel_setting *iter;
-
- if (uatomic_read(&index_urcu_ref.refcount) == 0
- && uatomic_read(&setting->urcu_ref.refcount) == 0) {
- cds_list_del(&setting->list);
- free(setting);
-
- free_index = 0;
- cds_list_for_each_entry(iter, <t_channels, list) {
- iter->index = free_index++;
- iter->free_event_id = 0;
- }
- /* FIXME: why not run this? */
-//ust// markers_compact_event_ids();
- }
-}
-
-/*
- * Perform channel index compaction when the last trace channel is freed.
- *
- * Called with lock_markers() and channels mutex held.
- */
-static void release_trace_channel(struct urcu_ref *urcu_ref)
-{
- struct ltt_channel_setting *iter, *n;
-
- cds_list_for_each_entry_safe(iter, n, <t_channels, list)
- release_channel_setting(&iter->urcu_ref);
-}
-
-/**
- * ltt_channels_register - Register a trace channel.
- * @name: channel name
- *
- * Uses refcounting.
- */
-int ltt_channels_register(const char *name)
-{
- struct ltt_channel_setting *setting;
- int ret = 0;
-
- pthread_mutex_lock(<t_channel_mutex);
- setting = lookup_channel(name);
- if (setting) {
- if (uatomic_read(&setting->urcu_ref.refcount) == 0)
- goto init_urcu_ref;
- else {
- urcu_ref_get(&setting->urcu_ref);
- goto end;
- }
- }
- setting = zmalloc(sizeof(*setting));
- if (!setting) {
- ret = -ENOMEM;
- goto end;
- }
- cds_list_add(&setting->list, <t_channels);
- strncpy(setting->name, name, PATH_MAX-1);
- setting->index = free_index++;
-init_urcu_ref:
- urcu_ref_init(&setting->urcu_ref);
-end:
- pthread_mutex_unlock(<t_channel_mutex);
- return ret;
-}
-
-/**
- * ltt_channels_unregister - Unregister a trace channel.
- * @name: channel name
- *
- * Must be called with markers mutex held.
- */
-int ltt_channels_unregister(const char *name)
-{
- struct ltt_channel_setting *setting;
- int ret = 0;
-
- pthread_mutex_lock(<t_channel_mutex);
- setting = lookup_channel(name);
- if (!setting || uatomic_read(&setting->urcu_ref.refcount) == 0) {
- ret = -ENOENT;
- goto end;
- }
- urcu_ref_put(&setting->urcu_ref, release_channel_setting);
-end:
- pthread_mutex_unlock(<t_channel_mutex);
- return ret;
-}
-
-/**
- * ltt_channels_set_default - Set channel default behavior.
- * @name: default channel name
- * @subbuf_size: size of the subbuffers
- * @subbuf_cnt: number of subbuffers
- */
-int ltt_channels_set_default(const char *name,
- unsigned int subbuf_size,
- unsigned int subbuf_cnt)
-{
- struct ltt_channel_setting *setting;
- int ret = 0;
-
- pthread_mutex_lock(<t_channel_mutex);
- setting = lookup_channel(name);
- if (!setting || uatomic_read(&setting->urcu_ref.refcount) == 0) {
- ret = -ENOENT;
- goto end;
- }
- setting->subbuf_size = subbuf_size;
- setting->subbuf_cnt = subbuf_cnt;
-end:
- pthread_mutex_unlock(<t_channel_mutex);
- return ret;
-}
-
-/**
- * ltt_channels_get_name_from_index - get channel name from channel index
- * @index: channel index
- *
- * Allows to lookup the channel name given its index. Done to keep the name
- * information outside of each trace channel instance.
- */
-const char *ltt_channels_get_name_from_index(unsigned int index)
-{
- struct ltt_channel_setting *iter;
-
- cds_list_for_each_entry(iter, <t_channels, list)
- if (iter->index == index && uatomic_read(&iter->urcu_ref.refcount))
- return iter->name;
- return NULL;
-}
-
-static struct ltt_channel_setting *
-ltt_channels_get_setting_from_name(const char *name)
-{
- struct ltt_channel_setting *iter;
-
- cds_list_for_each_entry(iter, <t_channels, list)
- if (!strcmp(iter->name, name)
- && uatomic_read(&iter->urcu_ref.refcount))
- return iter;
- return NULL;
-}
-
-/**
- * ltt_channels_get_index_from_name - get channel index from channel name
- * @name: channel name
- *
- * Allows to lookup the channel index given its name. Done to keep the name
- * information outside of each trace channel instance.
- * Returns -1 if not found.
- */
-int ltt_channels_get_index_from_name(const char *name)
-{
- struct ltt_channel_setting *setting;
-
- setting = ltt_channels_get_setting_from_name(name);
- if (setting)
- return setting->index;
- else
- return -1;
-}
-
-/**
- * ltt_channels_trace_alloc - Allocate channel structures for a trace
- * @subbuf_size: subbuffer size. 0 uses default.
- * @subbuf_cnt: number of subbuffers per per-cpu buffers. 0 uses default.
- * @flags: Default channel flags
- *
- * Use the current channel list to allocate the channels for a trace.
- * Called with trace lock held. Does not perform the trace buffer allocation,
- * because we must let the user overwrite specific channel sizes.
- */
-struct ust_channel *ltt_channels_trace_alloc(unsigned int *nr_channels,
- int overwrite,
- int request_collection,
- int active)
-{
- struct ust_channel *channel = NULL;
- struct ltt_channel_setting *iter;
-
- pthread_mutex_lock(<t_channel_mutex);
- if (!free_index) {
- WARN("ltt_channels_trace_alloc: no free_index; are there any probes connected?");
- goto end;
- }
- if (!uatomic_read(&index_urcu_ref.refcount))
- urcu_ref_init(&index_urcu_ref);
- else
- urcu_ref_get(&index_urcu_ref);
- *nr_channels = free_index;
- channel = zmalloc(sizeof(struct ust_channel) * free_index);
- if (!channel) {
- WARN("ltt_channel_struct: channel null after alloc");
- goto end;
- }
- cds_list_for_each_entry(iter, <t_channels, list) {
- if (!uatomic_read(&iter->urcu_ref.refcount))
- continue;
- channel[iter->index].subbuf_size = iter->subbuf_size;
- channel[iter->index].subbuf_cnt = iter->subbuf_cnt;
- channel[iter->index].overwrite = overwrite;
- channel[iter->index].request_collection = request_collection;
- channel[iter->index].active = active;
- channel[iter->index].channel_name = iter->name;
- }
-end:
- pthread_mutex_unlock(<t_channel_mutex);
- return channel;
-}
-
-/**
- * ltt_channels_trace_free - Free one trace's channels
- * @channels: channels to free
- *
- * Called with trace lock held. The actual channel buffers must be freed before
- * this function is called.
- */
-void ltt_channels_trace_free(struct ust_channel *channels)
-{
- lock_ust_marker();
- pthread_mutex_lock(<t_channel_mutex);
- free(channels);
- urcu_ref_put(&index_urcu_ref, release_trace_channel);
- pthread_mutex_unlock(<t_channel_mutex);
- unlock_ust_marker();
-}
-
-/**
- * _ltt_channels_get_event_id - get next event ID for a marker
- * @channel: channel name
- * @name: event name
- *
- * Returns a unique event ID (for this channel) or < 0 on error.
- * Must be called with channels mutex held.
- */
-int _ltt_channels_get_event_id(const char *channel, const char *name)
-{
- struct ltt_channel_setting *setting;
- int ret;
-
- setting = ltt_channels_get_setting_from_name(channel);
- if (!setting) {
- ret = -ENOENT;
- goto end;
- }
- if (strcmp(channel, "metadata") == 0) {
- if (strcmp(name, "core_marker_id") == 0)
- ret = 0;
- else if (strcmp(name, "core_marker_format") == 0)
- ret = 1;
- else if (strcmp(name, "testev") == 0)
- ret = 2;
- else
- ret = -ENOENT;
- goto end;
- }
- if (setting->free_event_id == EVENTS_PER_CHANNEL - 1) {
- ret = -ENOSPC;
- goto end;
- }
- ret = setting->free_event_id++;
-end:
- return ret;
-}
-
-/**
- * ltt_channels_get_event_id - get next event ID for a marker
- * @channel: channel name
- * @name: event name
- *
- * Returns a unique event ID (for this channel) or < 0 on error.
- */
-int ltt_channels_get_event_id(const char *channel, const char *name)
-{
- int ret;
-
- pthread_mutex_lock(<t_channel_mutex);
- ret = _ltt_channels_get_event_id(channel, name);
- pthread_mutex_unlock(<t_channel_mutex);
- return ret;
-}
+++ /dev/null
-#ifndef UST_CHANNELS_H
-#define UST_CHANNELS_H
-
-/*
- * Copyright (C) 2008 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
- *
- * Dynamic tracer channel allocation.
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _LGPL_SOURCE
-#include <linux/limits.h>
-#include <errno.h>
-#include <ust/kcompat/kcompat.h>
-#include <ust/core.h>
-#include <urcu/list.h>
-#include <urcu/ref.h>
-
-#define EVENTS_PER_CHANNEL 65536
-#define MAX_CPUS 32
-
-struct ust_trace;
-
-struct ust_buffer;
-
-struct ust_channel {
- /* First 32 bytes cache-hot cacheline */
- struct ust_trace *trace;
- int *buf_struct_shmids;
- struct ust_buffer **buf;
- int overwrite:1;
- /* whether collection is requested upon trace start */
- int request_collection:1;
- int active:1;
- unsigned int n_subbufs_order;
- unsigned long commit_count_mask; /*
- * Commit count mask, removing
- * the MSBs corresponding to
- * bits used to represent the
- * subbuffer index.
- */
- /* End of first 32 bytes cacheline */
-
- struct urcu_ref urcu_ref; /* Channel transport reference count */
- size_t subbuf_size;
- int subbuf_size_order;
- unsigned int subbuf_cnt;
- const char *channel_name;
- int n_cpus;
-
- u32 version;
- size_t alloc_size;
- struct cds_list_head list;
-} ____cacheline_aligned;
-
-struct ltt_channel_setting {
- unsigned int subbuf_size;
- unsigned int subbuf_cnt;
- struct urcu_ref urcu_ref; /* Number of references to structure content */
- struct cds_list_head list;
- unsigned int index; /* index of channel in trace channel array */
- u16 free_event_id; /* Next event ID to allocate */
- char name[PATH_MAX];
-};
-
-extern int ltt_channels_register(const char *name);
-extern int ltt_channels_unregister(const char *name);
-extern int ltt_channels_set_default(const char *name,
- unsigned int subbuf_size,
- unsigned int subbuf_cnt);
-extern const char *ltt_channels_get_name_from_index(unsigned int index);
-extern int ltt_channels_get_index_from_name(const char *name);
-extern struct ust_channel *ltt_channels_trace_alloc(unsigned int *nr_channels,
- int overwrite,
- int request_collection,
- int active);
-extern void ltt_channels_trace_free(struct ust_channel *channels);
-extern int _ltt_channels_get_event_id(const char *channel, const char *name);
-extern int ltt_channels_get_event_id(const char *channel, const char *name);
-
-extern int ust_channels_overwrite_by_default;
-extern int ust_channels_request_collection_by_default;
-
-#endif /* UST_CHANNELS_H */
+++ /dev/null
-/*
- * Copyright (C) 2007 Mathieu Desnoyers
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- *
- */
-
-/* This file contains a high-level API for activating and deactivating ust_markers,
- * and making sure ust_markers in a given library can be released when the library
- * is unloaded.
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-
-#include "tracer.h"
-#include "usterr_signal_safe.h"
-
-#define DEFAULT_CHANNEL "cpu"
-#define DEFAULT_PROBE "default"
-
-static int initialized;
-
-CDS_LIST_HEAD(probes_list);
-
-/*
- * Mutex protecting the probe slab cache.
- * Nests inside the traces mutex.
- */
-DEFINE_MUTEX(probes_mutex);
-
-struct ltt_available_probe default_probe = {
- .name = "default",
- .format = NULL,
- .probe_func = ltt_vtrace,
- .callbacks[0] = ltt_serialize_data,
-};
-
-//ust//static struct kmem_cache *ust_markers_loaded_cachep;
-static CDS_LIST_HEAD(ust_markers_loaded_list);
-/*
- * List sorted by name strcmp order.
- */
-static CDS_LIST_HEAD(probes_registered_list);
-
-static struct ltt_available_probe *get_probe_from_name(const char *pname)
-{
- struct ltt_available_probe *iter;
- int comparison, found = 0;
-
- if (!pname)
- pname = DEFAULT_PROBE;
- cds_list_for_each_entry(iter, &probes_registered_list, node) {
- comparison = strcmp(pname, iter->name);
- if (!comparison)
- found = 1;
- if (comparison <= 0)
- break;
- }
- if (found)
- return iter;
- else
- return NULL;
-}
-
-/* (unused)
-static char *skip_spaces(char *buf)
-{
- while (*buf != '\0' && isspace(*buf))
- buf++;
- return buf;
-}
-
-static char *skip_nonspaces(char *buf)
-{
- while (*buf != '\0' && !isspace(*buf))
- buf++;
- return buf;
-}
-
-static void get_ust_marker_string(char *buf, char **start,
- char **end)
-{
- *start = skip_spaces(buf);
- *end = skip_nonspaces(*start);
- **end = '\0';
-}
-*/
-
-int ltt_probe_register(struct ltt_available_probe *pdata)
-{
- int ret = 0;
- int comparison;
- struct ltt_available_probe *iter;
-
- pthread_mutex_lock(&probes_mutex);
- cds_list_for_each_entry_reverse(iter, &probes_registered_list, node) {
- comparison = strcmp(pdata->name, iter->name);
- if (!comparison) {
- ret = -EBUSY;
- goto end;
- } else if (comparison > 0) {
- /* We belong to the location right after iter. */
- cds_list_add(&pdata->node, &iter->node);
- goto end;
- }
- }
- /* Should be added at the head of the list */
- cds_list_add(&pdata->node, &probes_registered_list);
-end:
- pthread_mutex_unlock(&probes_mutex);
- return ret;
-}
-
-/*
- * Called when a probe does not want to be called anymore.
- */
-int ltt_probe_unregister(struct ltt_available_probe *pdata)
-{
- int ret = 0;
- struct ltt_active_ust_marker *amark, *tmp;
-
- pthread_mutex_lock(&probes_mutex);
- cds_list_for_each_entry_safe(amark, tmp, &ust_markers_loaded_list, node) {
- if (amark->probe == pdata) {
- ret = ust_marker_probe_unregister_private_data(
- pdata->probe_func, amark);
- if (ret)
- goto end;
- cds_list_del(&amark->node);
- free(amark);
- }
- }
- cds_list_del(&pdata->node);
-end:
- pthread_mutex_unlock(&probes_mutex);
- return ret;
-}
-
-/*
- * Connect ust_marker "mname" to probe "pname".
- * Only allow _only_ probe instance to be connected to a ust_marker.
- */
-int ltt_ust_marker_connect(const char *channel, const char *mname,
- const char *pname)
-
-{
- int ret;
- struct ltt_active_ust_marker *pdata;
- struct ltt_available_probe *probe;
-
- ltt_lock_traces();
- pthread_mutex_lock(&probes_mutex);
- probe = get_probe_from_name(pname);
- if (!probe) {
- ret = -ENOENT;
- goto end;
- }
- pdata = ust_marker_get_private_data(channel, mname, probe->probe_func, 0);
- if (pdata && !IS_ERR(pdata)) {
- ret = -EEXIST;
- goto end;
- }
- pdata = zmalloc(sizeof(struct ltt_active_ust_marker));
- if (!pdata) {
- ret = -ENOMEM;
- goto end;
- }
- pdata->probe = probe;
- /*
- * ID has priority over channel in case of conflict.
- */
- ret = ust_marker_probe_register(channel, mname, NULL,
- probe->probe_func, pdata);
- if (ret)
- free(pdata);
- else
- cds_list_add(&pdata->node, &ust_markers_loaded_list);
-end:
- pthread_mutex_unlock(&probes_mutex);
- ltt_unlock_traces();
- return ret;
-}
-
-/*
- * Disconnect ust_marker "mname", probe "pname".
- */
-int ltt_ust_marker_disconnect(const char *channel, const char *mname,
- const char *pname)
-{
- struct ltt_active_ust_marker *pdata;
- struct ltt_available_probe *probe;
- int ret = 0;
-
- pthread_mutex_lock(&probes_mutex);
- probe = get_probe_from_name(pname);
- if (!probe) {
- ret = -ENOENT;
- goto end;
- }
- pdata = ust_marker_get_private_data(channel, mname, probe->probe_func, 0);
- if (IS_ERR(pdata)) {
- ret = PTR_ERR(pdata);
- goto end;
- } else if (!pdata) {
- /*
- * Not registered by us.
- */
- ret = -EPERM;
- goto end;
- }
- ret = ust_marker_probe_unregister(channel, mname, probe->probe_func, pdata);
- if (ret)
- goto end;
- else {
- cds_list_del(&pdata->node);
- free(pdata);
- }
-end:
- pthread_mutex_unlock(&probes_mutex);
- return ret;
-}
-
-static void disconnect_all_ust_markers(void)
-{
- struct ltt_active_ust_marker *pdata, *tmp;
-
- cds_list_for_each_entry_safe(pdata, tmp, &ust_markers_loaded_list, node) {
- ust_marker_probe_unregister_private_data(pdata->probe->probe_func,
- pdata);
- cds_list_del(&pdata->node);
- free(pdata);
- }
-}
-
-void __attribute__((constructor)) init_ust_marker_control(void)
-{
- if (!initialized) {
- int ret;
-
- init_ust_marker();
- ret = ltt_probe_register(&default_probe);
- BUG_ON(ret);
- ret = ltt_ust_marker_connect("metadata", "core_marker_format",
- DEFAULT_PROBE);
- BUG_ON(ret);
- ret = ltt_ust_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
- BUG_ON(ret);
- initialized = 1;
- }
-}
-
-static void __attribute__((destructor)) ust_marker_control_exit(void)
-{
- int ret;
-
- ret = ltt_ust_marker_disconnect("metadata", "core_marker_format",
- DEFAULT_PROBE);
- BUG_ON(ret);
- ret = ltt_ust_marker_disconnect("metadata", "core_marker_id",
- DEFAULT_PROBE);
- BUG_ON(ret);
- ret = ltt_probe_unregister(&default_probe);
- BUG_ON(ret);
- disconnect_all_ust_markers();
- ust_marker_synchronize_unregister();
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 - Pierre-Marc Fournier (pierre-marc dot fournier at polymtl dot ca)
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#ifndef MARKER_CONTROL_H
-#define MARKER_CONTROL_H
-
-int init_ust_marker_control(void);
-int ltt_probe_register(struct ltt_available_probe *pdata);
-
-#endif /* MARKER_CONTROL_H */
+++ /dev/null
-/*
- * Copyright (C) 2007-2011 Mathieu Desnoyers
- *
- * 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;
- * version 2.1 of the License.
- *
- * 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _LGPL_SOURCE
-#include <stdlib.h>
-#include <errno.h>
-#include <pthread.h>
-#include <urcu-call-rcu.h>
-#include <urcu-bp.h>
-#include <urcu/rculist.h>
-#include <urcu/hlist.h>
-
-#include <ust/core.h>
-#include <ust/marker.h>
-#include <ust/marker-internal.h>
-#include <ust/tracepoint.h>
-#include <ust/tracepoint-internal.h>
-
-#include "usterr_signal_safe.h"
-#include "channels.h"
-#include "tracercore.h"
-#include "tracer.h"
-
-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 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)
-{
- if (!(nested_mutex++))
- pthread_mutex_lock(&ust_marker_mutex);
-}
-
-void unlock_ust_marker(void)
-{
- if (!(--nested_mutex))
- pthread_mutex_unlock(&ust_marker_mutex);
-}
-
-/*
- * ust_marker hash table, containing the active ust_marker.
- * 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
- * data between two consecutive operation (add or remove) on a given
- * ust_marker. It is also used to delay the free of multiple probes
- * array until a quiescent state is reached. ust_marker entries
- * modifications are protected by the ust_marker_mutex.
- */
-struct ust_marker_entry {
- struct cds_hlist_node hlist;
- char *format;
- char *name;
- /* Probe wrapper */
- void (*call)(const struct ust_marker *mdata, void *call_private, ...);
- struct ust_marker_probe_closure single;
- struct ust_marker_probe_array *multi;
- int refcount; /* Number of times armed. 0 if disarmed. */
- u16 channel_id;
- u16 event_id;
- unsigned char ptype:1;
- unsigned char format_allocated:1;
- char channel[0]; /* Contains channel'\0'name'\0'format'\0' */
-};
-
-/**
- * __ust_marker_empty_function - Empty probe callback
- * @mdata: ust_marker data
- * @probe_private: probe private data
- * @call_private: call site private data
- * @fmt: format string
- * @...: variable argument list
- *
- * Empty callback provided as a probe to the ust_marker. By providing
- * this to a disabled ust_marker, we make sure the execution flow is
- * always valid even though the function pointer change and the
- * ust_marker enabling are two distinct operations that modifies the
- * execution flow of preemptible code.
- */
-notrace void __ust_marker_empty_function(const struct ust_marker *mdata,
- void *probe_private, void *call_private, const char *fmt, va_list *args)
-{
-}
-
-/*
- * ust_marker_probe_cb Callback that prepares the variable argument list for probes.
- * @mdata: pointer of type struct ust_marker
- * @call_private: caller site private data
- * @...: Variable argument list.
- *
- * Since we do not use "typical" pointer based RCU in the 1 argument case, we
- * need to put a full cmm_smp_rmb() in this branch. This is why we do not use
- * rcu_dereference() for the pointer read.
- */
-notrace void ust_marker_probe_cb(const struct ust_marker *mdata,
- void *call_private, ...)
-{
- va_list args;
- char ptype;
-
- /*
- * rcu_read_lock_sched does two things : disabling preemption to make
- * sure the teardown of the callbacks can be done correctly when they
- * are in modules and they insure RCU read coherency.
- */
- rcu_read_lock();
- ptype = mdata->ptype;
- if (likely(!ptype)) {
- ust_marker_probe_func *func;
- /* Must read the ptype before ptr. They are not data dependant,
- * so we put an explicit cmm_smp_rmb() here. */
- cmm_smp_rmb();
- func = mdata->single.func;
- /* Must read the ptr before private data. They are not data
- * dependant, so we put an explicit cmm_smp_rmb() here. */
- cmm_smp_rmb();
- va_start(args, call_private);
- func(mdata, mdata->single.probe_private, call_private,
- mdata->format, &args);
- va_end(args);
- } else {
- struct ust_marker_probe_array *multi;
- int i;
- /*
- * Read mdata->ptype before mdata->multi.
- */
- cmm_smp_rmb();
- multi = mdata->multi;
- /*
- * multi points to an array, therefore accessing the array
- * depends on reading multi. However, even in this case,
- * we must insure that the pointer is read _before_ the array
- * data. Same as rcu_dereference, but we need a full cmm_smp_rmb()
- * in the fast path, so put the explicit cmm_barrier here.
- */
- cmm_smp_read_barrier_depends();
- for (i = 0; multi->c[i].func; i++) {
- va_start(args, call_private);
- multi->c[i].func(mdata, multi->c[i].probe_private,
- call_private, mdata->format, &args);
- va_end(args);
- }
- }
- rcu_read_unlock();
-}
-
-/*
- * ust_marker_probe_cb Callback that does not prepare the variable argument list.
- * @mdata: pointer of type struct ust_marker
- * @call_private: caller site private data
- * @...: Variable argument list.
- *
- * Should be connected to ust_marker "UST_MARKER_NOARGS".
- */
-static notrace void ust_marker_probe_cb_noarg(const struct ust_marker *mdata,
- void *call_private, ...)
-{
- va_list args; /* not initialized */
- char ptype;
-
- rcu_read_lock();
- ptype = mdata->ptype;
- if (likely(!ptype)) {
- ust_marker_probe_func *func;
- /* Must read the ptype before ptr. They are not data dependant,
- * so we put an explicit cmm_smp_rmb() here. */
- cmm_smp_rmb();
- func = mdata->single.func;
- /* Must read the ptr before private data. They are not data
- * dependant, so we put an explicit cmm_smp_rmb() here. */
- cmm_smp_rmb();
- func(mdata, mdata->single.probe_private, call_private,
- mdata->format, &args);
- } else {
- struct ust_marker_probe_array *multi;
- int i;
- /*
- * Read mdata->ptype before mdata->multi.
- */
- cmm_smp_rmb();
- multi = mdata->multi;
- /*
- * multi points to an array, therefore accessing the array
- * depends on reading multi. However, even in this case,
- * we must insure that the pointer is read _before_ the array
- * data. Same as rcu_dereference, but we need a full cmm_smp_rmb()
- * in the fast path, so put the explicit cmm_barrier here.
- */
- cmm_smp_read_barrier_depends();
- for (i = 0; multi->c[i].func; i++)
- multi->c[i].func(mdata, multi->c[i].probe_private,
- call_private, mdata->format, &args);
- }
- rcu_read_unlock();
-}
-
-static void free_old_closure(struct rcu_head *head)
-{
- 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)
-{
- int i;
-
- if (!ust_marker_debug)
- return;
-
- if (!entry->ptype) {
- DBG("Single probe : %p %p",
- entry->single.func,
- entry->single.probe_private);
- } else {
- for (i = 0; entry->multi->c[i].func; i++)
- DBG("Multi probe %d : %p %p", i,
- entry->multi->c[i].func,
- entry->multi->c[i].probe_private);
- }
-}
-
-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_array *old, *new;
-
- WARN_ON(!probe);
-
- debug_print_probes(entry);
- old = entry->multi;
- if (!entry->ptype) {
- if (entry->single.func == probe &&
- entry->single.probe_private == probe_private)
- return ERR_PTR(-EBUSY);
- if (entry->single.func == __ust_marker_empty_function) {
- /* 0 -> 1 probes */
- entry->single.func = probe;
- entry->single.probe_private = probe_private;
- entry->refcount = 1;
- entry->ptype = 0;
- debug_print_probes(entry);
- return NULL;
- } else {
- /* 1 -> 2 probes */
- nr_probes = 1;
- old = NULL;
- }
- } else {
- /* (N -> N+1), (N != 0, 1) probes */
- 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(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->c[0] = entry->single;
- else
- memcpy(&new->c[0], &old->c[0],
- nr_probes * sizeof(struct ust_marker_probe_closure));
- 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;
- debug_print_probes(entry);
- return old;
-}
-
-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_array *old, *new;
-
- old = entry->multi;
-
- debug_print_probes(entry);
- if (!entry->ptype) {
- /* 0 -> N is an error */
- WARN_ON(entry->single.func == __ust_marker_empty_function);
- /* 1 -> 0 probes */
- WARN_ON(probe && entry->single.func != probe);
- WARN_ON(entry->single.probe_private != probe_private);
- entry->single.func = __ust_marker_empty_function;
- entry->refcount = 0;
- entry->ptype = 0;
- debug_print_probes(entry);
- return NULL;
- } else {
- /* (N -> M), (N > 1, M >= 0) probes */
- 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++;
- }
- }
-
- if (nr_probes - nr_del == 0) {
- /* N -> 0, (N > 1) */
- entry->single.func = __ust_marker_empty_function;
- entry->refcount = 0;
- entry->ptype = 0;
- } else if (nr_probes - nr_del == 1) {
- /* N -> 1, (N > 1) */
- 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(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->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;
- }
- debug_print_probes(entry);
- return old;
-}
-
-/*
- * Get ust_marker if the ust_marker is present in the ust_marker hash table.
- * Must be called with ust_marker_mutex held.
- * Returns NULL if not present.
- */
-static struct ust_marker_entry *get_ust_marker(const char *channel, const char *name)
-{
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
- struct ust_marker_entry *e;
- size_t channel_len = strlen(channel) + 1;
- size_t name_len = strlen(name) + 1;
- u32 hash;
-
- hash = jhash(channel, channel_len-1, 0) ^ jhash(name, name_len-1, 0);
- head = &ust_marker_table[hash & ((1 << UST_MARKER_HASH_BITS)-1)];
- cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(channel, e->channel) && !strcmp(name, e->name))
- return e;
- }
- return NULL;
-}
-
-/*
- * Add the ust_marker to the ust_marker hash table. Must be called with
- * ust_marker_mutex held.
- */
-static struct ust_marker_entry *add_ust_marker(const char *channel, const char *name,
- const char *format)
-{
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
- struct ust_marker_entry *e;
- size_t channel_len = strlen(channel) + 1;
- size_t name_len = strlen(name) + 1;
- size_t format_len = 0;
- u32 hash;
-
- hash = jhash(channel, channel_len-1, 0) ^ jhash(name, name_len-1, 0);
- if (format)
- format_len = strlen(format) + 1;
- head = &ust_marker_table[hash & ((1 << UST_MARKER_HASH_BITS)-1)];
- cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(channel, e->channel) && !strcmp(name, e->name)) {
- DBG("ust_marker %s.%s busy", channel, name);
- return ERR_PTR(-EBUSY); /* Already there */
- }
- }
- /*
- * Using zmalloc here to allocate a variable length element. Could
- * cause some memory fragmentation if overused.
- */
- e = zmalloc(sizeof(struct ust_marker_entry)
- + channel_len + name_len + format_len);
- if (!e)
- return ERR_PTR(-ENOMEM);
- memcpy(e->channel, channel, channel_len);
- e->name = &e->channel[channel_len];
- memcpy(e->name, name, name_len);
- if (format) {
- e->format = &e->name[name_len];
- memcpy(e->format, format, format_len);
- if (strcmp(e->format, UST_MARKER_NOARGS) == 0)
- e->call = ust_marker_probe_cb_noarg;
- else
- e->call = ust_marker_probe_cb;
- __ust_marker(metadata, core_marker_format, NULL,
- "channel %s name %s format %s",
- e->channel, e->name, e->format);
- } else {
- e->format = NULL;
- e->call = ust_marker_probe_cb;
- }
- e->single.func = __ust_marker_empty_function;
- e->single.probe_private = NULL;
- e->multi = NULL;
- e->ptype = 0;
- e->format_allocated = 0;
- e->refcount = 0;
- cds_hlist_add_head(&e->hlist, head);
- return e;
-}
-
-/*
- * Remove the ust_marker from the ust_marker hash table. Must be called with mutex_lock
- * held.
- */
-static int remove_ust_marker(const char *channel, const char *name)
-{
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
- struct ust_marker_entry *e;
- int found = 0;
- size_t channel_len = strlen(channel) + 1;
- size_t name_len = strlen(name) + 1;
- u32 hash;
- int ret;
-
- hash = jhash(channel, channel_len-1, 0) ^ jhash(name, name_len-1, 0);
- head = &ust_marker_table[hash & ((1 << UST_MARKER_HASH_BITS)-1)];
- cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(channel, e->channel) && !strcmp(name, e->name)) {
- found = 1;
- break;
- }
- }
- if (!found)
- return -ENOENT;
- if (e->single.func != __ust_marker_empty_function)
- return -EBUSY;
- cds_hlist_del(&e->hlist);
- if (e->format_allocated)
- free(e->format);
- ret = ltt_channels_unregister(e->channel);
- WARN_ON(ret);
- free(e);
- return 0;
-}
-
-/*
- * Set the mark_entry format to the format found in the element.
- */
-static int ust_marker_set_format(struct ust_marker_entry *entry, const char *format)
-{
- entry->format = strdup(format);
- if (!entry->format)
- return -ENOMEM;
- entry->format_allocated = 1;
-
- __ust_marker(metadata, core_marker_format, NULL,
- "channel %s name %s format %s",
- entry->channel, entry->name, entry->format);
- return 0;
-}
-
-/*
- * Sets the probe callback corresponding to one ust_marker.
- */
-static int set_ust_marker(struct ust_marker_entry *entry, struct ust_marker *elem,
- int active)
-{
- int ret = 0;
- WARN_ON(strcmp(entry->name, elem->name) != 0);
-
- if (entry->format) {
- if (strcmp(entry->format, elem->format) != 0) {
- ERR("Format mismatch for probe %s (%s), ust_marker (%s)",
- entry->name,
- entry->format,
- elem->format);
- return -EPERM;
- }
- } else {
- ret = ust_marker_set_format(entry, elem->format);
- if (ret)
- return ret;
- }
-
- /*
- * probe_cb setup (statically known) is done here. It is
- * asynchronous with the rest of execution, therefore we only
- * pass from a "safe" callback (with argument) to an "unsafe"
- * callback (does not set arguments).
- */
- elem->call = entry->call;
- elem->channel_id = entry->channel_id;
- elem->event_id = entry->event_id;
- /*
- * Sanity check :
- * We only update the single probe private data when the ptr is
- * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1)
- */
- WARN_ON(elem->single.func != __ust_marker_empty_function
- && elem->single.probe_private != entry->single.probe_private
- && !elem->ptype);
- elem->single.probe_private = entry->single.probe_private;
- /*
- * Make sure the private data is valid when we update the
- * single probe ptr.
- */
- cmm_smp_wmb();
- elem->single.func = entry->single.func;
- /*
- * We also make sure that the new probe callbacks array is consistent
- * before setting a pointer to it.
- */
- rcu_assign_pointer(elem->multi, entry->multi);
- /*
- * Update the function or multi probe array pointer before setting the
- * ptype.
- */
- cmm_smp_wmb();
- elem->ptype = entry->ptype;
-
- if (elem->tp_name && (active ^ elem->state)) {
- WARN_ON(!elem->tp_cb);
- /*
- * It is ok to directly call the probe registration because type
- * checking has been done in the __ust_marker_tp() macro.
- */
-
- if (active) {
- ret = tracepoint_probe_register_noupdate(
- elem->tp_name,
- elem->tp_cb, NULL);
- } else {
- /*
- * tracepoint_probe_update_all() must be called
- * before the library containing tp_cb is unloaded.
- */
- ret = tracepoint_probe_unregister_noupdate(
- elem->tp_name,
- elem->tp_cb, NULL);
- }
- }
- elem->state = active;
-
- return ret;
-}
-
-/*
- * 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 around the call site.
- */
-static void disable_ust_marker(struct ust_marker *elem)
-{
- int ret;
-
- /* leave "call" as is. It is known statically. */
- if (elem->tp_name && elem->state) {
- WARN_ON(!elem->tp_cb);
- /*
- * It is ok to directly call the probe registration because type
- * checking has been done in the __ust_marker_tp() macro.
- */
- /*
- * tracepoint_probe_update_all() must be called
- * before the module containing tp_cb is unloaded.
- */
- 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;
- /* Update the function before setting the ptype */
- cmm_smp_wmb();
- elem->ptype = 0; /* single probe */
- /*
- * Leave the private data and channel_id/event_id there, because removal
- * is racy and should be done only after an RCU period. These are never
- * used until the next initialization anyway.
- */
-}
-
-/*
- * is_ust_marker_enabled - Check if a ust_marker is enabled
- * @channel: channel name
- * @name: ust_marker name
- *
- * Returns 1 if the ust_marker is enabled, 0 if disabled.
- */
-int is_ust_marker_enabled(const char *channel, const char *name)
-{
- struct ust_marker_entry *entry;
-
- lock_ust_marker();
- entry = get_ust_marker(channel, name);
- unlock_ust_marker();
-
- return entry && !!entry->refcount;
-}
-
-/**
- * ust_marker_update_probe_range - Update a probe range
- * @begin: beginning of the range
- * @end: end of the range
- *
- * 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;
-
- for (iter = begin; iter < end; iter++) {
- if (!*iter)
- continue; /* skip dummy */
- mark_entry = get_ust_marker((*iter)->channel, (*iter)->name);
- if (mark_entry) {
- set_ust_marker(mark_entry, *iter, !!mark_entry->refcount);
- /*
- * ignore error, continue
- */
- } else {
- disable_ust_marker(*iter);
- }
- }
-}
-
-static void lib_update_ust_marker(void)
-{
- struct ust_marker_lib *lib;
-
- 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);
- unlock_ust_marker();
-}
-
-/*
- * Update probes, removing the faulty probes.
- *
- * Internal callback only changed before the first probe is connected to it.
- * Single probe private data can only be changed on 0 -> 1 and 2 -> 1
- * transitions. All other transitions will leave the old private data valid.
- * This makes the non-atomicity of the callback/private data updates valid.
- *
- * "special case" updates :
- * 0 -> 1 callback
- * 1 -> 0 callback
- * 1 -> 2 callbacks
- * 2 -> 1 callbacks
- * Other updates all behave the same, just like the 2 -> 3 or 3 -> 2 updates.
- * Site effect : ust_marker_set_format may delete the ust_marker entry (creating a
- * replacement).
- */
-static void ust_marker_update_probes(void)
-{
- lib_update_ust_marker();
- tracepoint_probe_update_all();
-}
-
-/**
- * ust_marker_probe_register - Connect a probe to a ust_marker
- * @channel: ust_marker channel
- * @name: ust_marker name
- * @format: format string
- * @probe: probe handler
- * @probe_private: probe private data
- *
- * private data must be a valid allocated memory address, or NULL.
- * Returns 0 if ok, error value on error.
- * The probe address must at least be aligned on the architecture pointer size.
- */
-int ust_marker_probe_register(const char *channel, const char *name,
- const char *format, ust_marker_probe_func *probe,
- void *probe_private)
-{
- struct ust_marker_entry *entry;
- int ret = 0, ret_err;
- struct ust_marker_probe_array *old;
- int first_probe = 0;
-
- lock_ust_marker();
- entry = get_ust_marker(channel, name);
- if (!entry) {
- first_probe = 1;
- entry = add_ust_marker(channel, name, format);
- if (IS_ERR(entry))
- ret = PTR_ERR(entry);
- if (ret)
- goto end;
- ret = ltt_channels_register(channel);
- if (ret)
- goto error_remove_ust_marker;
- ret = ltt_channels_get_index_from_name(channel);
- if (ret < 0)
- goto error_unregister_channel;
- entry->channel_id = ret;
- ret = ltt_channels_get_event_id(channel, name);
- if (ret < 0)
- goto error_unregister_channel;
- entry->event_id = ret;
- ret = 0;
- __ust_marker(metadata, core_marker_id, NULL,
- "channel %s name %s event_id %hu "
- "int #1u%zu long #1u%zu pointer #1u%zu "
- "size_t #1u%zu alignment #1u%u",
- channel, name, entry->event_id,
- sizeof(int), sizeof(long), sizeof(void *),
- sizeof(size_t), ltt_get_alignment());
- } else if (format) {
- if (!entry->format)
- ret = ust_marker_set_format(entry, format);
- else if (strcmp(entry->format, format))
- ret = -EPERM;
- if (ret)
- goto end;
- }
-
- old = ust_marker_entry_add_probe(entry, probe, probe_private);
- if (IS_ERR(old)) {
- ret = PTR_ERR(old);
- if (first_probe)
- goto error_unregister_channel;
- else
- goto end;
- }
- unlock_ust_marker();
-
- /* Activate ust_marker if necessary */
- ust_marker_update_probes();
-
- if (old) {
- synchronize_rcu();
- free_old_closure(&old->rcu);
- }
- return ret;
-
-error_unregister_channel:
- ret_err = ltt_channels_unregister(channel);
- WARN_ON(ret_err);
-error_remove_ust_marker:
- ret_err = remove_ust_marker(channel, name);
- WARN_ON(ret_err);
-end:
- unlock_ust_marker();
- return ret;
-}
-
-/**
- * ust_marker_probe_unregister - Disconnect a probe from a ust_marker
- * @channel: ust_marker channel
- * @name: ust_marker name
- * @probe: probe function pointer
- * @probe_private: probe private data
- *
- * Returns the private data given to ust_marker_probe_register, or an ERR_PTR().
- * We do not need to call a synchronize_sched to make sure the probes have
- * finished running before doing a module unload, because the module unload
- * itself uses stop_machine(), which insures that every preempt disabled section
- * have finished.
- */
-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_array *old;
- int ret = 0;
-
- lock_ust_marker();
- entry = get_ust_marker(channel, name);
- if (!entry) {
- ret = -ENOENT;
- goto end;
- }
- old = ust_marker_entry_remove_probe(entry, probe, probe_private);
- unlock_ust_marker();
-
- ust_marker_update_probes();
-
- if (old) {
- synchronize_rcu();
- free_old_closure(&old->rcu);
- }
- return ret;
-
-end:
- unlock_ust_marker();
- return ret;
-}
-
-static struct ust_marker_entry *
-get_ust_marker_from_private_data(ust_marker_probe_func *probe,
- void *probe_private)
-{
- struct ust_marker_entry *entry;
- unsigned int i;
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
-
- for (i = 0; i < UST_MARKER_TABLE_SIZE; i++) {
- head = &ust_marker_table[i];
- cds_hlist_for_each_entry(entry, node, head, hlist) {
- if (!entry->ptype) {
- if (entry->single.func == probe
- && entry->single.probe_private
- == probe_private)
- return entry;
- } else {
- struct ust_marker_probe_array *closure;
- closure = entry->multi;
- for (i = 0; closure->c[i].func; i++) {
- if (closure->c[i].func == probe &&
- closure->c[i].probe_private
- == probe_private)
- return entry;
- }
- }
- }
- }
- return NULL;
-}
-
-/**
- * ust_marker_probe_unregister_private_data - Disconnect a probe from a ust_marker
- * @probe: probe function
- * @probe_private: probe private data
- *
- * Unregister a probe by providing the registered private data.
- * Only removes the first ust_marker found in hash table.
- * Return 0 on success or error value.
- * We do not need to call a synchronize_sched to make sure the probes have
- * finished running before doing a module unload, because the module unload
- * itself uses stop_machine(), which insures that every preempt disabled section
- * have finished.
- */
-int ust_marker_probe_unregister_private_data(ust_marker_probe_func *probe,
- void *probe_private)
-{
- struct ust_marker_entry *entry;
- int ret = 0;
- struct ust_marker_probe_array *old;
- char *channel = NULL, *name = NULL;
-
- lock_ust_marker();
- entry = get_ust_marker_from_private_data(probe, probe_private);
- if (!entry) {
- ret = -ENOENT;
- goto unlock;
- }
- old = ust_marker_entry_remove_probe(entry, NULL, probe_private);
- channel = strdup(entry->channel);
- name = strdup(entry->name);
- /* Ignore busy error message */
- remove_ust_marker(channel, name);
- unlock_ust_marker();
-
- ust_marker_update_probes();
-
- if (old) {
- synchronize_rcu();
- free_old_closure(&old->rcu);
- }
- goto end;
-
-unlock:
- unlock_ust_marker();
-end:
- free(channel);
- free(name);
- return ret;
-}
-
-/**
- * ust_marker_get_private_data - Get a ust_marker's probe private data
- * @channel: ust_marker channel
- * @name: ust_marker name
- * @probe: probe to match
- * @num: get the nth matching probe's private data
- *
- * Returns the nth private data pointer (starting from 0) matching, or an
- * ERR_PTR.
- * Returns the private data pointer, or an ERR_PTR.
- * The private data pointer should _only_ be dereferenced if the caller is the
- * owner of the data, or its content could vanish. This is mostly used to
- * confirm that a caller is the owner of a registered probe.
- */
-void *ust_marker_get_private_data(const char *channel, const char *name,
- ust_marker_probe_func *probe, int num)
-{
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
- struct ust_marker_entry *e;
- size_t channel_len = strlen(channel) + 1;
- size_t name_len = strlen(name) + 1;
- int i;
- u32 hash;
-
- hash = jhash(channel, channel_len-1, 0) ^ jhash(name, name_len-1, 0);
- head = &ust_marker_table[hash & ((1 << UST_MARKER_HASH_BITS)-1)];
- cds_hlist_for_each_entry(e, node, head, hlist) {
- if (!strcmp(channel, e->channel) && !strcmp(name, e->name)) {
- if (!e->ptype) {
- if (num == 0 && e->single.func == probe)
- return e->single.probe_private;
- } else {
- struct ust_marker_probe_array *closure;
- int match = 0;
- closure = e->multi;
- for (i = 0; closure->c[i].func; i++) {
- if (closure->c[i].func != probe)
- continue;
- if (match++ == num)
- return closure->c[i].probe_private;
- }
- }
- break;
- }
- }
- return ERR_PTR(-ENOENT);
-}
-
-/**
- * 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.
- * Called with markers mutex held.
- */
-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;
-
- cds_list_for_each_entry(iter_lib, &ust_marker_libs, list) {
- if (iter_lib < iter->lib)
- continue;
- else if (iter_lib > iter->lib)
- iter->ust_marker = NULL;
- found = ust_marker_get_iter_range(&iter->ust_marker,
- iter_lib->ust_marker_start,
- iter_lib->ust_marker_start + iter_lib->ust_marker_count);
- if (found) {
- iter->lib = iter_lib;
- break;
- }
- }
- return found;
-}
-
-/* Called with markers mutex held. */
-static void ust_marker_get_iter(struct ust_marker_iter *iter)
-{
- int found = 0;
-
- found = lib_get_iter_ust_marker(iter);
- if (!found)
- ust_marker_iter_reset(iter);
-}
-
-void ust_marker_iter_start(struct ust_marker_iter *iter)
-{
- lock_ust_marker();
- ust_marker_get_iter(iter);
-}
-
-/* Called with markers mutex held. */
-void ust_marker_iter_next(struct ust_marker_iter *iter)
-{
- iter->ust_marker++;
- /*
- * iter->ust_marker may be invalid because we blindly incremented it.
- * Make sure it is valid by marshalling on the ust_marker, getting the
- * ust_marker from following modules if necessary.
- */
- ust_marker_get_iter(iter);
-}
-
-void ust_marker_iter_stop(struct ust_marker_iter *iter)
-{
- unlock_ust_marker();
-}
-
-void ust_marker_iter_reset(struct ust_marker_iter *iter)
-{
- iter->lib = NULL;
- iter->ust_marker = NULL;
-}
-
-void ltt_dump_ust_marker_state(struct ust_trace *trace)
-{
- struct ust_marker_entry *entry;
- struct ltt_probe_private_data call_data;
- struct cds_hlist_head *head;
- struct cds_hlist_node *node;
- unsigned int i;
-
- lock_ust_marker();
- call_data.trace = trace;
- call_data.serializer = NULL;
-
- for (i = 0; i < UST_MARKER_TABLE_SIZE; i++) {
- head = &ust_marker_table[i];
- cds_hlist_for_each_entry(entry, node, head, hlist) {
- __ust_marker(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",
- entry->channel,
- entry->name,
- entry->event_id,
- sizeof(int), sizeof(long),
- sizeof(void *), sizeof(size_t),
- ltt_get_alignment());
- if (entry->format)
- __ust_marker(metadata,
- core_marker_format,
- &call_data,
- "channel %s name %s format %s",
- entry->channel,
- entry->name,
- entry->format);
- }
- }
- unlock_ust_marker();
-}
-
-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)
-{
- if (new_ust_marker_cb) {
- struct ust_marker * const *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)
-{
- struct ust_marker_lib *pl, *iter;
-
- pl = (struct ust_marker_lib *) zmalloc(sizeof(struct ust_marker_lib));
-
- pl->ust_marker_start = ust_marker_start;
- pl->ust_marker_count = ust_marker_count;
-
- lock_ust_marker();
-
- /*
- * We sort the libs by struct lib pointer address.
- */
- cds_list_for_each_entry_reverse(iter, &ust_marker_libs, list) {
- BUG_ON(iter == pl); /* Should never be in the list twice */
- if (iter < pl) {
- /* We belong to the location right after iter. */
- cds_list_add(&pl->list, &iter->list);
- goto lib_added;
- }
- }
- /* We should be added at the head of the list */
- cds_list_add(&pl->list, &ust_marker_libs);
-lib_added:
- unlock_ust_marker();
-
- new_ust_marker(ust_marker_start, ust_marker_start + ust_marker_count);
-
- /* 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);
-
- return 0;
-}
-
-int ust_marker_unregister_lib(struct ust_marker * const *ust_marker_start)
-{
- struct ust_marker_lib *lib;
-
- lock_ust_marker();
- cds_list_for_each_entry(lib, &ust_marker_libs, list) {
- if(lib->ust_marker_start == ust_marker_start) {
- struct ust_marker_lib *lib2free = lib;
- cds_list_del(&lib->list);
- free(lib2free);
- break;
- }
- }
- unlock_ust_marker();
-
- return 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);
- initialized = 1;
- }
-}
-
-void __attribute__((destructor)) destroy_ust_marker(void)
-{
- ust_marker_unregister_lib(__start___ust_marker_ptrs);
-}
+++ /dev/null
-/*
- * LTTng serializing code.
- *
- * Copyright Mathieu Desnoyers, March 2007.
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- *
- *
- * See this discussion about weirdness about passing va_list and then va_list to
- * functions. (related to array argument passing). va_list seems to be
- * implemented as an array on x86_64, but not on i386... This is why we pass a
- * va_list * to ltt_vtrace.
- */
-
-#define _GNU_SOURCE
-#define _LGPL_SOURCE
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <urcu-bp.h>
-#include <urcu/rculist.h>
-
-#include <ust/core.h>
-#include <ust/clock.h>
-#include "buffers.h"
-#include "tracer.h"
-#include "usterr_signal_safe.h"
-#include "ust_snprintf.h"
-
-/*
- * Because UST core defines a non-const PAGE_SIZE, define PAGE_SIZE_STATIC here.
- * It is just an approximation for the tracer stack.
- */
-#define PAGE_SIZE_STATIC 4096
-
-enum ltt_type {
- LTT_TYPE_SIGNED_INT,
- LTT_TYPE_UNSIGNED_INT,
- LTT_TYPE_STRING,
- LTT_TYPE_NONE,
-};
-
-/*
- * Special stack for the tracer. Keeps serialization offsets for each field.
- * Per-thread. Deals with reentrancy from signals by simply ensuring that
- * interrupting signals put the stack back to its original position.
- */
-#define TRACER_STACK_LEN (PAGE_SIZE_STATIC / sizeof(unsigned long))
-static unsigned long __thread tracer_stack[TRACER_STACK_LEN];
-
-static unsigned int __thread tracer_stack_pos;
-
-#define LTT_ATTRIBUTE_NETWORK_BYTE_ORDER (1<<1)
-
-/*
- * Inspired from vsnprintf
- *
- * The serialization format string supports the basic printf format strings.
- * In addition, it defines new formats that can be used to serialize more
- * complex/non portable data structures.
- *
- * Typical use:
- *
- * field_name %ctype
- * field_name #tracetype %ctype
- * field_name #tracetype %ctype1 %ctype2 ...
- *
- * A conversion is performed between format string types supported by GCC and
- * the trace type requested. GCC type is used to perform type checking on format
- * strings. Trace type is used to specify the exact binary representation
- * in the trace. A mapping is done between one or more GCC types to one trace
- * type. Sign extension, if required by the conversion, is performed following
- * the trace type.
- *
- * If a gcc format is not declared with a trace format, the gcc format is
- * also used as binary representation in the trace.
- *
- * Strings are supported with %s.
- * A single tracetype (sequence) can take multiple c types as parameter.
- *
- * c types:
- *
- * see printf(3).
- *
- * Note: to write a uint32_t in a trace, the following expression is recommended
- * si it can be portable:
- *
- * ("#4u%lu", (unsigned long)var)
- *
- * trace types:
- *
- * Serialization specific formats :
- *
- * Fixed size integers
- * #1u writes uint8_t
- * #2u writes uint16_t
- * #4u writes uint32_t
- * #8u writes uint64_t
- * #1d writes int8_t
- * #2d writes int16_t
- * #4d writes int32_t
- * #8d writes int64_t
- * i.e.:
- * #1u%lu #2u%lu #4d%lu #8d%lu #llu%hu #d%lu
- *
- * * Attributes:
- *
- * n: (for network byte order)
- * #ntracetype%ctype
- * is written in the trace in network byte order.
- *
- * i.e.: #bn4u%lu, #n%lu, #b%u
- *
- * TODO (eventually)
- * Variable length sequence
- * #a #tracetype1 #tracetype2 %array_ptr %elem_size %num_elems
- * In the trace:
- * #a specifies that this is a sequence
- * #tracetype1 is the type of elements in the sequence
- * #tracetype2 is the type of the element count
- * GCC input:
- * array_ptr is a pointer to an array that contains members of size
- * elem_size.
- * num_elems is the number of elements in the array.
- * i.e.: #a #lu #lu %p %lu %u
- *
- * Callback
- * #k callback (taken from the probe data)
- * The following % arguments are exepected by the callback
- *
- * i.e.: #a #lu #lu #k %p
- *
- * Note: No conversion is done from floats to integers, nor from integers to
- * floats between c types and trace types. float conversion from double to float
- * or from float to double is also not supported.
- *
- * REMOVE
- * %*b expects sizeof(data), data
- * where sizeof(data) is 1, 2, 4 or 8
- *
- * Fixed length struct, union or array.
- * FIXME: unable to extract those sizes statically.
- * %*r expects sizeof(*ptr), ptr
- * %*.*r expects sizeof(*ptr), __alignof__(*ptr), ptr
- * struct and unions removed.
- * Fixed length array:
- * [%p]#a[len #tracetype]
- * i.e.: [%p]#a[12 #lu]
- *
- * Variable length sequence
- * %*.*:*v expects sizeof(*ptr), __alignof__(*ptr), elem_num, ptr
- * where elem_num is the number of elements in the sequence
- */
-static inline const char *parse_trace_type(const char *fmt,
- char *trace_size, enum ltt_type *trace_type,
- unsigned long *attributes)
-{
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
- /* 'z' support added 23/7/1999 S.H. */
- /* 'z' changed to 'Z' --davidm 1/25/99 */
- /* 't' added for ptrdiff_t */
-
- /* parse attributes. */
-repeat:
- switch (*fmt) {
- case 'n':
- *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER;
- ++fmt;
- goto repeat;
- }
-
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
- *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
- *fmt == 'S' || *fmt == '1' || *fmt == '2' ||
- *fmt == '4' || *fmt == 8) {
- qualifier = *fmt;
- ++fmt;
- if (qualifier == 'l' && *fmt == 'l') {
- qualifier = 'L';
- ++fmt;
- }
- }
-
- switch (*fmt) {
- case 'c':
- *trace_type = LTT_TYPE_UNSIGNED_INT;
- *trace_size = sizeof(unsigned char);
- goto parse_end;
- case 's':
- *trace_type = LTT_TYPE_STRING;
- goto parse_end;
- case 'p':
- *trace_type = LTT_TYPE_UNSIGNED_INT;
- *trace_size = sizeof(void *);
- goto parse_end;
- case 'd':
- case 'i':
- *trace_type = LTT_TYPE_SIGNED_INT;
- break;
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- *trace_type = LTT_TYPE_UNSIGNED_INT;
- break;
- default:
- if (!*fmt)
- --fmt;
- goto parse_end;
- }
- switch (qualifier) {
- case 'L':
- *trace_size = sizeof(long long);
- break;
- case 'l':
- *trace_size = sizeof(long);
- break;
- case 'Z':
- case 'z':
- *trace_size = sizeof(size_t);
- break;
-//ust// case 't':
-//ust// *trace_size = sizeof(ptrdiff_t);
-//ust// break;
- case 'h':
- *trace_size = sizeof(short);
- break;
- case '1':
- *trace_size = sizeof(uint8_t);
- break;
- case '2':
- *trace_size = sizeof(uint16_t);
- break;
- case '4':
- *trace_size = sizeof(uint32_t);
- break;
- case '8':
- *trace_size = sizeof(uint64_t);
- break;
- default:
- *trace_size = sizeof(int);
- }
-
-parse_end:
- return fmt;
-}
-
-/*
- * Restrictions:
- * Field width and precision are *not* supported.
- * %n not supported.
- */
-static inline
-const char *parse_c_type(const char *fmt, char *c_size, enum ltt_type *c_type,
- char *outfmt)
-{
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
- /* 'z' support added 23/7/1999 S.H. */
- /* 'z' changed to 'Z' --davidm 1/25/99 */
- /* 't' added for ptrdiff_t */
-
- /* process flags : ignore standard print formats for now. */
-repeat:
- switch (*fmt) {
- case '-':
- case '+':
- case ' ':
- case '#':
- case '0':
- ++fmt;
- goto repeat;
- }
-
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
- *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
- *fmt == 'S') {
- qualifier = *fmt;
- ++fmt;
- if (qualifier == 'l' && *fmt == 'l') {
- qualifier = 'L';
- ++fmt;
- }
- }
-
- if (outfmt) {
- if (qualifier != -1)
- *outfmt++ = (char)qualifier;
- *outfmt++ = *fmt;
- *outfmt = 0;
- }
-
- switch (*fmt) {
- case 'c':
- *c_type = LTT_TYPE_UNSIGNED_INT;
- *c_size = sizeof(unsigned char);
- goto parse_end;
- case 's':
- *c_type = LTT_TYPE_STRING;
- goto parse_end;
- case 'p':
- *c_type = LTT_TYPE_UNSIGNED_INT;
- *c_size = sizeof(void *);
- goto parse_end;
- case 'd':
- case 'i':
- *c_type = LTT_TYPE_SIGNED_INT;
- break;
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- *c_type = LTT_TYPE_UNSIGNED_INT;
- break;
- default:
- if (!*fmt)
- --fmt;
- goto parse_end;
- }
- switch (qualifier) {
- case 'L':
- *c_size = sizeof(long long);
- break;
- case 'l':
- *c_size = sizeof(long);
- break;
- case 'Z':
- case 'z':
- *c_size = sizeof(size_t);
- break;
-//ust// case 't':
-//ust// *c_size = sizeof(ptrdiff_t);
-//ust// break;
- case 'h':
- *c_size = sizeof(short);
- break;
- default:
- *c_size = sizeof(int);
- }
-
-parse_end:
- return fmt;
-}
-
-static inline size_t serialize_trace_data(struct ust_buffer *buf,
- size_t buf_offset,
- char trace_size, enum ltt_type trace_type,
- char c_size, enum ltt_type c_type,
- unsigned int *stack_pos_ctx,
- int *largest_align,
- va_list *args)
-{
- union {
- unsigned long v_ulong;
- uint64_t v_uint64;
- struct {
- const char *s;
- size_t len;
- } v_string;
- } tmp;
-
- /*
- * Be careful about sign extension here.
- * Sign extension is done with the destination (trace) type.
- */
- switch (trace_type) {
- case LTT_TYPE_SIGNED_INT:
- switch (c_size) {
- case 1:
- tmp.v_ulong = (long)(int8_t)va_arg(*args, int);
- break;
- case 2:
- tmp.v_ulong = (long)(int16_t)va_arg(*args, int);
- break;
- case 4:
- tmp.v_ulong = (long)(int32_t)va_arg(*args, int);
- break;
- case 8:
- tmp.v_uint64 = va_arg(*args, int64_t);
- break;
- default:
- BUG();
- }
- break;
- case LTT_TYPE_UNSIGNED_INT:
- switch (c_size) {
- case 1:
- tmp.v_ulong = (unsigned long)(uint8_t)va_arg(*args, unsigned int);
- break;
- case 2:
- tmp.v_ulong = (unsigned long)(uint16_t)va_arg(*args, unsigned int);
- break;
- case 4:
- tmp.v_ulong = (unsigned long)(uint32_t)va_arg(*args, unsigned int);
- break;
- case 8:
- tmp.v_uint64 = va_arg(*args, uint64_t);
- break;
- default:
- BUG();
- }
- break;
- case LTT_TYPE_STRING:
- tmp.v_string.s = va_arg(*args, const char *);
- if ((unsigned long)tmp.v_string.s < PAGE_SIZE)
- tmp.v_string.s = "<NULL>";
- if (!buf) {
- /*
- * Reserve tracer stack entry.
- */
- tracer_stack_pos++;
- assert(tracer_stack_pos <= TRACER_STACK_LEN);
- cmm_barrier();
- tracer_stack[*stack_pos_ctx] =
- strlen(tmp.v_string.s) + 1;
- }
- tmp.v_string.len = tracer_stack[(*stack_pos_ctx)++];
- if (buf)
- ust_buffers_strncpy(buf, buf_offset, tmp.v_string.s,
- tmp.v_string.len);
- buf_offset += tmp.v_string.len;
- goto copydone;
- default:
- BUG();
- }
-
- /*
- * If trace_size is lower or equal to 4 bytes, there is no sign
- * extension to do because we are already encoded in a long. Therefore,
- * we can combine signed and unsigned ops. 4 bytes float also works
- * with this, because we do a simple copy of 4 bytes into 4 bytes
- * without manipulation (and we do not support conversion from integers
- * to floats).
- * It is also the case if c_size is 8 bytes, which is the largest
- * possible integer.
- */
- if (ltt_get_alignment()) {
- buf_offset += ltt_align(buf_offset, trace_size);
- if (largest_align)
- *largest_align = max_t(int, *largest_align, trace_size);
- }
- if (trace_size <= 4 || c_size == 8) {
- if (buf) {
- switch (trace_size) {
- case 1:
- if (c_size == 8)
- ust_buffers_write(buf, buf_offset,
- (uint8_t[]){ (uint8_t)tmp.v_uint64 },
- sizeof(uint8_t));
- else
- ust_buffers_write(buf, buf_offset,
- (uint8_t[]){ (uint8_t)tmp.v_ulong },
- sizeof(uint8_t));
- break;
- case 2:
- if (c_size == 8)
- ust_buffers_write(buf, buf_offset,
- (uint16_t[]){ (uint16_t)tmp.v_uint64 },
- sizeof(uint16_t));
- else
- ust_buffers_write(buf, buf_offset,
- (uint16_t[]){ (uint16_t)tmp.v_ulong },
- sizeof(uint16_t));
- break;
- case 4:
- if (c_size == 8)
- ust_buffers_write(buf, buf_offset,
- (uint32_t[]){ (uint32_t)tmp.v_uint64 },
- sizeof(uint32_t));
- else
- ust_buffers_write(buf, buf_offset,
- (uint32_t[]){ (uint32_t)tmp.v_ulong },
- sizeof(uint32_t));
- break;
- case 8:
- /*
- * c_size cannot be other than 8 here because
- * trace_size > 4.
- */
- ust_buffers_write(buf, buf_offset,
- (uint64_t[]){ (uint64_t)tmp.v_uint64 },
- sizeof(uint64_t));
- break;
- default:
- BUG();
- }
- }
- buf_offset += trace_size;
- goto copydone;
- } else {
- /*
- * Perform sign extension.
- */
- if (buf) {
- switch (trace_type) {
- case LTT_TYPE_SIGNED_INT:
- ust_buffers_write(buf, buf_offset,
- (int64_t[]){ (int64_t)tmp.v_ulong },
- sizeof(int64_t));
- break;
- case LTT_TYPE_UNSIGNED_INT:
- ust_buffers_write(buf, buf_offset,
- (uint64_t[]){ (uint64_t)tmp.v_ulong },
- sizeof(uint64_t));
- break;
- default:
- BUG();
- }
- }
- buf_offset += trace_size;
- goto copydone;
- }
-
-copydone:
- return buf_offset;
-}
-
-notrace size_t ltt_serialize_data(struct ust_buffer *buf, size_t buf_offset,
- struct ltt_serialize_closure *closure,
- void *serialize_private,
- unsigned int stack_pos_ctx,
- int *largest_align,
- const char *fmt, va_list *args)
-{
- char trace_size = 0, c_size = 0; /*
- * 0 (unset), 1, 2, 4, 8 bytes.
- */
- enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
- unsigned long attributes = 0;
-
- for (; *fmt ; ++fmt) {
- switch (*fmt) {
- case '#':
- /* tracetypes (#) */
- ++fmt; /* skip first '#' */
- if (*fmt == '#') /* Escaped ## */
- break;
- attributes = 0;
- fmt = parse_trace_type(fmt, &trace_size, &trace_type,
- &attributes);
- break;
- case '%':
- /* c types (%) */
- ++fmt; /* skip first '%' */
- if (*fmt == '%') /* Escaped %% */
- break;
- fmt = parse_c_type(fmt, &c_size, &c_type, NULL);
- /*
- * Output c types if no trace types has been
- * specified.
- */
- if (!trace_size)
- trace_size = c_size;
- if (trace_type == LTT_TYPE_NONE)
- trace_type = c_type;
- if (c_type == LTT_TYPE_STRING)
- trace_type = LTT_TYPE_STRING;
- /* perform trace write */
- buf_offset = serialize_trace_data(buf,
- buf_offset, trace_size,
- trace_type, c_size, c_type,
- &stack_pos_ctx,
- largest_align,
- args);
- trace_size = 0;
- c_size = 0;
- trace_type = LTT_TYPE_NONE;
- c_size = LTT_TYPE_NONE;
- attributes = 0;
- break;
- /* default is to skip the text, doing nothing */
- }
- }
- return buf_offset;
-}
-
-/*
- * Calculate data size
- * Assume that the padding for alignment starts at a sizeof(void *) address.
- */
-static notrace size_t ltt_get_data_size(struct ltt_serialize_closure *closure,
- void *serialize_private,
- unsigned int stack_pos_ctx, int *largest_align,
- const char *fmt, va_list *args)
-{
- ltt_serialize_cb cb = closure->callbacks[0];
- closure->cb_idx = 0;
- return (size_t)cb(NULL, 0, closure, serialize_private,
- stack_pos_ctx, largest_align, fmt, args);
-}
-
-static notrace
-void ltt_write_event_data(struct ust_buffer *buf, size_t buf_offset,
- struct ltt_serialize_closure *closure,
- void *serialize_private,
- unsigned int stack_pos_ctx,
- int largest_align,
- const char *fmt, va_list *args)
-{
- ltt_serialize_cb cb = closure->callbacks[0];
- closure->cb_idx = 0;
- buf_offset += ltt_align(buf_offset, largest_align);
- cb(buf, buf_offset, closure, serialize_private, stack_pos_ctx, NULL,
- fmt, args);
-}
-
-
-notrace void ltt_vtrace(const struct ust_marker *mdata, void *probe_data,
- void *call_data,
- const char *fmt, va_list *args)
-{
- int largest_align, ret;
- struct ltt_active_ust_marker *pdata;
- uint16_t eID;
- size_t data_size, slot_size;
- unsigned int chan_index;
- struct ust_channel *channel;
- struct ust_trace *trace, *dest_trace = NULL;
- struct ust_buffer *buf;
- u64 tsc;
- long buf_offset;
- va_list args_copy;
- struct ltt_serialize_closure closure;
- struct ltt_probe_private_data *private_data = call_data;
- void *serialize_private = NULL;
- int cpu;
- unsigned int rflags;
- unsigned int stack_pos_ctx;
-
- /*
- * This test is useful for quickly exiting static tracing when no trace
- * is active. We expect to have an active trace when we get here.
- */
- if (unlikely(ltt_traces.num_active_traces == 0))
- return;
-
- rcu_read_lock();
- cpu = ust_get_cpu();
-
- /* Force volatile access. */
- CMM_STORE_SHARED(ltt_nesting, CMM_LOAD_SHARED(ltt_nesting) + 1);
- stack_pos_ctx = tracer_stack_pos;
- cmm_barrier();
-
- pdata = (struct ltt_active_ust_marker *)probe_data;
- eID = mdata->event_id;
- chan_index = mdata->channel_id;
- closure.callbacks = pdata->probe->callbacks;
-
- if (unlikely(private_data)) {
- dest_trace = private_data->trace;
- if (private_data->serializer)
- closure.callbacks = &private_data->serializer;
- serialize_private = private_data->serialize_private;
- }
-
- va_copy(args_copy, *args);
- /*
- * Assumes event payload to start on largest_align alignment.
- */
- largest_align = 1; /* must be non-zero for ltt_align */
- data_size = ltt_get_data_size(&closure, serialize_private,
- stack_pos_ctx, &largest_align,
- fmt, &args_copy);
- largest_align = min_t(int, largest_align, sizeof(void *));
- va_end(args_copy);
-
- /* Iterate on each trace */
- cds_list_for_each_entry_rcu(trace, <t_traces.head, list) {
- /*
- * Expect the filter to filter out events. If we get here,
- * we went through tracepoint activation as a first step.
- */
- if (unlikely(dest_trace && trace != dest_trace))
- continue;
- if (unlikely(!trace->active))
- continue;
- if (unlikely(!ltt_run_filter(trace, eID)))
- continue;
-#ifdef CONFIG_LTT_DEBUG_EVENT_SIZE
- rflags = LTT_RFLAG_ID_SIZE;
-#else
- if (unlikely(eID >= LTT_FREE_EVENTS))
- rflags = LTT_RFLAG_ID;
- else
- rflags = 0;
-#endif
- /*
- * Skip channels added after trace creation.
- */
- if (unlikely(chan_index >= trace->nr_channels))
- continue;
- channel = &trace->channels[chan_index];
- if (!channel->active)
- continue;
-
- /*
- * If a new cpu was plugged since the trace was started, we did
- * not add it to the trace, and therefore we write the event to
- * cpu 0.
- */
- if (cpu >= channel->n_cpus) {
- cpu = 0;
- }
-
- /* reserve space : header and data */
- ret = ltt_reserve_slot(channel, trace, data_size, largest_align,
- cpu, &buf, &slot_size, &buf_offset,
- &tsc, &rflags);
- if (unlikely(ret < 0))
- continue; /* buffer full */
-
- va_copy(args_copy, *args);
- /* FIXME : could probably encapsulate transport better. */
- buf = channel->buf[cpu];
- /* Out-of-order write : header and data */
- buf_offset = ltt_write_event_header(channel, buf, buf_offset,
- eID, data_size, tsc, rflags);
- ltt_write_event_data(buf, buf_offset, &closure,
- serialize_private,
- stack_pos_ctx, largest_align,
- fmt, &args_copy);
- va_end(args_copy);
- /* Out-of-order commit */
- ltt_commit_slot(channel, buf, buf_offset, data_size, slot_size);
- DBG("just commited event (%s/%s) at offset %ld and size %zd", mdata->channel, mdata->name, buf_offset, slot_size);
- }
-
- cmm_barrier();
- tracer_stack_pos = stack_pos_ctx;
- CMM_STORE_SHARED(ltt_nesting, CMM_LOAD_SHARED(ltt_nesting) - 1);
-
- rcu_read_unlock();
-}
-
-notrace void ltt_trace(const struct ust_marker *mdata, void *probe_data,
- void *call_data,
- const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- ltt_vtrace(mdata, probe_data, call_data, fmt, &args);
- va_end(args);
-}
-
-static notrace void skip_space(const char **ps)
-{
- while(**ps == ' ')
- (*ps)++;
-}
-
-static notrace void copy_token(char **out, const char **in)
-{
- while (**in != ' ' && **in != '\0') {
- **out = **in;
- (*out)++;
- (*in)++;
- }
-}
-
-/* serialize_to_text
- *
- * Given a format string and a va_list of arguments, convert them to a
- * human-readable string.
- *
- * @outbuf: the buffer to output the string to
- * @bufsize: the max size that can be used in outbuf
- * @fmt: the marker format string
- * @ap: a va_list that contains the arguments corresponding to fmt
- *
- * Return value: the number of chars that have been put in outbuf, excluding
- * the final \0, or, if the buffer was too small, the number of chars that
- * would have been written in outbuf if it had been large enough.
- *
- * outbuf may be NULL. The return value may then be used be allocate an
- * appropriate outbuf.
- *
- */
-
-notrace
-int serialize_to_text(char *outbuf, int bufsize, const char *fmt, va_list ap)
-{
- int fmt_len = strlen(fmt);
- char *new_fmt = alloca(fmt_len + 1);
- const char *orig_fmt_p = fmt;
- char *new_fmt_p = new_fmt;
- char false_buf;
- int result;
- enum { none, cfmt, tracefmt, argname } prev_token = none;
-
- while (*orig_fmt_p != '\0') {
- if (*orig_fmt_p == '%') {
- prev_token = cfmt;
- copy_token(&new_fmt_p, &orig_fmt_p);
- }
- else if (*orig_fmt_p == '#') {
- prev_token = tracefmt;
- do {
- orig_fmt_p++;
- } while (*orig_fmt_p != ' ' && *orig_fmt_p != '\0');
- }
- else if (*orig_fmt_p == ' ') {
- if (prev_token == argname) {
- *new_fmt_p = '=';
- new_fmt_p++;
- }
- else if (prev_token == cfmt) {
- *new_fmt_p = ' ';
- new_fmt_p++;
- }
-
- skip_space(&orig_fmt_p);
- }
- else {
- prev_token = argname;
- copy_token(&new_fmt_p, &orig_fmt_p);
- }
- }
-
- *new_fmt_p = '\0';
-
- if (outbuf == NULL) {
- /* use this false_buffer for compatibility with pre-C99 */
- outbuf = &false_buf;
- bufsize = 1;
- }
- result = ust_safe_vsnprintf(outbuf, bufsize, new_fmt, ap);
-
- return result;
-}
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-/* This file contains the implementation of the UST listener thread, which
- * receives trace control commands. It also coordinates the initialization of
- * libust.
- */
-
-#define _GNU_SOURCE
-#define _LGPL_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <pthread.h>
-#include <signal.h>
-#include <sys/epoll.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <regex.h>
-#include <urcu/uatomic.h>
-#include <urcu/list.h>
-
-#include <ust/marker.h>
-#include <ust/tracepoint.h>
-#include <ust/tracepoint-internal.h>
-#include <ust/tracectl.h>
-#include <ust/clock.h>
-#include "tracer.h"
-#include "usterr_signal_safe.h"
-#include "ustcomm.h"
-#include "buffers.h"
-#include "marker-control.h"
-
-/* This should only be accessed by the constructor, before the creation
- * of the listener, and then only by the listener.
- */
-s64 pidunique = -1LL;
-
-/* The process pid is used to detect a non-traceable fork
- * and allow the non-traceable fork to be ignored
- * by destructor sequences in libust
- */
-static pid_t processpid = 0;
-
-static struct ustcomm_header _receive_header;
-static struct ustcomm_header *receive_header = &_receive_header;
-static char receive_buffer[USTCOMM_BUFFER_SIZE];
-static char send_buffer[USTCOMM_BUFFER_SIZE];
-
-static int epoll_fd;
-
-/*
- * Listener thread data vs fork() protection mechanism. Ensures that no listener
- * thread mutexes and data structures are being concurrently modified or held by
- * other threads when fork() is executed.
- */
-static pthread_mutex_t listener_thread_data_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-/* Mutex protecting listen_sock. Nests inside listener_thread_data_mutex. */
-static pthread_mutex_t listen_sock_mutex = PTHREAD_MUTEX_INITIALIZER;
-static struct ustcomm_sock *listen_sock;
-
-extern struct chan_info_struct chan_infos[];
-
-static struct cds_list_head ust_socks = CDS_LIST_HEAD_INIT(ust_socks);
-
-/* volatile because shared between the listener and the main thread */
-int buffers_to_export = 0;
-
-int ust_clock_source;
-
-static long long make_pidunique(void)
-{
- s64 retval;
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
-
- retval = tv.tv_sec;
- retval <<= 32;
- retval |= tv.tv_usec;
-
- return retval;
-}
-
-static void print_ust_marker(FILE *fp)
-{
- struct ust_marker_iter iter;
-
- ust_marker_iter_reset(&iter);
- ust_marker_iter_start(&iter);
-
- while (iter.ust_marker) {
- fprintf(fp, "ust_marker: %s/%s %d \"%s\" %p\n",
- (*iter.ust_marker)->channel,
- (*iter.ust_marker)->name,
- (int)(*iter.ust_marker)->state,
- (*iter.ust_marker)->format,
- NULL); /*
- * location is null for now, will be added
- * to a different table.
- */
- ust_marker_iter_next(&iter);
- }
- ust_marker_iter_stop(&iter);
-}
-
-static void print_trace_events(FILE *fp)
-{
- struct trace_event_iter iter;
-
- trace_event_iter_reset(&iter);
- trace_event_iter_start(&iter);
-
- while (iter.trace_event) {
- fprintf(fp, "trace_event: %s\n", (*iter.trace_event)->name);
- trace_event_iter_next(&iter);
- }
- trace_event_iter_stop(&iter);
-}
-
-static int connect_ustconsumer(void)
-{
- int result, fd;
- char default_daemon_path[] = SOCK_DIR "/ustconsumer";
- char *explicit_daemon_path, *daemon_path;
-
- explicit_daemon_path = getenv("UST_DAEMON_SOCKET");
- if (explicit_daemon_path) {
- daemon_path = explicit_daemon_path;
- } else {
- daemon_path = default_daemon_path;
- }
-
- DBG("Connecting to daemon_path %s", daemon_path);
-
- result = ustcomm_connect_path(daemon_path, &fd);
- if (result < 0) {
- WARN("connect_ustconsumer failed, daemon_path: %s",
- daemon_path);
- return result;
- }
-
- return fd;
-}
-
-
-static void request_buffer_consumer(int sock,
- const char *trace,
- const char *channel,
- int cpu)
-{
- struct ustcomm_header send_header, recv_header;
- struct ustcomm_buffer_info buf_inf;
- int result = 0;
-
- result = ustcomm_pack_buffer_info(&send_header,
- &buf_inf,
- trace,
- channel,
- cpu);
-
- if (result < 0) {
- ERR("failed to pack buffer info message %s_%d",
- channel, cpu);
- return;
- }
-
- buf_inf.pid = getpid();
- send_header.command = CONSUME_BUFFER;
-
- result = ustcomm_req(sock, &send_header, (char *) &buf_inf,
- &recv_header, NULL);
- if (result <= 0) {
- PERROR("request for buffer consumer failed, is the daemon online?");
- }
-
- return;
-}
-
-/* Ask the daemon to collect a trace called trace_name and being
- * produced by this pid.
- *
- * The trace must be at least allocated. (It can also be started.)
- * This is because _ltt_trace_find is used.
- */
-
-static void inform_consumer_daemon(const char *trace_name)
-{
- int sock, i,j;
- struct ust_trace *trace;
- const char *ch_name;
-
- sock = connect_ustconsumer();
- if (sock < 0) {
- return;
- }
-
- DBG("Connected to ustconsumer");
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find(trace_name);
- if (trace == NULL) {
- WARN("inform_consumer_daemon: could not find trace \"%s\"; it is probably already destroyed", trace_name);
- goto unlock_traces;
- }
-
- for (i=0; i < trace->nr_channels; i++) {
- if (trace->channels[i].request_collection) {
- /* iterate on all cpus */
- for (j=0; j<trace->channels[i].n_cpus; j++) {
- ch_name = trace->channels[i].channel_name;
- request_buffer_consumer(sock, trace_name,
- ch_name, j);
- CMM_STORE_SHARED(buffers_to_export,
- CMM_LOAD_SHARED(buffers_to_export)+1);
- }
- }
- }
-
-unlock_traces:
- ltt_unlock_traces();
-
- close(sock);
-}
-
-static struct ust_channel *find_channel(const char *ch_name,
- struct ust_trace *trace)
-{
- int i;
-
- for (i=0; i<trace->nr_channels; i++) {
- if (!strcmp(trace->channels[i].channel_name, ch_name)) {
- return &trace->channels[i];
- }
- }
-
- return NULL;
-}
-
-static int get_buffer_shmid_pipe_fd(const char *trace_name, const char *ch_name,
- int ch_cpu,
- int *buf_shmid,
- int *buf_struct_shmid,
- int *buf_pipe_fd)
-{
- struct ust_trace *trace;
- struct ust_channel *channel;
- struct ust_buffer *buf;
-
- DBG("get_buffer_shmid_pipe_fd");
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
- ltt_unlock_traces();
-
- if (trace == NULL) {
- ERR("cannot find trace!");
- return -ENODATA;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- ERR("cannot find channel %s!", ch_name);
- return -ENODATA;
- }
-
- buf = channel->buf[ch_cpu];
-
- *buf_shmid = buf->shmid;
- *buf_struct_shmid = channel->buf_struct_shmids[ch_cpu];
- *buf_pipe_fd = buf->data_ready_fd_read;
-
- return 0;
-}
-
-static int get_subbuf_num_size(const char *trace_name, const char *ch_name,
- int *num, int *size)
-{
- struct ust_trace *trace;
- struct ust_channel *channel;
-
- DBG("get_subbuf_size");
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
- ltt_unlock_traces();
-
- if (!trace) {
- ERR("cannot find trace!");
- return -ENODATA;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- ERR("unable to find channel");
- return -ENODATA;
- }
-
- *num = channel->subbuf_cnt;
- *size = channel->subbuf_size;
-
- return 0;
-}
-
-/* Return the power of two which is equal or higher to v */
-
-static unsigned int pow2_higher_or_eq(unsigned int v)
-{
- int hb = fls(v);
- int retval = 1<<(hb-1);
-
- if (v-retval == 0)
- return retval;
- else
- return retval<<1;
-}
-
-static int set_subbuf_size(const char *trace_name, const char *ch_name,
- unsigned int size)
-{
- unsigned int power;
- int retval = 0;
- struct ust_trace *trace;
- struct ust_channel *channel;
-
- DBG("set_subbuf_size");
-
- power = pow2_higher_or_eq(size);
- power = max_t(unsigned int, 2u, power);
- if (power != size) {
- WARN("using the next power of two for buffer size = %u\n", power);
- }
-
- ltt_lock_traces();
- trace = _ltt_trace_find_setup(trace_name);
- if (trace == NULL) {
- ERR("cannot find trace!");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- ERR("unable to find channel");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- channel->subbuf_size = power;
- DBG("the set_subbuf_size for the requested channel is %zu", channel->subbuf_size);
-
-unlock_traces:
- ltt_unlock_traces();
-
- return retval;
-}
-
-static int set_subbuf_num(const char *trace_name, const char *ch_name,
- unsigned int num)
-{
- struct ust_trace *trace;
- struct ust_channel *channel;
- int retval = 0;
-
- DBG("set_subbuf_num");
-
- if (num < 2) {
- ERR("subbuffer count should be greater than 2");
- return -EINVAL;
- }
-
- ltt_lock_traces();
- trace = _ltt_trace_find_setup(trace_name);
- if (trace == NULL) {
- ERR("cannot find trace!");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- ERR("unable to find channel");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- channel->subbuf_cnt = num;
- DBG("the set_subbuf_cnt for the requested channel is %u", channel->subbuf_cnt);
-
-unlock_traces:
- ltt_unlock_traces();
- return retval;
-}
-
-static int get_subbuffer(const char *trace_name, const char *ch_name,
- int ch_cpu, long *consumed_old)
-{
- int retval = 0;
- struct ust_trace *trace;
- struct ust_channel *channel;
- struct ust_buffer *buf;
-
- DBG("get_subbuf");
-
- *consumed_old = 0;
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
-
- if (!trace) {
- DBG("Cannot find trace. It was likely destroyed by the user.");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- ERR("unable to find channel");
- retval = -ENODATA;
- goto unlock_traces;
- }
-
- buf = channel->buf[ch_cpu];
-
- retval = ust_buffers_get_subbuf(buf, consumed_old);
- if (retval < 0) {
- WARN("missed buffer?");
- }
-
-unlock_traces:
- ltt_unlock_traces();
-
- return retval;
-}
-
-
-static int notify_buffer_mapped(const char *trace_name,
- const char *ch_name,
- int ch_cpu)
-{
- int retval = 0;
- struct ust_trace *trace;
- struct ust_channel *channel;
- struct ust_buffer *buf;
-
- DBG("get_buffer_fd");
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
-
- if (!trace) {
- retval = -ENODATA;
- DBG("Cannot find trace. It was likely destroyed by the user.");
- goto unlock_traces;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- retval = -ENODATA;
- ERR("unable to find channel");
- goto unlock_traces;
- }
-
- buf = channel->buf[ch_cpu];
-
- /* Being here is the proof the daemon has mapped the buffer in its
- * memory. We may now decrement buffers_to_export.
- */
- if (uatomic_read(&buf->consumed) == 0) {
- DBG("decrementing buffers_to_export");
- CMM_STORE_SHARED(buffers_to_export, CMM_LOAD_SHARED(buffers_to_export)-1);
- }
-
-unlock_traces:
- ltt_unlock_traces();
-
- return retval;
-}
-
-static int put_subbuffer(const char *trace_name, const char *ch_name,
- int ch_cpu, long consumed_old)
-{
- int retval = 0;
- struct ust_trace *trace;
- struct ust_channel *channel;
- struct ust_buffer *buf;
-
- DBG("put_subbuf");
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
-
- if (!trace) {
- retval = -ENODATA;
- DBG("Cannot find trace. It was likely destroyed by the user.");
- goto unlock_traces;
- }
-
- channel = find_channel(ch_name, trace);
- if (!channel) {
- retval = -ENODATA;
- ERR("unable to find channel");
- goto unlock_traces;
- }
-
- buf = channel->buf[ch_cpu];
-
- retval = ust_buffers_put_subbuf(buf, consumed_old);
- if (retval < 0) {
- WARN("ust_buffers_put_subbuf: error (subbuf=%s_%d)",
- ch_name, ch_cpu);
- } else {
- DBG("ust_buffers_put_subbuf: success (subbuf=%s_%d)",
- ch_name, ch_cpu);
- }
-
-unlock_traces:
- ltt_unlock_traces();
-
- return retval;
-}
-
-static void release_listener_mutex(void *ptr)
-{
- pthread_mutex_unlock(&listener_thread_data_mutex);
-}
-
-static void listener_cleanup(void *ptr)
-{
- pthread_mutex_lock(&listen_sock_mutex);
- if (listen_sock) {
- ustcomm_del_named_sock(listen_sock, 0);
- listen_sock = NULL;
- }
- pthread_mutex_unlock(&listen_sock_mutex);
-}
-
-static int force_subbuf_switch(const char *trace_name)
-{
- struct ust_trace *trace;
- int i, j, retval = 0;
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
- if (!trace) {
- retval = -ENODATA;
- DBG("Cannot find trace. It was likely destroyed by the user.");
- goto unlock_traces;
- }
-
- for (i = 0; i < trace->nr_channels; i++) {
- for (j = 0; j < trace->channels[i].n_cpus; j++) {
- ltt_force_switch(trace->channels[i].buf[j],
- FORCE_FLUSH);
- }
- }
-
-unlock_traces:
- ltt_unlock_traces();
-
- return retval;
-}
-
-static int process_trace_cmd(int command, char *trace_name)
-{
- int result;
- char trace_type[] = "ustrelay";
-
- switch(command) {
- case START:
- /* start is an operation that setups the trace, allocates it and starts it */
- result = ltt_trace_setup(trace_name);
- if (result < 0) {
- ERR("ltt_trace_setup failed");
- return result;
- }
-
- result = ltt_trace_set_type(trace_name, trace_type);
- if (result < 0) {
- ERR("ltt_trace_set_type failed");
- return result;
- }
-
- result = ltt_trace_alloc(trace_name);
- if (result < 0) {
- ERR("ltt_trace_alloc failed");
- return result;
- }
-
- inform_consumer_daemon(trace_name);
-
- result = ltt_trace_start(trace_name);
- if (result < 0) {
- ERR("ltt_trace_start failed");
- return result;
- }
-
- return 0;
- case SETUP_TRACE:
- DBG("trace setup");
-
- result = ltt_trace_setup(trace_name);
- if (result < 0) {
- ERR("ltt_trace_setup failed");
- return result;
- }
-
- result = ltt_trace_set_type(trace_name, trace_type);
- if (result < 0) {
- ERR("ltt_trace_set_type failed");
- return result;
- }
-
- return 0;
- case ALLOC_TRACE:
- DBG("trace alloc");
-
- result = ltt_trace_alloc(trace_name);
- if (result < 0) {
- ERR("ltt_trace_alloc failed");
- return result;
- }
- inform_consumer_daemon(trace_name);
-
- return 0;
-
- case CREATE_TRACE:
- DBG("trace create");
-
- result = ltt_trace_setup(trace_name);
- if (result < 0) {
- ERR("ltt_trace_setup failed");
- return result;
- }
-
- result = ltt_trace_set_type(trace_name, trace_type);
- if (result < 0) {
- ERR("ltt_trace_set_type failed");
- return result;
- }
-
- return 0;
- case START_TRACE:
- DBG("trace start");
-
- result = ltt_trace_alloc(trace_name);
- if (result < 0) {
- ERR("ltt_trace_alloc failed");
- return result;
- }
- if (!result) {
- inform_consumer_daemon(trace_name);
- }
-
- result = ltt_trace_start(trace_name);
- if (result < 0) {
- ERR("ltt_trace_start failed");
- return result;
- }
-
- return 0;
- case STOP_TRACE:
- DBG("trace stop");
-
- result = ltt_trace_stop(trace_name);
- if (result < 0) {
- ERR("ltt_trace_stop failed");
- return result;
- }
-
- return 0;
- case DESTROY_TRACE:
- DBG("trace destroy");
-
- result = ltt_trace_destroy(trace_name, 0);
- if (result < 0) {
- ERR("ltt_trace_destroy failed");
- return result;
- }
- return 0;
- case FORCE_SUBBUF_SWITCH:
- DBG("force switch");
-
- result = force_subbuf_switch(trace_name);
- if (result < 0) {
- ERR("force_subbuf_switch failed");
- return result;
- }
- return 0;
- }
-
- return 0;
-}
-
-
-static void process_channel_cmd(int sock, int command,
- struct ustcomm_channel_info *ch_inf)
-{
- struct ustcomm_header _reply_header;
- struct ustcomm_header *reply_header = &_reply_header;
- struct ustcomm_channel_info *reply_msg =
- (struct ustcomm_channel_info *)send_buffer;
- int result, offset = 0, num, size;
-
- memset(reply_header, 0, sizeof(*reply_header));
-
- switch (command) {
- case GET_SUBBUF_NUM_SIZE:
- result = get_subbuf_num_size(ch_inf->trace,
- ch_inf->channel,
- &num, &size);
- if (result < 0) {
- reply_header->result = result;
- break;
- }
-
- reply_msg->channel = USTCOMM_POISON_PTR;
- reply_msg->subbuf_num = num;
- reply_msg->subbuf_size = size;
-
-
- reply_header->size = COMPUTE_MSG_SIZE(reply_msg, offset);
-
- break;
- case SET_SUBBUF_NUM:
- reply_header->result = set_subbuf_num(ch_inf->trace,
- ch_inf->channel,
- ch_inf->subbuf_num);
-
- break;
- case SET_SUBBUF_SIZE:
- reply_header->result = set_subbuf_size(ch_inf->trace,
- ch_inf->channel,
- ch_inf->subbuf_size);
-
-
- break;
- }
- if (ustcomm_send(sock, reply_header, (char *)reply_msg) < 0) {
- ERR("ustcomm_send failed");
- }
-}
-
-static void process_buffer_cmd(int sock, int command,
- struct ustcomm_buffer_info *buf_inf)
-{
- struct ustcomm_header _reply_header;
- struct ustcomm_header *reply_header = &_reply_header;
- struct ustcomm_buffer_info *reply_msg =
- (struct ustcomm_buffer_info *)send_buffer;
- int result, offset = 0, buf_shmid, buf_struct_shmid, buf_pipe_fd;
- long consumed_old;
-
- memset(reply_header, 0, sizeof(*reply_header));
-
- switch (command) {
- case GET_BUF_SHMID_PIPE_FD:
- result = get_buffer_shmid_pipe_fd(buf_inf->trace,
- buf_inf->channel,
- buf_inf->ch_cpu,
- &buf_shmid,
- &buf_struct_shmid,
- &buf_pipe_fd);
- if (result < 0) {
- reply_header->result = result;
- break;
- }
-
- reply_msg->channel = USTCOMM_POISON_PTR;
- reply_msg->buf_shmid = buf_shmid;
- reply_msg->buf_struct_shmid = buf_struct_shmid;
-
- reply_header->size = COMPUTE_MSG_SIZE(reply_msg, offset);
- reply_header->fd_included = 1;
-
- if (ustcomm_send_fd(sock, reply_header, (char *)reply_msg,
- &buf_pipe_fd) < 0) {
- ERR("ustcomm_send failed");
- }
- return;
-
- case NOTIFY_BUF_MAPPED:
- reply_header->result =
- notify_buffer_mapped(buf_inf->trace,
- buf_inf->channel,
- buf_inf->ch_cpu);
- break;
- case GET_SUBBUFFER:
- result = get_subbuffer(buf_inf->trace, buf_inf->channel,
- buf_inf->ch_cpu, &consumed_old);
- if (result < 0) {
- reply_header->result = result;
- break;
- }
-
- reply_msg->channel = USTCOMM_POISON_PTR;
- reply_msg->consumed_old = consumed_old;
-
- reply_header->size = COMPUTE_MSG_SIZE(reply_msg, offset);
-
- break;
- case PUT_SUBBUFFER:
- result = put_subbuffer(buf_inf->trace, buf_inf->channel,
- buf_inf->ch_cpu,
- buf_inf->consumed_old);
- reply_header->result = result;
-
- break;
- }
-
- if (ustcomm_send(sock, reply_header, (char *)reply_msg) < 0) {
- ERR("ustcomm_send failed");
- }
-
-}
-
-static void process_ust_marker_cmd(int sock, int command,
- struct ustcomm_ust_marker_info *ust_marker_inf)
-{
- struct ustcomm_header _reply_header;
- struct ustcomm_header *reply_header = &_reply_header;
- int result = 0;
-
- memset(reply_header, 0, sizeof(*reply_header));
-
- switch(command) {
- case ENABLE_MARKER:
-
- result = ltt_ust_marker_connect(ust_marker_inf->channel,
- ust_marker_inf->ust_marker,
- "default");
- if (result < 0) {
- WARN("could not enable ust_marker; channel=%s,"
- " name=%s",
- ust_marker_inf->channel,
- ust_marker_inf->ust_marker);
-
- }
- break;
- case DISABLE_MARKER:
- result = ltt_ust_marker_disconnect(ust_marker_inf->channel,
- ust_marker_inf->ust_marker,
- "default");
- if (result < 0) {
- WARN("could not disable ust_marker; channel=%s,"
- " name=%s",
- ust_marker_inf->channel,
- ust_marker_inf->ust_marker);
- }
- break;
- }
-
- reply_header->result = result;
-
- if (ustcomm_send(sock, reply_header, NULL) < 0) {
- ERR("ustcomm_send failed");
- }
-
-}
-static void process_client_cmd(struct ustcomm_header *recv_header,
- char *recv_buf, int sock)
-{
- int result;
- struct ustcomm_header _reply_header;
- struct ustcomm_header *reply_header = &_reply_header;
- char *send_buf = send_buffer;
-
- memset(reply_header, 0, sizeof(*reply_header));
- memset(send_buf, 0, sizeof(send_buffer));
-
- switch(recv_header->command) {
- case GET_SUBBUF_NUM_SIZE:
- case SET_SUBBUF_NUM:
- case SET_SUBBUF_SIZE:
- {
- struct ustcomm_channel_info *ch_inf;
- ch_inf = (struct ustcomm_channel_info *)recv_buf;
- result = ustcomm_unpack_channel_info(ch_inf);
- if (result < 0) {
- ERR("couldn't unpack channel info");
- reply_header->result = -EINVAL;
- goto send_response;
- }
- process_channel_cmd(sock, recv_header->command, ch_inf);
- return;
- }
- case GET_BUF_SHMID_PIPE_FD:
- case NOTIFY_BUF_MAPPED:
- case GET_SUBBUFFER:
- case PUT_SUBBUFFER:
- {
- struct ustcomm_buffer_info *buf_inf;
- buf_inf = (struct ustcomm_buffer_info *)recv_buf;
- result = ustcomm_unpack_buffer_info(buf_inf);
- if (result < 0) {
- ERR("couldn't unpack buffer info");
- reply_header->result = -EINVAL;
- goto send_response;
- }
- process_buffer_cmd(sock, recv_header->command, buf_inf);
- return;
- }
- case ENABLE_MARKER:
- case DISABLE_MARKER:
- {
- struct ustcomm_ust_marker_info *ust_marker_inf;
- ust_marker_inf = (struct ustcomm_ust_marker_info *)recv_buf;
- result = ustcomm_unpack_ust_marker_info(ust_marker_inf);
- if (result < 0) {
- ERR("couldn't unpack ust_marker info");
- reply_header->result = -EINVAL;
- goto send_response;
- }
- process_ust_marker_cmd(sock, recv_header->command, ust_marker_inf);
- return;
- }
- case LIST_MARKERS:
- {
- char *ptr;
- size_t size;
- FILE *fp;
-
- fp = open_memstream(&ptr, &size);
- if (fp == NULL) {
- ERR("opening memstream failed");
- return;
- }
- print_ust_marker(fp);
- fclose(fp);
-
- reply_header->size = size + 1; /* Include final \0 */
-
- result = ustcomm_send(sock, reply_header, ptr);
-
- free(ptr);
-
- if (result < 0) {
- PERROR("failed to send ust_marker list");
- }
-
- break;
- }
- case LIST_TRACE_EVENTS:
- {
- char *ptr;
- size_t size;
- FILE *fp;
-
- fp = open_memstream(&ptr, &size);
- if (fp == NULL) {
- ERR("opening memstream failed");
- return;
- }
- print_trace_events(fp);
- fclose(fp);
-
- reply_header->size = size + 1; /* Include final \0 */
-
- result = ustcomm_send(sock, reply_header, ptr);
-
- free(ptr);
-
- if (result < 0) {
- ERR("list_trace_events failed");
- return;
- }
-
- break;
- }
- case LOAD_PROBE_LIB:
- {
- char *libfile;
-
- /* FIXME: No functionality at all... */
- libfile = recv_buf;
-
- DBG("load_probe_lib loading %s", libfile);
-
- break;
- }
- case GET_PIDUNIQUE:
- {
- struct ustcomm_pidunique *pid_msg;
- pid_msg = (struct ustcomm_pidunique *)send_buf;
-
- pid_msg->pidunique = pidunique;
- reply_header->size = sizeof(pid_msg);
-
- goto send_response;
-
- }
- case GET_SOCK_PATH:
- {
- struct ustcomm_single_field *sock_msg;
- char *sock_path_env;
-
- sock_msg = (struct ustcomm_single_field *)send_buf;
-
- sock_path_env = getenv("UST_DAEMON_SOCKET");
-
- if (!sock_path_env) {
- result = ustcomm_pack_single_field(reply_header,
- sock_msg,
- SOCK_DIR "/ustconsumer");
-
- } else {
- result = ustcomm_pack_single_field(reply_header,
- sock_msg,
- sock_path_env);
- }
- reply_header->result = result;
-
- goto send_response;
- }
- case SET_SOCK_PATH:
- {
- struct ustcomm_single_field *sock_msg;
- sock_msg = (struct ustcomm_single_field *)recv_buf;
- result = ustcomm_unpack_single_field(sock_msg);
- if (result < 0) {
- reply_header->result = -EINVAL;
- goto send_response;
- }
-
- reply_header->result = setenv("UST_DAEMON_SOCKET",
- sock_msg->field, 1);
-
- goto send_response;
- }
- case START:
- case SETUP_TRACE:
- case ALLOC_TRACE:
- case CREATE_TRACE:
- case START_TRACE:
- case STOP_TRACE:
- case DESTROY_TRACE:
- case FORCE_SUBBUF_SWITCH:
- {
- struct ustcomm_single_field *trace_inf =
- (struct ustcomm_single_field *)recv_buf;
-
- result = ustcomm_unpack_single_field(trace_inf);
- if (result < 0) {
- ERR("couldn't unpack trace info");
- reply_header->result = -EINVAL;
- goto send_response;
- }
-
- reply_header->result =
- process_trace_cmd(recv_header->command,
- trace_inf->field);
- goto send_response;
-
- }
- default:
- reply_header->result = -EINVAL;
-
- goto send_response;
- }
-
- return;
-
-send_response:
- ustcomm_send(sock, reply_header, send_buf);
-}
-
-#define MAX_EVENTS 10
-
-void *listener_main(void *p)
-{
- struct ustcomm_sock *epoll_sock;
- struct epoll_event events[MAX_EVENTS];
- struct sockaddr addr;
- int accept_fd, nfds, result, i, addr_size;
-
- DBG("LISTENER");
-
- pthread_cleanup_push(listener_cleanup, NULL);
-
- for(;;) {
- nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
- if (nfds == -1) {
- PERROR("listener_main: epoll_wait failed");
- continue;
- }
-
- for (i = 0; i < nfds; i++) {
- pthread_mutex_lock(&listener_thread_data_mutex);
- pthread_cleanup_push(release_listener_mutex, NULL);
- epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
- if (epoll_sock == listen_sock) {
- addr_size = sizeof(struct sockaddr);
- accept_fd = accept(epoll_sock->fd,
- &addr,
- (socklen_t *)&addr_size);
- if (accept_fd == -1) {
- PERROR("listener_main: accept failed");
- continue;
- }
- ustcomm_init_sock(accept_fd, epoll_fd,
- &ust_socks);
- } else {
- memset(receive_header, 0,
- sizeof(*receive_header));
- memset(receive_buffer, 0,
- sizeof(receive_buffer));
- result = ustcomm_recv(epoll_sock->fd,
- receive_header,
- receive_buffer);
- if (result == 0) {
- ustcomm_del_sock(epoll_sock, 0);
- } else {
- process_client_cmd(receive_header,
- receive_buffer,
- epoll_sock->fd);
- }
- }
- pthread_cleanup_pop(1); /* release listener mutex */
- }
- }
-
- pthread_cleanup_pop(1);
-}
-
-/* These should only be accessed in the parent thread,
- * not the listener.
- */
-static volatile sig_atomic_t have_listener = 0;
-static pthread_t listener_thread;
-
-void create_listener(void)
-{
- int result;
- sigset_t sig_all_blocked;
- sigset_t orig_parent_mask;
-
- if (have_listener) {
- WARN("not creating listener because we already had one");
- return;
- }
-
- /* A new thread created by pthread_create inherits the signal mask
- * from the parent. To avoid any signal being received by the
- * listener thread, we block all signals temporarily in the parent,
- * while we create the listener thread.
- */
-
- sigfillset(&sig_all_blocked);
-
- result = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_parent_mask);
- if (result) {
- PERROR("pthread_sigmask: %s", strerror(result));
- }
-
- result = pthread_create(&listener_thread, NULL, listener_main, NULL);
- if (result == -1) {
- PERROR("pthread_create");
- }
-
- /* Restore original signal mask in parent */
- result = pthread_sigmask(SIG_SETMASK, &orig_parent_mask, NULL);
- if (result) {
- PERROR("pthread_sigmask: %s", strerror(result));
- } else {
- have_listener = 1;
- }
-}
-
-#define AUTOPROBE_DISABLED 0
-#define AUTOPROBE_ENABLE_ALL 1
-#define AUTOPROBE_ENABLE_REGEX 2
-static int autoprobe_method = AUTOPROBE_DISABLED;
-static regex_t autoprobe_regex;
-
-static void auto_probe_connect(struct ust_marker *m)
-{
- int result;
-
- char* concat_name = NULL;
- const char *probe_name = "default";
-
- if (autoprobe_method == AUTOPROBE_DISABLED) {
- return;
- } else if (autoprobe_method == AUTOPROBE_ENABLE_REGEX) {
- result = asprintf(&concat_name, "%s/%s", m->channel, m->name);
- if (result == -1) {
- ERR("auto_probe_connect: asprintf failed (ust_marker %s/%s)",
- m->channel, m->name);
- return;
- }
- if (regexec(&autoprobe_regex, concat_name, 0, NULL, 0)) {
- free(concat_name);
- return;
- }
- free(concat_name);
- }
-
- result = ltt_ust_marker_connect(m->channel, m->name, probe_name);
- if (result && result != -EEXIST)
- ERR("ltt_ust_marker_connect (ust_marker = %s/%s, errno = %d)", m->channel, m->name, -result);
-
- DBG("auto connected ust_marker %s (addr: %p) %s to probe default", m->channel, m, m->name);
-
-}
-
-static struct ustcomm_sock * init_app_socket(int epoll_fd)
-{
- char *dir_name, *sock_name;
- int result;
- struct ustcomm_sock *sock = NULL;
- time_t mtime;
-
- dir_name = ustcomm_user_sock_dir();
- if (!dir_name)
- return NULL;
-
- mtime = ustcomm_pid_st_mtime(getpid());
- if (!mtime) {
- goto free_dir_name;
- }
-
- result = asprintf(&sock_name, "%s/%d.%ld", dir_name,
- (int) getpid(), (long) mtime);
- if (result < 0) {
- ERR("string overflow allocating socket name, "
- "UST thread bailing");
- goto free_dir_name;
- }
-
- result = ensure_dir_exists(dir_name, S_IRWXU);
- if (result == -1) {
- ERR("Unable to create socket directory %s, UST thread bailing",
- dir_name);
- goto free_sock_name;
- }
-
- sock = ustcomm_init_named_socket(sock_name, epoll_fd);
- if (!sock) {
- ERR("Error initializing named socket (%s). Check that directory"
- "exists and that it is writable. UST thread bailing", sock_name);
- goto free_sock_name;
- }
-
-free_sock_name:
- free(sock_name);
-free_dir_name:
- free(dir_name);
-
- return sock;
-}
-
-static void __attribute__((constructor)) init()
-{
- struct timespec ts;
- int result;
- char* autoprobe_val = NULL;
- char* subbuffer_size_val = NULL;
- char* subbuffer_count_val = NULL;
- unsigned int subbuffer_size;
- unsigned int subbuffer_count;
- unsigned int power;
-
- /* Assign the pidunique, to be able to differentiate the processes with same
- * pid, (before and after an exec).
- */
- pidunique = make_pidunique();
- processpid = getpid();
-
- DBG("Tracectl constructor");
-
- /* Set up epoll */
- epoll_fd = epoll_create(MAX_EVENTS);
- if (epoll_fd == -1) {
- ERR("epoll_create failed, tracing shutting down");
- return;
- }
-
- /* Create the socket */
- listen_sock = init_app_socket(epoll_fd);
- if (!listen_sock) {
- ERR("failed to create application socket,"
- " tracing shutting down");
- return;
- }
-
- create_listener();
-
- /* Get clock the clock source type */
-
- /* Default clock source */
- ust_clock_source = CLOCK_TRACE;
- if (clock_gettime(ust_clock_source, &ts) != 0) {
- ust_clock_source = CLOCK_MONOTONIC;
- DBG("UST traces will not be synchronized with LTTng traces");
- }
-
- if (getenv("UST_TRACE") || getenv("UST_AUTOPROBE")) {
- /* Ensure ust_marker control is initialized */
- init_ust_marker_control();
- }
-
- autoprobe_val = getenv("UST_AUTOPROBE");
- if (autoprobe_val) {
- struct ust_marker_iter iter;
-
- DBG("Autoprobe enabled.");
-
- /* first, set the callback that will connect the
- * probe on new ust_marker
- */
- if (autoprobe_val[0] == '/') {
- result = regcomp(&autoprobe_regex, autoprobe_val+1, 0);
- if (result) {
- char regexerr[150];
-
- regerror(result, &autoprobe_regex, regexerr, sizeof(regexerr));
- ERR("cannot parse regex %s (%s), will ignore UST_AUTOPROBE", autoprobe_val, regexerr);
- /* don't crash the application just for this */
- } else {
- autoprobe_method = AUTOPROBE_ENABLE_REGEX;
- }
- } else {
- /* just enable all instrumentation */
- autoprobe_method = AUTOPROBE_ENABLE_ALL;
- }
-
- ust_marker_set_new_ust_marker_cb(auto_probe_connect);
-
- /* Now, connect the probes that were already registered. */
- ust_marker_iter_reset(&iter);
- ust_marker_iter_start(&iter);
-
- DBG("now iterating on ust_marker already registered");
- while (iter.ust_marker) {
- DBG("now iterating on ust_marker %s", (*iter.ust_marker)->name);
- auto_probe_connect(*iter.ust_marker);
- ust_marker_iter_next(&iter);
- }
- ust_marker_iter_stop(&iter);
- }
-
- if (getenv("UST_OVERWRITE")) {
- int val = atoi(getenv("UST_OVERWRITE"));
- if (val == 0 || val == 1) {
- CMM_STORE_SHARED(ust_channels_overwrite_by_default, val);
- } else {
- WARN("invalid value for UST_OVERWRITE");
- }
- }
-
- if (getenv("UST_AUTOCOLLECT")) {
- int val = atoi(getenv("UST_AUTOCOLLECT"));
- if (val == 0 || val == 1) {
- CMM_STORE_SHARED(ust_channels_request_collection_by_default, val);
- } else {
- WARN("invalid value for UST_AUTOCOLLECT");
- }
- }
-
- subbuffer_size_val = getenv("UST_SUBBUF_SIZE");
- if (subbuffer_size_val) {
- sscanf(subbuffer_size_val, "%u", &subbuffer_size);
- power = pow2_higher_or_eq(subbuffer_size);
- if (power != subbuffer_size)
- WARN("using the next power of two for buffer size = %u\n", power);
- chan_infos[LTT_CHANNEL_UST].def_subbufsize = power;
- }
-
- subbuffer_count_val = getenv("UST_SUBBUF_NUM");
- if (subbuffer_count_val) {
- sscanf(subbuffer_count_val, "%u", &subbuffer_count);
- if (subbuffer_count < 2)
- subbuffer_count = 2;
- chan_infos[LTT_CHANNEL_UST].def_subbufcount = subbuffer_count;
- }
-
- if (getenv("UST_TRACE")) {
- char trace_name[] = "auto";
- char trace_type[] = "ustrelay";
-
- DBG("starting early tracing");
-
- /* Ensure buffers are initialized, for the transport to be available.
- * We are about to set a trace type and it will fail without this.
- */
- init_ustrelay_transport();
-
- /* FIXME: When starting early tracing (here), depending on the
- * order of constructors, it is very well possible some ust_marker
- * sections are not yet registered. Because of this, some
- * channels may not be registered. Yet, we are about to ask the
- * daemon to collect the channels. Channels which are not yet
- * registered will not be collected.
- *
- * Currently, in LTTng, there is no way to add a channel after
- * trace start. The reason for this is that it induces complex
- * concurrency issues on the trace structures, which can only
- * be resolved using RCU. This has not been done yet. As a
- * workaround, we are forcing the registration of the "ust"
- * channel here. This is the only channel (apart from metadata)
- * that can be reliably used in early tracing.
- *
- * Non-early tracing does not have this problem and can use
- * arbitrary channel names.
- */
- ltt_channels_register("ust");
-
- result = ltt_trace_setup(trace_name);
- if (result < 0) {
- ERR("ltt_trace_setup failed");
- return;
- }
-
- result = ltt_trace_set_type(trace_name, trace_type);
- if (result < 0) {
- ERR("ltt_trace_set_type failed");
- return;
- }
-
- result = ltt_trace_alloc(trace_name);
- if (result < 0) {
- ERR("ltt_trace_alloc failed");
- return;
- }
-
- result = ltt_trace_start(trace_name);
- if (result < 0) {
- ERR("ltt_trace_start failed");
- return;
- }
-
- /* Do this after the trace is started in order to avoid creating confusion
- * if the trace fails to start. */
- inform_consumer_daemon(trace_name);
- }
-
- return;
-
- /* should decrementally destroy stuff if error */
-
-}
-
-/* This is only called if we terminate normally, not with an unhandled signal,
- * so we cannot rely on it. However, for now, LTTV requires that the header of
- * the last sub-buffer contain a valid end time for the trace. This is done
- * automatically only when the trace is properly stopped.
- *
- * If the traced program crashed, it is always possible to manually add the
- * right value in the header, or to open the trace in text mode.
- *
- * FIXME: Fix LTTV so it doesn't need this.
- */
-
-static void destroy_traces(void)
-{
- int result;
-
- /* if trace running, finish it */
-
- DBG("destructor stopping traces");
-
- result = ltt_trace_stop("auto");
- if (result == -1) {
- ERR("ltt_trace_stop error");
- }
-
- result = ltt_trace_destroy("auto", 0);
- if (result == -1) {
- ERR("ltt_trace_destroy error");
- }
-}
-
-static int trace_recording(void)
-{
- int retval = 0;
- struct ust_trace *trace;
-
- ltt_lock_traces();
-
- cds_list_for_each_entry(trace, <t_traces.head, list) {
- if (trace->active) {
- retval = 1;
- break;
- }
- }
-
- ltt_unlock_traces();
-
- return retval;
-}
-
-int restarting_usleep(useconds_t usecs)
-{
- struct timespec tv;
- int result;
-
- tv.tv_sec = 0;
- tv.tv_nsec = usecs * 1000;
-
- do {
- result = nanosleep(&tv, &tv);
- } while (result == -1 && errno == EINTR);
-
- return result;
-}
-
-static void stop_listener(void)
-{
- int result;
-
- if (!have_listener)
- return;
-
- result = pthread_cancel(listener_thread);
- if (result != 0) {
- ERR("pthread_cancel: %s", strerror(result));
- }
- result = pthread_join(listener_thread, NULL);
- if (result != 0) {
- ERR("pthread_join: %s", strerror(result));
- }
-}
-
-/* This destructor keeps the process alive for a few seconds in order
- * to leave time for ustconsumer to connect to its buffers. This is necessary
- * for programs whose execution is very short. It is also useful in all
- * programs when tracing is started close to the end of the program
- * execution.
- *
- * FIXME: For now, this only works for the first trace created in a
- * process.
- */
-
-static void __attribute__((destructor)) keepalive()
-{
- if (processpid != getpid()) {
- return;
- }
-
- if (trace_recording() && CMM_LOAD_SHARED(buffers_to_export)) {
- int total = 0;
- DBG("Keeping process alive for consumer daemon...");
- while (CMM_LOAD_SHARED(buffers_to_export)) {
- const int interv = 200000;
- restarting_usleep(interv);
- total += interv;
-
- if (total >= 3000000) {
- WARN("non-consumed buffers remaining after wait limit; not waiting anymore");
- break;
- }
- }
- DBG("Finally dying...");
- }
-
- destroy_traces();
-
- /* Ask the listener to stop and clean up. */
- stop_listener();
-}
-
-void ust_potential_exec(void)
-{
- ust_marker(potential_exec, UST_MARKER_NOARGS);
-
- DBG("test");
-
- keepalive();
-}
-
-/* Notify ust that there was a fork. This needs to be called inside
- * the new process, anytime a process whose memory is not shared with
- * the parent is created. If this function is not called, the events
- * of the new process will not be collected.
- *
- * Signals should be disabled before the fork and reenabled only after
- * this call in order to guarantee tracing is not started before ust_fork()
- * sanitizes the new process.
- */
-
-static void ust_fork(void)
-{
- struct ustcomm_sock *sock, *sock_tmp;
- struct ust_trace *trace, *trace_tmp;
- int result;
-
- /* FIXME: technically, the locks could have been taken before the fork */
- DBG("ust: forking");
-
- /* Get the pid of the new process */
- processpid = getpid();
-
- /*
- * FIXME: This could be prettier, we loop over the list twice and
- * following good locking practice should lock around the loop
- */
- cds_list_for_each_entry_safe(trace, trace_tmp, <t_traces.head, list) {
- ltt_trace_stop(trace->trace_name);
- }
-
- /* Delete all active connections, but leave them in the epoll set */
- cds_list_for_each_entry_safe(sock, sock_tmp, &ust_socks, list) {
- ustcomm_del_sock(sock, 1);
- }
-
- /*
- * FIXME: This could be prettier, we loop over the list twice and
- * following good locking practice should lock around the loop
- */
- cds_list_for_each_entry_safe(trace, trace_tmp, <t_traces.head, list) {
- ltt_trace_destroy(trace->trace_name, 1);
- }
-
- /* Clean up the listener socket and epoll, keeping the socket file */
- if (listen_sock) {
- ustcomm_del_named_sock(listen_sock, 1);
- listen_sock = NULL;
- }
- close(epoll_fd);
-
- /* Re-start the launch sequence */
- CMM_STORE_SHARED(buffers_to_export, 0);
- have_listener = 0;
-
- /* Set up epoll */
- epoll_fd = epoll_create(MAX_EVENTS);
- if (epoll_fd == -1) {
- ERR("epoll_create failed, tracing shutting down");
- return;
- }
-
- /* Create the socket */
- listen_sock = init_app_socket(epoll_fd);
- if (!listen_sock) {
- ERR("failed to create application socket,"
- " tracing shutting down");
- return;
- }
- create_listener();
- ltt_trace_setup("auto");
- result = ltt_trace_set_type("auto", "ustrelay");
- if (result < 0) {
- ERR("ltt_trace_set_type failed");
- return;
- }
-
- ltt_trace_alloc("auto");
- ltt_trace_start("auto");
- inform_consumer_daemon("auto");
-}
-
-void ust_before_fork(ust_fork_info_t *fork_info)
-{
- /* Disable signals. This is to avoid that the child
- * intervenes before it is properly setup for tracing. It is
- * safer to disable all signals, because then we know we are not
- * breaking anything by restoring the original mask.
- */
- sigset_t all_sigs;
- int result;
-
- /* FIXME:
- - only do this if tracing is active
- */
-
- /* Disable signals */
- sigfillset(&all_sigs);
- result = sigprocmask(SIG_BLOCK, &all_sigs, &fork_info->orig_sigs);
- if (result == -1) {
- PERROR("sigprocmask");
- return;
- }
-
- /*
- * Take the fork lock to make sure we are not in the middle of
- * something in the listener thread.
- */
- pthread_mutex_lock(&listener_thread_data_mutex);
- /*
- * Hold listen_sock_mutex to protect from listen_sock teardown.
- */
- pthread_mutex_lock(&listen_sock_mutex);
- rcu_bp_before_fork();
-}
-
-/* Don't call this function directly in a traced program */
-static void ust_after_fork_common(ust_fork_info_t *fork_info)
-{
- int result;
-
- pthread_mutex_unlock(&listen_sock_mutex);
- pthread_mutex_unlock(&listener_thread_data_mutex);
- /* Restore signals */
- result = sigprocmask(SIG_SETMASK, &fork_info->orig_sigs, NULL);
- if (result == -1) {
- PERROR("sigprocmask");
- return;
- }
-}
-
-void ust_after_fork_parent(ust_fork_info_t *fork_info)
-{
- rcu_bp_after_fork_parent();
- /* Release mutexes and reenable signals */
- ust_after_fork_common(fork_info);
-}
-
-void ust_after_fork_child(ust_fork_info_t *fork_info)
-{
- /* Release urcu mutexes */
- rcu_bp_after_fork_child();
-
- /* Sanitize the child */
- ust_fork();
-
- /* Release mutexes and reenable signals */
- ust_after_fork_common(fork_info);
-}
-
+++ /dev/null
-/*
- * tracer.c
- *
- * (C) Copyright 2005-2008 -
- * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- *
- * Inspired from LTT :
- * Karim Yaghmour (karim@opersys.com)
- * Tom Zanussi (zanussi@us.ibm.com)
- * Bob Wisniewski (bob@watson.ibm.com)
- * And from K42 :
- * Bob Wisniewski (bob@watson.ibm.com)
- *
- * Changelog:
- * 22/09/06, Move to the marker/probes mechanism.
- * 19/10/05, Complete lockless mechanism.
- * 27/05/05, Modular redesign and rewrite.
- */
-
-#include <urcu-bp.h>
-#include <urcu/rculist.h>
-
-#include <ust/clock.h>
-
-#include "tracercore.h"
-#include "tracer.h"
-#include "usterr_signal_safe.h"
-
-struct chan_info_struct chan_infos[] = {
- [LTT_CHANNEL_METADATA] = {
- LTT_METADATA_CHANNEL,
- LTT_DEFAULT_SUBBUF_SIZE_LOW,
- LTT_DEFAULT_N_SUBBUFS_LOW,
- },
- [LTT_CHANNEL_UST] = {
- LTT_UST_CHANNEL,
- LTT_DEFAULT_SUBBUF_SIZE_HIGH,
- LTT_DEFAULT_N_SUBBUFS_HIGH,
- },
-};
-
-static enum ltt_channels get_channel_type_from_name(const char *name)
-{
- int i;
-
- if (!name)
- return LTT_CHANNEL_UST;
-
- for (i = 0; i < ARRAY_SIZE(chan_infos); i++)
- if (chan_infos[i].name && !strcmp(name, chan_infos[i].name))
- return (enum ltt_channels)i;
-
- return LTT_CHANNEL_UST;
-}
-
-static CDS_LIST_HEAD(ltt_transport_list);
-/* transport mutex, nests inside traces mutex (ltt_lock_traces) */
-static DEFINE_MUTEX(ltt_transport_mutex);
-/**
- * ltt_transport_register - LTT transport registration
- * @transport: transport structure
- *
- * Registers a transport which can be used as output to extract the data out of
- * LTTng. The module calling this registration function must ensure that no
- * trap-inducing code will be executed by the transport functions. E.g.
- * vmalloc_sync_all() must be called between a vmalloc and the moment the memory
- * is made visible to the transport function. This registration acts as a
- * vmalloc_sync_all. Therefore, only if the module allocates virtual memory
- * after its registration must it synchronize the TLBs.
- */
-void ltt_transport_register(struct ltt_transport *transport)
-{
- pthread_mutex_lock(<t_transport_mutex);
- cds_list_add_tail(&transport->node, <t_transport_list);
- pthread_mutex_unlock(<t_transport_mutex);
-}
-
-/**
- * ltt_transport_unregister - LTT transport unregistration
- * @transport: transport structure
- */
-void ltt_transport_unregister(struct ltt_transport *transport)
-{
- pthread_mutex_lock(<t_transport_mutex);
- cds_list_del(&transport->node);
- pthread_mutex_unlock(<t_transport_mutex);
-}
-
-static inline int is_channel_overwrite(enum ltt_channels chan,
- enum trace_mode mode)
-{
- switch (mode) {
- case LTT_TRACE_NORMAL:
- return 0;
- case LTT_TRACE_FLIGHT:
- switch (chan) {
- case LTT_CHANNEL_METADATA:
- return 0;
- default:
- return 1;
- }
- case LTT_TRACE_HYBRID:
- switch (chan) {
- case LTT_CHANNEL_METADATA:
- return 0;
- default:
- return 1;
- }
- default:
- return 0;
- }
-}
-
-static void trace_async_wakeup(struct ust_trace *trace)
-{
- int i;
- struct ust_channel *chan;
-
- /* Must check each channel for pending read wakeup */
- for (i = 0; i < trace->nr_channels; i++) {
- chan = &trace->channels[i];
- if (chan->active)
- trace->ops->wakeup_channel(chan);
- }
-}
-
-/**
- * _ltt_trace_find - find a trace by given name.
- * trace_name: trace name
- *
- * Returns a pointer to the trace structure, NULL if not found.
- */
-struct ust_trace *_ltt_trace_find(const char *trace_name)
-{
- struct ust_trace *trace;
-
- cds_list_for_each_entry(trace, <t_traces.head, list)
- if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
- return trace;
-
- return NULL;
-}
-
-/* _ltt_trace_find_setup :
- * find a trace in setup list by given name.
- *
- * Returns a pointer to the trace structure, NULL if not found.
- */
-struct ust_trace *_ltt_trace_find_setup(const char *trace_name)
-{
- struct ust_trace *trace;
-
- cds_list_for_each_entry(trace, <t_traces.setup_head, list)
- if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
- return trace;
-
- return NULL;
-}
-
-/**
- * ltt_release_transport - Release an LTT transport
- * @kref : reference count on the transport
- */
-void ltt_release_transport(struct urcu_ref *urcu_ref)
-{
- return;
-}
-
-/**
- * ltt_release_trace - Release a LTT trace
- * @kref : reference count on the trace
- */
-void ltt_release_trace(struct urcu_ref *urcu_ref)
-{
- struct ust_trace *trace = _ust_container_of(urcu_ref,
- struct ust_trace, urcu_ref);
- ltt_channels_trace_free(trace->channels);
- free(trace);
-}
-
-static inline void prepare_chan_size_num(unsigned int *subbuf_size,
- unsigned int *n_subbufs)
-{
- /* Make sure the subbuffer size is larger than a page */
- *subbuf_size = max_t(unsigned int, *subbuf_size, PAGE_SIZE);
-
- /* round to next power of 2 */
- *subbuf_size = 1 << get_count_order(*subbuf_size);
- *n_subbufs = 1 << get_count_order(*n_subbufs);
-
- /* Subbuf size and number must both be power of two */
- WARN_ON(hweight32(*subbuf_size) != 1);
- WARN_ON(hweight32(*n_subbufs) != 1);
-}
-
-int _ltt_trace_setup(const char *trace_name)
-{
- int err = 0;
- struct ust_trace *new_trace = NULL;
- int metadata_index;
- unsigned int chan;
- enum ltt_channels chantype;
-
- if (_ltt_trace_find_setup(trace_name)) {
- ERR("Trace name %s already used", trace_name);
- err = -EEXIST;
- goto traces_error;
- }
-
- if (_ltt_trace_find(trace_name)) {
- ERR("Trace name %s already used", trace_name);
- err = -EEXIST;
- goto traces_error;
- }
-
- new_trace = zmalloc(sizeof(struct ust_trace));
- if (!new_trace) {
- ERR("Unable to allocate memory for trace %s", trace_name);
- err = -ENOMEM;
- goto traces_error;
- }
- strncpy(new_trace->trace_name, trace_name, NAME_MAX);
- new_trace->channels = ltt_channels_trace_alloc(&new_trace->nr_channels,
- ust_channels_overwrite_by_default,
- ust_channels_request_collection_by_default, 1);
- if (!new_trace->channels) {
- ERR("Unable to allocate memory for chaninfo %s\n", trace_name);
- err = -ENOMEM;
- goto trace_free;
- }
-
- /*
- * Force metadata channel to active, no overwrite.
- */
- metadata_index = ltt_channels_get_index_from_name("metadata");
- WARN_ON(metadata_index < 0);
- new_trace->channels[metadata_index].overwrite = 0;
- new_trace->channels[metadata_index].active = 1;
-
- /*
- * Set hardcoded tracer defaults for some channels
- */
- for (chan = 0; chan < new_trace->nr_channels; chan++) {
- if (!(new_trace->channels[chan].active))
- continue;
-
- chantype = get_channel_type_from_name(
- ltt_channels_get_name_from_index(chan));
- new_trace->channels[chan].subbuf_size =
- chan_infos[chantype].def_subbufsize;
- new_trace->channels[chan].subbuf_cnt =
- chan_infos[chantype].def_subbufcount;
- }
-
- cds_list_add(&new_trace->list, <t_traces.setup_head);
- return 0;
-
-trace_free:
- free(new_trace);
-traces_error:
- return err;
-}
-
-
-int ltt_trace_setup(const char *trace_name)
-{
- int ret;
- ltt_lock_traces();
- ret = _ltt_trace_setup(trace_name);
- ltt_unlock_traces();
- return ret;
-}
-
-/* must be called from within a traces lock. */
-static void _ltt_trace_free(struct ust_trace *trace)
-{
- cds_list_del(&trace->list);
- free(trace);
-}
-
-int ltt_trace_set_type(const char *trace_name, const char *trace_type)
-{
- int err = 0;
- struct ust_trace *trace;
- struct ltt_transport *tran_iter, *transport = NULL;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- pthread_mutex_lock(<t_transport_mutex);
- cds_list_for_each_entry(tran_iter, <t_transport_list, node) {
- if (!strcmp(tran_iter->name, trace_type)) {
- transport = tran_iter;
- break;
- }
- }
- pthread_mutex_unlock(<t_transport_mutex);
-
- if (!transport) {
- ERR("Transport %s is not present", trace_type);
- err = -EINVAL;
- goto traces_error;
- }
-
- trace->transport = transport;
-
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-int ltt_trace_set_channel_subbufsize(const char *trace_name,
- const char *channel_name, unsigned int size)
-{
- int err = 0;
- struct ust_trace *trace;
- int index;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- index = ltt_channels_get_index_from_name(channel_name);
- if (index < 0) {
- ERR("Channel %s not found", channel_name);
- err = -ENOENT;
- goto traces_error;
- }
- trace->channels[index].subbuf_size = size;
-
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-int ltt_trace_set_channel_subbufcount(const char *trace_name,
- const char *channel_name, unsigned int cnt)
-{
- int err = 0;
- struct ust_trace *trace;
- int index;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- index = ltt_channels_get_index_from_name(channel_name);
- if (index < 0) {
- ERR("Channel %s not found", channel_name);
- err = -ENOENT;
- goto traces_error;
- }
- trace->channels[index].subbuf_cnt = cnt;
-
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-int ltt_trace_set_channel_enable(const char *trace_name,
- const char *channel_name, unsigned int enable)
-{
- int err = 0;
- struct ust_trace *trace;
- int index;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- /*
- * Datas in metadata channel(marker info) is necessary to be able to
- * read the trace, we always enable this channel.
- */
- if (!enable && !strcmp(channel_name, "metadata")) {
- ERR("Trying to disable metadata channel");
- err = -EINVAL;
- goto traces_error;
- }
-
- index = ltt_channels_get_index_from_name(channel_name);
- if (index < 0) {
- ERR("Channel %s not found", channel_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- trace->channels[index].active = enable;
-
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-int ltt_trace_set_channel_overwrite(const char *trace_name,
- const char *channel_name, unsigned int overwrite)
-{
- int err = 0;
- struct ust_trace *trace;
- int index;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- /*
- * Always put the metadata channel in non-overwrite mode :
- * This is a very low traffic channel and it can't afford to have its
- * data overwritten : this data (marker info) is necessary to be
- * able to read the trace.
- */
- if (overwrite && !strcmp(channel_name, "metadata")) {
- ERR("Trying to set metadata channel to overwrite mode");
- err = -EINVAL;
- goto traces_error;
- }
-
- index = ltt_channels_get_index_from_name(channel_name);
- if (index < 0) {
- ERR("Channel %s not found", channel_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- trace->channels[index].overwrite = overwrite;
-
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-int ltt_trace_alloc(const char *trace_name)
-{
- int err = 0;
- struct ust_trace *trace;
- unsigned int subbuf_size, subbuf_cnt;
- int chan;
- const char *channel_name;
-
- ltt_lock_traces();
-
- if (_ltt_trace_find(trace_name)) { /* Trace already allocated */
- err = 1;
- goto traces_error;
- }
-
- trace = _ltt_trace_find_setup(trace_name);
- if (!trace) {
- ERR("Trace not found %s", trace_name);
- err = -ENOENT;
- goto traces_error;
- }
-
- urcu_ref_init(&trace->urcu_ref);
- urcu_ref_init(&trace->ltt_transport_urcu_ref);
- trace->active = 0;
- trace->freq_scale = trace_clock_freq_scale();
-
- if (!trace->transport) {
- ERR("Transport is not set");
- err = -EINVAL;
- goto transport_error;
- }
- trace->ops = &trace->transport->ops;
-
- trace->start_freq = trace_clock_frequency();
- trace->start_tsc = trace_clock_read64();
- gettimeofday(&trace->start_time, NULL); //ust// changed /* FIXME: is this ok? */
-
- for (chan = 0; chan < trace->nr_channels; chan++) {
- if (!(trace->channels[chan].active))
- continue;
-
- channel_name = ltt_channels_get_name_from_index(chan);
- WARN_ON(!channel_name);
- subbuf_size = trace->channels[chan].subbuf_size;
- subbuf_cnt = trace->channels[chan].subbuf_cnt;
- prepare_chan_size_num(&subbuf_size, &subbuf_cnt);
- err = trace->ops->create_channel(trace_name, trace,
- channel_name,
- &trace->channels[chan],
- subbuf_size,
- subbuf_cnt,
- trace->channels[chan].overwrite);
- if (err != 0) {
- ERR("Cannot create channel %s", channel_name);
- goto create_channel_error;
- }
- }
-
- cds_list_del(&trace->list);
- cds_list_add_rcu(&trace->list, <t_traces.head);
-
- ltt_unlock_traces();
-
- return 0;
-
-create_channel_error:
- for (chan--; chan >= 0; chan--)
- if (trace->channels[chan].active)
- trace->ops->remove_channel(&trace->channels[chan]);
-
-transport_error:
-traces_error:
- ltt_unlock_traces();
- return err;
-}
-
-/* Must be called while sure that trace is in the list. */
-static int _ltt_trace_destroy(struct ust_trace *trace)
-{
- int err = -EPERM;
-
- if (trace == NULL) {
- err = -ENOENT;
- goto traces_error;
- }
- if (trace->active) {
- ERR("Can't destroy trace %s : tracer is active", trace->trace_name);
- err = -EBUSY;
- goto active_error;
- }
-
- cds_list_del_rcu(&trace->list);
- synchronize_rcu();
-
- return 0;
-
-active_error:
-traces_error:
- return err;
-}
-
-/* Sleepable part of the destroy */
-static void __ltt_trace_destroy(struct ust_trace *trace, int drop)
-{
- int i;
- struct ust_channel *chan;
-
- if(!drop) {
- for (i = 0; i < trace->nr_channels; i++) {
- chan = &trace->channels[i];
- if (chan->active)
- trace->ops->finish_channel(chan);
- }
- }
-
- /*
- * The currently destroyed trace is not in the trace list anymore,
- * so it's safe to call the async wakeup ourself. It will deliver
- * the last subbuffers.
- */
- trace_async_wakeup(trace);
-
- for (i = 0; i < trace->nr_channels; i++) {
- chan = &trace->channels[i];
- if (chan->active)
- trace->ops->remove_channel(chan);
- }
-
- urcu_ref_put(&trace->ltt_transport_urcu_ref, ltt_release_transport);
-
- urcu_ref_put(&trace->urcu_ref, ltt_release_trace);
-}
-
-int ltt_trace_destroy(const char *trace_name, int drop)
-{
- int err = 0;
- struct ust_trace *trace;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find(trace_name);
- if (trace) {
- err = _ltt_trace_destroy(trace);
- if (err)
- goto error;
-
- ltt_unlock_traces();
-
- __ltt_trace_destroy(trace, drop);
-
- return 0;
- }
-
- trace = _ltt_trace_find_setup(trace_name);
- if (trace) {
- _ltt_trace_free(trace);
- ltt_unlock_traces();
- return 0;
- }
-
- err = -ENOENT;
-
-error:
- ltt_unlock_traces();
- return err;
-}
-
-/* must be called from within a traces lock. */
-static int _ltt_trace_start(struct ust_trace *trace)
-{
- int err = 0;
-
- if (trace == NULL) {
- err = -ENOENT;
- goto traces_error;
- }
- if (trace->active)
- DBG("Tracing already active for trace %s", trace->trace_name);
- trace->active = 1;
- /* Read by trace points without protection : be careful */
- ltt_traces.num_active_traces++;
- return err;
-
-traces_error:
- return err;
-}
-
-int ltt_trace_start(const char *trace_name)
-{
- int err = 0;
- struct ust_trace *trace;
-
- ltt_lock_traces();
-
- trace = _ltt_trace_find(trace_name);
- err = _ltt_trace_start(trace);
- if (err)
- goto no_trace;
-
- ltt_unlock_traces();
-
- /*
- * Call the process-wide state dump.
- * Notice that there is no protection on the trace : that's exactly
- * why we iterate on the list and check for trace equality instead of
- * directly using this trace handle inside the logging function: we want
- * to record events only in a single trace in the trace session list.
- */
-
- ltt_dump_ust_marker_state(trace);
-
- return err;
-
- /* Error handling */
-no_trace:
- ltt_unlock_traces();
- return err;
-}
-
-/* must be called from within traces lock */
-static int _ltt_trace_stop(struct ust_trace *trace)
-{
- int err = -EPERM;
-
- if (trace == NULL) {
- err = -ENOENT;
- goto traces_error;
- }
- if (!trace->active)
- DBG("LTT : Tracing not active for trace %s", trace->trace_name);
- if (trace->active) {
- trace->active = 0;
- ltt_traces.num_active_traces--;
- }
- return 0;
-
-traces_error:
- return err;
-}
-
-int ltt_trace_stop(const char *trace_name)
-{
- int err = 0;
- struct ust_trace *trace;
-
- ltt_lock_traces();
- trace = _ltt_trace_find(trace_name);
- err = _ltt_trace_stop(trace);
- ltt_unlock_traces();
- return err;
-}
+++ /dev/null
-/**
- * ltt-type-serializer.c
- *
- * LTTng specialized type serializer.
- *
- * Copyright Mathieu Desnoyers, 2008.
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-/* This file contains functions for tracepoint custom probes support. */
-
-#define _GNU_SOURCE
-#define _LGPL_SOURCE
-#include <urcu/rculist.h>
-#include <ust/core.h>
-#include <ust/clock.h>
-#include <urcu-bp.h>
-#include "tracer.h"
-#include "type-serializer.h"
-
-notrace
-void _ltt_specialized_trace(const struct ust_marker *mdata, void *probe_data,
- void *serialize_private, unsigned int data_size,
- unsigned int largest_align)
-{
- int ret;
- uint16_t eID;
- size_t slot_size;
- unsigned int chan_index;
- struct ust_buffer *buf;
- struct ust_channel *chan;
- struct ust_trace *trace;
- u64 tsc;
- long buf_offset;
- int cpu;
- unsigned int rflags;
-
- /*
- * If we get here, it's probably because we have useful work to do.
- */
- if (unlikely(ltt_traces.num_active_traces == 0))
- return;
-
- rcu_read_lock();
- cpu = ust_get_cpu();
-
- /* Force volatile access. */
- CMM_STORE_SHARED(ltt_nesting, CMM_LOAD_SHARED(ltt_nesting) + 1);
-
- /*
- * asm volatile and "memory" clobber prevent the compiler from moving
- * instructions out of the ltt nesting count. This is required to ensure
- * that probe side-effects which can cause recursion (e.g. unforeseen
- * traps, divisions by 0, ...) are triggered within the incremented
- * nesting count section.
- */
- cmm_barrier();
- eID = mdata->event_id;
- chan_index = mdata->channel_id;
-
- /*
- * Iterate on each trace, typically small number of active traces,
- * list iteration with prefetch is usually slower.
- */
- cds_list_for_each_entry_rcu(trace, <t_traces.head, list) {
- if (unlikely(!trace->active))
- continue;
-//ust// if (unlikely(!ltt_run_filter(trace, eID)))
-//ust// continue;
-#ifdef CONFIG_LTT_DEBUG_EVENT_SIZE
- rflags = LTT_RFLAG_ID_SIZE;
-#else
- if (unlikely(eID >= LTT_FREE_EVENTS))
- rflags = LTT_RFLAG_ID;
- else
- rflags = 0;
-#endif
- /*
- * Skip channels added after trace creation.
- */
- if (unlikely(chan_index >= trace->nr_channels))
- continue;
- chan = &trace->channels[chan_index];
- if (!chan->active)
- continue;
-
- /* If a new cpu was plugged since the trace was started, we did
- * not add it to the trace, and therefore we write the event to
- * cpu 0.
- */
- if(cpu >= chan->n_cpus) {
- cpu = 0;
- }
-
- /* reserve space : header and data */
- ret = ltt_reserve_slot(chan, trace, data_size, largest_align,
- cpu, &buf, &slot_size, &buf_offset, &tsc,
- &rflags);
- if (unlikely(ret < 0))
- continue; /* buffer full */
-
- /* Out-of-order write : header and data */
- buf_offset = ltt_write_event_header(chan, buf,
- buf_offset, eID, data_size,
- tsc, rflags);
- if (data_size) {
- buf_offset += ltt_align(buf_offset, largest_align);
- ust_buffers_write(buf, buf_offset,
- serialize_private, data_size);
- buf_offset += data_size;
- }
- /* Out-of-order commit */
- ltt_commit_slot(chan, buf, buf_offset, data_size, slot_size);
- }
- /*
- * asm volatile and "memory" clobber prevent the compiler from moving
- * instructions out of the ltt nesting count. This is required to ensure
- * that probe side-effects which can cause recursion (e.g. unforeseen
- * traps, divisions by 0, ...) are triggered within the incremented
- * nesting count section.
- */
- cmm_barrier();
- CMM_STORE_SHARED(ltt_nesting, CMM_LOAD_SHARED(ltt_nesting) - 1);
- rcu_read_unlock();
-}
+++ /dev/null
-#ifndef _LTT_TYPE_SERIALIZER_H
-#define _LTT_TYPE_SERIALIZER_H
-
-#include <ust/marker.h>
-#include <ust/marker-internal.h>
-#include <ust/core.h>
-#include "buffers.h"
-
-/*
- * largest_align must be non-zero, equal to the minimum between the largest type
- * and sizeof(void *).
- */
-extern void _ltt_specialized_trace(const struct ust_marker *mdata, void *probe_data,
- void *serialize_private, unsigned int data_size,
- unsigned int largest_align);
-
-/*
- * Statically check that 0 < largest_align < sizeof(void *) to make sure it is
- * dumb-proof. It will make sure 0 is changed into 1 and unsigned long long is
- * changed into sizeof(void *) on 32-bit architectures.
- */
-static inline void ltt_specialized_trace(const struct ust_marker *mdata,
- void *probe_data,
- void *serialize_private, unsigned int data_size,
- unsigned int largest_align)
-{
- largest_align = min_t(unsigned int, largest_align, sizeof(void *));
- largest_align = max_t(unsigned int, largest_align, 1);
- _ltt_specialized_trace(mdata, probe_data, serialize_private, data_size,
- largest_align);
-}
-
-/*
- * Type serializer definitions.
- */
-
-/*
- * Return size of structure without end-of-structure padding.
- */
-#define serialize_sizeof(type) offsetof(typeof(type), end_field)
-
-struct serialize_long_int {
- unsigned long f1;
- unsigned int f2;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_int_int_long {
- unsigned int f1;
- unsigned int f2;
- unsigned long f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_int_int_short {
- unsigned int f1;
- unsigned int f2;
- unsigned short f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_long {
- unsigned long f1;
- unsigned long f2;
- unsigned long f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_int {
- unsigned long f1;
- unsigned long f2;
- unsigned int f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_short_char {
- unsigned long f1;
- unsigned long f2;
- unsigned short f3;
- unsigned char f4;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_short {
- unsigned long f1;
- unsigned long f2;
- unsigned short f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_short_char {
- unsigned long f1;
- unsigned short f2;
- unsigned char f3;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_short {
- unsigned long f1;
- unsigned short f2;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_char {
- unsigned long f1;
- unsigned char f2;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_sizet_int {
- size_t f1;
- unsigned int f2;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_sizet_int {
- unsigned long f1;
- unsigned long f2;
- size_t f3;
- unsigned int f4;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_long_long_sizet_int_int {
- unsigned long f1;
- unsigned long f2;
- size_t f3;
- unsigned int f4;
- unsigned int f5;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_l4421224411111 {
- unsigned long f1;
- uint32_t f2;
- uint32_t f3;
- uint16_t f4;
- uint8_t f5;
- uint16_t f6;
- uint16_t f7;
- uint32_t f8;
- uint32_t f9;
- uint8_t f10;
- uint8_t f11;
- uint8_t f12;
- uint8_t f13;
- uint8_t f14;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-struct serialize_l214421224411111 {
- unsigned long f1;
- uint16_t f2;
- uint8_t f3;
- uint32_t f4;
- uint32_t f5;
- uint16_t f6;
- uint8_t f7;
- uint16_t f8;
- uint16_t f9;
- uint32_t f10;
- uint32_t f11;
- uint8_t f12;
- uint8_t f13;
- uint8_t f14;
- uint8_t f15;
- uint8_t f16;
- uint8_t end_field[0];
-} LTT_ALIGN;
-
-struct serialize_l4412228 {
- unsigned long f1;
- uint32_t f2;
- uint32_t f3;
- uint8_t f4;
- uint16_t f5;
- uint16_t f6;
- uint16_t f7;
- uint64_t f8;
- unsigned char end_field[0];
-} LTT_ALIGN;
-
-#endif /* _LTT_TYPE_SERIALIZER_H */
+++ /dev/null
-AM_CPPFLAGS = -I$(top_srcdir)/include
-AM_CFLAGS = -fno-strict-aliasing
-
-noinst_LTLIBRARIES = libustcomm.la
-libustcomm_la_SOURCES = \
- ustcomm.h \
- ustcomm.c
-
-libustcomm_la_LDFLAGS = -no-undefined -static
-libustcomm_la_CFLAGS = -DUST_COMPONENT="libustcomm" -fPIC -fno-strict-aliasing
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-/* API used by UST components to communicate with each other via sockets. */
-
-#define _GNU_SOURCE
-#include <dirent.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ustcomm.h"
-#include "usterr.h"
-#include "share.h"
-
-static int mkdir_p(const char *path, mode_t mode)
-{
- const char *path_p;
- char *tmp;
-
- int retval = 0;
- int result;
- mode_t old_umask;
-
- tmp = zmalloc(strlen(path) + 1);
- if (tmp == NULL)
- return -1;
-
- /* skip first / */
- path_p = path+1;
-
- old_umask = umask(0);
- for(;;) {
- while (*path_p != '/') {
- if(*path_p == 0)
- break;
- ++path_p;
- }
- if (*path_p == '/') {
- strncpy(tmp, path, path_p - path);
- tmp[path_p-path] = '\0';
- if (tmp[path_p - path - 1] != '/') {
- result = mkdir(tmp, mode);
- if(result == -1) {
- if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) {
- /* Then this is a real error */
- retval = -1;
- break;
- }
- }
- }
- /* pass / */
- path_p++;
- } else {
- /* last component */
- result = mkdir(path, mode);
- if (result == -1)
- retval = -1;
- break;
- }
- }
-
- free(tmp);
- umask(old_umask);
- return retval;
-}
-
-static struct sockaddr_un * create_sock_addr(const char *name,
- size_t *sock_addr_size)
-{
- struct sockaddr_un * addr;
- size_t alloc_size;
-
- alloc_size = (size_t) (((struct sockaddr_un *) 0)->sun_path) +
- strlen(name) + 1;
-
- addr = malloc(alloc_size);
- if (addr < 0) {
- ERR("allocating addr failed");
- return NULL;
- }
-
- addr->sun_family = AF_UNIX;
- strcpy(addr->sun_path, name);
-
- *sock_addr_size = alloc_size;
-
- return addr;
-}
-
-struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd,
- struct cds_list_head *list)
-{
- struct epoll_event ev;
- struct ustcomm_sock *sock;
-
- sock = malloc(sizeof(struct ustcomm_sock));
- if (!sock) {
- perror("malloc: couldn't allocate ustcomm_sock");
- return NULL;
- }
-
- ev.events = EPOLLIN;
- ev.data.ptr = sock;
- sock->fd = fd;
-
- if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev) == -1) {
- perror("epoll_ctl: failed to add socket\n");
- free(sock);
- return NULL;
- }
-
- sock->epoll_fd = epoll_fd;
- if (list) {
- cds_list_add(&sock->list, list);
- } else {
- CDS_INIT_LIST_HEAD(&sock->list);
- }
-
- return sock;
-}
-
-void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll)
-{
- cds_list_del(&sock->list);
- if (!keep_in_epoll) {
- if (epoll_ctl(sock->epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL) == -1) {
- PERROR("epoll_ctl: failed to delete socket");
- }
- }
- close(sock->fd);
- free(sock);
-}
-
-struct ustcomm_sock * ustcomm_init_named_socket(const char *name,
- int epoll_fd)
-{
- int result;
- int fd;
- size_t sock_addr_size;
- struct sockaddr_un * addr;
- struct ustcomm_sock *sock;
-
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if(fd == -1) {
- PERROR("socket");
- return NULL;
- }
-
- addr = create_sock_addr(name, &sock_addr_size);
- if (addr == NULL) {
- ERR("allocating addr, UST thread bailing");
- goto close_sock;
- }
-
- result = access(name, F_OK);
- if(result == 0) {
- /* file exists */
- result = unlink(name);
- if(result == -1) {
- PERROR("unlink of socket file");
- goto free_addr;
- }
- DBG("socket already exists; overwriting");
- }
-
- result = bind(fd, (struct sockaddr *)addr, sock_addr_size);
- if(result == -1) {
- PERROR("bind");
- goto free_addr;
- }
-
- result = listen(fd, 1);
- if(result == -1) {
- PERROR("listen");
- goto free_addr;
- }
-
- sock = ustcomm_init_sock(fd, epoll_fd,
- NULL);
- if (!sock) {
- ERR("failed to create ustcomm_sock");
- goto free_addr;
- }
-
- free(addr);
-
- return sock;
-
-free_addr:
- free(addr);
-close_sock:
- close(fd);
-
- return NULL;
-}
-
-void ustcomm_del_named_sock(struct ustcomm_sock *sock,
- int keep_socket_file)
-{
- int result, fd;
- struct stat st;
- struct sockaddr dummy;
- struct sockaddr_un *sockaddr = NULL;
- int alloc_size;
-
- fd = sock->fd;
-
- if(!keep_socket_file) {
-
- /* Get the socket name */
- alloc_size = sizeof(dummy);
- if (getsockname(fd, &dummy, (socklen_t *)&alloc_size) < 0) {
- PERROR("getsockname failed");
- goto del_sock;
- }
-
- sockaddr = zmalloc(alloc_size);
- if (!sockaddr) {
- ERR("failed to allocate sockaddr");
- goto del_sock;
- }
-
- if (getsockname(fd, sockaddr, (socklen_t *)&alloc_size) < 0) {
- PERROR("getsockname failed");
- goto free_sockaddr;
- }
-
- /* Destroy socket */
- result = stat(sockaddr->sun_path, &st);
- if(result < 0) {
- PERROR("stat (%s)", sockaddr->sun_path);
- goto free_sockaddr;
- }
-
- /* Paranoid check before deleting. */
- result = S_ISSOCK(st.st_mode);
- if(!result) {
- ERR("The socket we are about to delete is not a socket.");
- goto free_sockaddr;
- }
-
- result = unlink(sockaddr->sun_path);
- if(result < 0) {
- PERROR("unlink");
- }
- }
-
-free_sockaddr:
- free(sockaddr);
-
-del_sock:
- ustcomm_del_sock(sock, keep_socket_file);
-}
-
-int ustcomm_recv_alloc(int sock,
- struct ustcomm_header *header,
- char **data) {
- int result;
- struct ustcomm_header peek_header;
- struct iovec iov[2];
- struct msghdr msg;
-
- /* Just to make the caller fail hard */
- *data = NULL;
-
- result = recv(sock, &peek_header, sizeof(peek_header),
- MSG_PEEK | MSG_WAITALL);
- if (result <= 0) {
- if(errno == ECONNRESET) {
- return 0;
- } else if (errno == EINTR) {
- return -1;
- } else if (result < 0) {
- PERROR("recv");
- return -1;
- }
- return 0;
- }
-
- memset(&msg, 0, sizeof(msg));
-
- iov[0].iov_base = (char *)header;
- iov[0].iov_len = sizeof(struct ustcomm_header);
-
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
-
- if (peek_header.size) {
- *data = zmalloc(peek_header.size);
- if (!*data) {
- return -ENOMEM;
- }
-
- iov[1].iov_base = *data;
- iov[1].iov_len = peek_header.size;
-
- msg.msg_iovlen++;
- }
-
- result = recvmsg(sock, &msg, MSG_WAITALL);
- if (result < 0) {
- free(*data);
- PERROR("recvmsg failed");
- }
-
- return result;
-}
-
-/* returns 1 to indicate a message was received
- * returns 0 to indicate no message was received (end of stream)
- * returns -1 to indicate an error
- */
-int ustcomm_recv_fd(int sock,
- struct ustcomm_header *header,
- char *data, int *fd)
-{
- int result;
- struct ustcomm_header peek_header;
- struct iovec iov[2];
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char buf[CMSG_SPACE(sizeof(int))];
-
- result = recv(sock, &peek_header, sizeof(peek_header),
- MSG_PEEK | MSG_WAITALL);
- if (result <= 0) {
- if(errno == ECONNRESET) {
- return 0;
- } else if (errno == EINTR) {
- return -1;
- } else if (result < 0) {
- PERROR("recv");
- return -1;
- }
- return 0;
- }
-
- memset(&msg, 0, sizeof(msg));
-
- iov[0].iov_base = (char *)header;
- iov[0].iov_len = sizeof(struct ustcomm_header);
-
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
-
- if (peek_header.size && data) {
- if (peek_header.size < 0 ||
- peek_header.size > USTCOMM_DATA_SIZE) {
- ERR("big peek header! %ld", peek_header.size);
- return 0;
- }
-
- iov[1].iov_base = data;
- iov[1].iov_len = peek_header.size;
-
- msg.msg_iovlen++;
- }
-
- if (fd && peek_header.fd_included) {
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- }
-
- result = recvmsg(sock, &msg, MSG_WAITALL);
- if (result <= 0) {
- if (result < 0) {
- PERROR("recvmsg failed");
- }
- return result;
- }
-
- if (fd && peek_header.fd_included) {
- cmsg = CMSG_FIRSTHDR(&msg);
- result = 0;
- while (cmsg != NULL) {
- if (cmsg->cmsg_level == SOL_SOCKET
- && cmsg->cmsg_type == SCM_RIGHTS) {
- *fd = *(int *) CMSG_DATA(cmsg);
- result = 1;
- break;
- }
- cmsg = CMSG_NXTHDR(&msg, cmsg);
- }
- if (!result) {
- ERR("Failed to receive file descriptor\n");
- }
- }
-
- return 1;
-}
-
-int ustcomm_recv(int sock,
- struct ustcomm_header *header,
- char *data)
-{
- return ustcomm_recv_fd(sock, header, data, NULL);
-}
-
-
-int ustcomm_send_fd(int sock,
- const struct ustcomm_header *header,
- const char *data,
- int *fd)
-{
- struct iovec iov[2];
- struct msghdr msg;
- int result;
- struct cmsghdr *cmsg;
- char buf[CMSG_SPACE(sizeof(int))];
-
- memset(&msg, 0, sizeof(msg));
-
- iov[0].iov_base = (char *)header;
- iov[0].iov_len = sizeof(struct ustcomm_header);
-
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
-
- if (header->size && data) {
- iov[1].iov_base = (char *)data;
- iov[1].iov_len = header->size;
-
- msg.msg_iovlen++;
-
- }
-
- if (fd && header->fd_included) {
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- *(int *) CMSG_DATA(cmsg) = *fd;
- msg.msg_controllen = cmsg->cmsg_len;
- }
-
- result = sendmsg(sock, &msg, MSG_NOSIGNAL);
- if (result < 0 && errno != EPIPE) {
- PERROR("sendmsg failed");
- }
- return result;
-}
-
-int ustcomm_send(int sock,
- const struct ustcomm_header *header,
- const char *data)
-{
- return ustcomm_send_fd(sock, header, data, NULL);
-}
-
-int ustcomm_req(int sock,
- const struct ustcomm_header *req_header,
- const char *req_data,
- struct ustcomm_header *res_header,
- char *res_data)
-{
- int result;
-
- result = ustcomm_send(sock, req_header, req_data);
- if ( result <= 0) {
- return result;
- }
-
- return ustcomm_recv(sock, res_header, res_data);
-}
-
-/* Return value:
- * 0: success
- * -1: error
- */
-
-int ustcomm_connect_path(const char *name, int *connection_fd)
-{
- int result, fd;
- size_t sock_addr_size;
- struct sockaddr_un *addr;
-
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if(fd == -1) {
- PERROR("socket");
- return -1;
- }
-
- addr = create_sock_addr(name, &sock_addr_size);
- if (addr == NULL) {
- ERR("allocating addr failed");
- goto close_sock;
- }
-
- result = connect(fd, (struct sockaddr *)addr, sock_addr_size);
- if(result == -1) {
- PERROR("connect (path=%s)", name);
- goto free_sock_addr;
- }
-
- *connection_fd = fd;
-
- free(addr);
-
- return 0;
-
-free_sock_addr:
- free(addr);
-close_sock:
- close(fd);
-
- return -1;
-}
-
-/* Returns the current users socket directory, must be freed */
-char *ustcomm_user_sock_dir(void)
-{
- int result;
- char *sock_dir = NULL;
-
- result = asprintf(&sock_dir, "%s%s", USER_SOCK_DIR,
- cuserid(NULL));
- if (result < 0) {
- ERR("string overflow allocating directory name");
- return NULL;
- }
-
- return sock_dir;
-}
-
-static int time_and_pid_from_socket_name(char *sock_name, unsigned long *time,
- pid_t *pid)
-{
- char *saveptr, *pid_m_time_str;
- char *sock_basename = strdup(basename(sock_name));
-
- if (!sock_basename) {
- return -1;
- }
-
- /* This is the pid */
- pid_m_time_str = strtok_r(sock_basename, ".", &saveptr);
- if (!pid_m_time_str) {
- goto out_err;
- }
-
- errno = 0;
- *pid = (pid_t)strtoul(pid_m_time_str, NULL, 10);
- if (errno) {
- goto out_err;
- }
-
- /* This should be the time-stamp */
- pid_m_time_str = strtok_r(NULL, ".", &saveptr);
- if (!pid_m_time_str) {
- goto out_err;
- }
-
- errno = 0;
- *time = strtoul(pid_m_time_str, NULL, 10);
- if (errno) {
- goto out_err;
- }
-
- return 0;
-
-out_err:
- free(sock_basename);
- return -1;
-}
-
-time_t ustcomm_pid_st_mtime(pid_t pid)
-{
- struct stat proc_stat;
- char proc_name[PATH_MAX];
-
- if (snprintf(proc_name, PATH_MAX - 1, "/proc/%ld", (long) pid) < 0) {
- return 0;
- }
-
- if (stat(proc_name, &proc_stat)) {
- return 0;
- }
-
- return proc_stat.st_mtime;
-}
-
-int ustcomm_is_socket_live(char *sock_name, pid_t *read_pid)
-{
- time_t time_from_pid;
- unsigned long time_from_sock;
- pid_t pid;
-
- if (time_and_pid_from_socket_name(sock_name, &time_from_sock, &pid)) {
- return 0;
- }
-
- if (read_pid) {
- *read_pid = pid;
- }
-
- time_from_pid = ustcomm_pid_st_mtime(pid);
- if (!time_from_pid) {
- return 0;
- }
-
- if ((unsigned long) time_from_pid == time_from_sock) {
- return 1;
- }
-
- return 0;
-}
-
-#define MAX_SOCK_PATH_BASE_LEN 100
-
-static int ustcomm_get_sock_name(char *dir_name, pid_t pid, char *sock_name)
-{
- struct dirent *dirent;
- char sock_path_base[MAX_SOCK_PATH_BASE_LEN];
- int len;
- DIR *dir = opendir(dir_name);
-
- snprintf(sock_path_base, MAX_SOCK_PATH_BASE_LEN - 1,
- "%ld.", (long) pid);
- len = strlen(sock_path_base);
-
- while ((dirent = readdir(dir))) {
- if (!strcmp(dirent->d_name, ".") ||
- !strcmp(dirent->d_name, "..") ||
- !strcmp(dirent->d_name, "ust-consumer") ||
- dirent->d_type == DT_DIR ||
- strncmp(dirent->d_name, sock_path_base, len)) {
- continue;
- }
-
- if (ustcomm_is_socket_live(dirent->d_name, NULL)) {
- if (snprintf(sock_name, PATH_MAX - 1, "%s/%s",
- dir_name, dirent->d_name) < 0) {
- PERROR("path longer than PATH_MAX?");
- goto out_err;
- }
- closedir(dir);
- return 0;
- }
- }
-
-out_err:
- closedir(dir);
- return -1;
-}
-
-/* Open a connection to a traceable app.
- *
- * Return value:
- * 0: success
- * -1: error
- */
-
-static int connect_app_non_root(pid_t pid, int *app_fd)
-{
- int result;
- int retval = 0;
- char *dir_name;
- char sock_name[PATH_MAX];
-
- dir_name = ustcomm_user_sock_dir();
- if (!dir_name)
- return -ENOMEM;
-
- if (ustcomm_get_sock_name(dir_name, pid, sock_name)) {
- retval = -ENOENT;
- goto free_dir_name;
- }
-
- result = ustcomm_connect_path(sock_name, app_fd);
- if (result < 0) {
- ERR("failed to connect to app");
- retval = -1;
- goto free_dir_name;
- }
-
-free_dir_name:
- free(dir_name);
-
- return retval;
-}
-
-
-
-static int connect_app_root(pid_t pid, int *app_fd)
-{
- DIR *tmp_dir;
- struct dirent *dirent;
- char dir_name[PATH_MAX], sock_name[PATH_MAX];
- int result = -1;
-
- tmp_dir = opendir(USER_TMP_DIR);
- if (!tmp_dir) {
- return -1;
- }
-
- while ((dirent = readdir(tmp_dir))) {
- if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE,
- strlen(USER_SOCK_DIR_BASE))) {
-
- if (snprintf(dir_name, PATH_MAX - 1, "%s/%s", USER_TMP_DIR,
- dirent->d_name) < 0) {
- continue;
- }
-
- if (ustcomm_get_sock_name(dir_name, pid, sock_name)) {
- continue;
- }
-
- result = ustcomm_connect_path(sock_name, app_fd);
-
- if (result == 0) {
- goto close_tmp_dir;
- }
- }
- }
-
-close_tmp_dir:
- closedir(tmp_dir);
-
- return result;
-}
-
-int ustcomm_connect_app(pid_t pid, int *app_fd)
-{
- *app_fd = 0;
-
- if (geteuid()) {
- return connect_app_non_root(pid, app_fd);
- } else {
- return connect_app_root(pid, app_fd);
- }
-
-}
-
-int ensure_dir_exists(const char *dir, mode_t mode)
-{
- struct stat st;
- int result;
-
- if (!strcmp(dir, ""))
- return -1;
-
- result = stat(dir, &st);
- if (result < 0 && errno != ENOENT) {
- return -1;
- } else if (result < 0) {
- /* ENOENT */
- int result;
-
- result = mkdir_p(dir, mode);
- if(result != 0) {
- ERR("executing in recursive creation of directory %s", dir);
- return -1;
- }
- } else {
- if (st.st_mode != mode) {
- result = chmod(dir, mode);
- if (result < 0) {
- ERR("couldn't set directory mode on %s", dir);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-char * ustcomm_print_data(char *data_field, int field_size,
- int *offset, const char *format, ...)
-{
- va_list args;
- int count, limit;
- char *ptr = USTCOMM_POISON_PTR;
-
- limit = field_size - *offset;
- va_start(args, format);
- count = vsnprintf(&data_field[*offset], limit, format, args);
- va_end(args);
-
- if (count < limit && count > -1) {
- ptr = NULL + *offset;
- *offset = *offset + count + 1;
- }
-
- return ptr;
-}
-
-char * ustcomm_restore_ptr(char *ptr, char *data_field, int data_field_size)
-{
- if ((unsigned long)ptr > data_field_size ||
- ptr == USTCOMM_POISON_PTR) {
- return NULL;
- }
-
- return data_field + (long)ptr;
-}
-
-int ustcomm_pack_single_field(struct ustcomm_header *header,
- struct ustcomm_single_field *single_field,
- const char *string)
-{
- int offset = 0;
-
- single_field->field = ustcomm_print_data(single_field->data,
- sizeof(single_field->data),
- &offset,
- string);
-
- if (single_field->field == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- header->size = COMPUTE_MSG_SIZE(single_field, offset);
-
- return 0;
-}
-
-int ustcomm_unpack_single_field(struct ustcomm_single_field *single_field)
-{
- single_field->field = ustcomm_restore_ptr(single_field->field,
- single_field->data,
- sizeof(single_field->data));
- if (!single_field->field) {
- return -EINVAL;
- }
-
- return 0;
-}
-
-int ustcomm_pack_channel_info(struct ustcomm_header *header,
- struct ustcomm_channel_info *ch_inf,
- const char *trace,
- const char *channel)
-{
- int offset = 0;
-
- ch_inf->trace = ustcomm_print_data(ch_inf->data,
- sizeof(ch_inf->data),
- &offset,
- trace);
-
- if (ch_inf->trace == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- ch_inf->channel = ustcomm_print_data(ch_inf->data,
- sizeof(ch_inf->data),
- &offset,
- channel);
-
- if (ch_inf->channel == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- header->size = COMPUTE_MSG_SIZE(ch_inf, offset);
-
- return 0;
-}
-
-
-int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf)
-{
- ch_inf->trace = ustcomm_restore_ptr(ch_inf->trace,
- ch_inf->data,
- sizeof(ch_inf->data));
- if (!ch_inf->trace) {
- return -EINVAL;
- }
-
- ch_inf->channel = ustcomm_restore_ptr(ch_inf->channel,
- ch_inf->data,
- sizeof(ch_inf->data));
- if (!ch_inf->channel) {
- return -EINVAL;
- }
-
- return 0;
-}
-
-int ustcomm_pack_buffer_info(struct ustcomm_header *header,
- struct ustcomm_buffer_info *buf_inf,
- const char *trace,
- const char *channel,
- int channel_cpu)
-{
- int offset = 0;
-
- buf_inf->trace = ustcomm_print_data(buf_inf->data,
- sizeof(buf_inf->data),
- &offset,
- trace);
-
- if (buf_inf->trace == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- buf_inf->channel = ustcomm_print_data(buf_inf->data,
- sizeof(buf_inf->data),
- &offset,
- channel);
-
- if (buf_inf->channel == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- buf_inf->ch_cpu = channel_cpu;
-
- header->size = COMPUTE_MSG_SIZE(buf_inf, offset);
-
- return 0;
-}
-
-
-int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf)
-{
- buf_inf->trace = ustcomm_restore_ptr(buf_inf->trace,
- buf_inf->data,
- sizeof(buf_inf->data));
- if (!buf_inf->trace) {
- return -EINVAL;
- }
-
- buf_inf->channel = ustcomm_restore_ptr(buf_inf->channel,
- buf_inf->data,
- sizeof(buf_inf->data));
- if (!buf_inf->channel) {
- return -EINVAL;
- }
-
- return 0;
-}
-
-int ustcomm_pack_ust_marker_info(struct ustcomm_header *header,
- struct ustcomm_ust_marker_info *ust_marker_inf,
- const char *trace,
- const char *channel,
- const char *ust_marker)
-{
- int offset = 0;
-
- ust_marker_inf->trace = ustcomm_print_data(ust_marker_inf->data,
- sizeof(ust_marker_inf->data),
- &offset,
- trace);
-
- if (ust_marker_inf->trace == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
-
- ust_marker_inf->channel = ustcomm_print_data(ust_marker_inf->data,
- sizeof(ust_marker_inf->data),
- &offset,
- channel);
-
- if (ust_marker_inf->channel == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
-
- ust_marker_inf->ust_marker = ustcomm_print_data(ust_marker_inf->data,
- sizeof(ust_marker_inf->data),
- &offset,
- ust_marker);
-
- if (ust_marker_inf->ust_marker == USTCOMM_POISON_PTR) {
- return -ENOMEM;
- }
-
- header->size = COMPUTE_MSG_SIZE(ust_marker_inf, offset);
-
- return 0;
-}
-
-int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf)
-{
- ust_marker_inf->trace = ustcomm_restore_ptr(ust_marker_inf->trace,
- ust_marker_inf->data,
- sizeof(ust_marker_inf->data));
- if (!ust_marker_inf->trace) {
- return -EINVAL;
- }
-
- ust_marker_inf->channel = ustcomm_restore_ptr(ust_marker_inf->channel,
- ust_marker_inf->data,
- sizeof(ust_marker_inf->data));
- if (!ust_marker_inf->channel) {
- return -EINVAL;
- }
-
- ust_marker_inf->ust_marker = ustcomm_restore_ptr(ust_marker_inf->ust_marker,
- ust_marker_inf->data,
- sizeof(ust_marker_inf->data));
- if (!ust_marker_inf->ust_marker) {
- return -EINVAL;
- }
-
- return 0;
-}
-
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#ifndef USTCOMM_H
-#define USTCOMM_H
-
-#include <sys/types.h>
-#include <sys/un.h>
-#include <urcu/list.h>
-
-#include <ust/kcompat/kcompat.h>
-
-#define SOCK_DIR "/tmp/ust-app-socks"
-#define USER_TMP_DIR "/tmp"
-#define USER_SOCK_DIR_BASE "ust-socks-"
-#define USER_SOCK_DIR USER_TMP_DIR "/" USER_SOCK_DIR_BASE
-
-struct ustcomm_sock {
- struct cds_list_head list;
- int fd;
- int epoll_fd;
-};
-
-struct ustcomm_header {
- int command;
- long size;
- int result;
- int fd_included;
-};
-
-#define USTCOMM_BUFFER_SIZE ((1 << 12) - sizeof(struct ustcomm_header))
-
-/* Specify a sata size that leaves margin at the end of a buffer
- * in order to make sure that we never have more data than
- * will fit in the buffer AND that the last chars (due to a
- * pre-receive memset) will always be 0, terminating any string
- */
-#define USTCOMM_DATA_SIZE (USTCOMM_BUFFER_SIZE - 20 * sizeof(void *))
-
-enum tracectl_commands {
- ALLOC_TRACE,
- CONSUME_BUFFER,
- CREATE_TRACE,
- DESTROY_TRACE,
- DISABLE_MARKER,
- ENABLE_MARKER,
- EXIT,
- FORCE_SUBBUF_SWITCH,
- GET_BUF_SHMID_PIPE_FD,
- GET_PIDUNIQUE,
- GET_SOCK_PATH,
- GET_SUBBUFFER,
- GET_SUBBUF_NUM_SIZE,
- LIST_MARKERS,
- LIST_TRACE_EVENTS,
- LOAD_PROBE_LIB,
- NOTIFY_BUF_MAPPED,
- PRINT_MARKERS,
- PRINT_TRACE_EVENTS,
- PUT_SUBBUFFER,
- SETUP_TRACE,
- SET_SOCK_PATH,
- SET_SUBBUF_NUM,
- SET_SUBBUF_SIZE,
- START,
- START_TRACE,
- STOP_TRACE,
-};
-
-struct ustcomm_single_field {
- char *field;
- char data[USTCOMM_DATA_SIZE];
-};
-
-struct ustcomm_channel_info {
- char *trace;
- char *channel;
- unsigned int subbuf_size;
- unsigned int subbuf_num;
- char data[USTCOMM_DATA_SIZE];
-};
-
-struct ustcomm_buffer_info {
- char *trace;
- char *channel;
- int ch_cpu;
- pid_t pid;
- int buf_shmid;
- int buf_struct_shmid;
- long consumed_old;
- char data[USTCOMM_DATA_SIZE];
-};
-
-struct ustcomm_ust_marker_info {
- char *trace;
- char *channel;
- char *ust_marker;
- char data[USTCOMM_DATA_SIZE];
-};
-
-struct ustcomm_pidunique {
- s64 pidunique;
-};
-
-struct ustcomm_notify_buf_mapped {
- char data[USTCOMM_DATA_SIZE];
-};
-
-/* Ensure directory existence, usefull for unix sockets */
-extern int ensure_dir_exists(const char *dir, mode_t mode);
-
-/* Create and delete sockets */
-extern struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd,
- struct cds_list_head *list);
-extern void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll);
-
-/* Create and delete named sockets */
-extern struct ustcomm_sock * ustcomm_init_named_socket(const char *name,
- int epoll_fd);
-extern void ustcomm_del_named_sock(struct ustcomm_sock *sock,
- int keep_socket_file);
-
-/* Send and receive functions for file descriptors */
-extern int ustcomm_send_fd(int sock, const struct ustcomm_header *header,
- const char *data, int *fd);
-extern int ustcomm_recv_fd(int sock, struct ustcomm_header *header,
- char *data, int *fd);
-
-/* Normal send and receive functions */
-extern int ustcomm_send(int sock, const struct ustcomm_header *header,
- const char *data);
-extern int ustcomm_recv(int sock, struct ustcomm_header *header,
- char *data);
-
-/* Receive and allocate data, not to be used inside libust */
-extern int ustcomm_recv_alloc(int sock,
- struct ustcomm_header *header,
- char **data);
-
-/* Request function, send and receive */
-extern int ustcomm_req(int sock,
- const struct ustcomm_header *req_header,
- const char *req_data,
- struct ustcomm_header *res_header,
- char *res_data);
-
-extern int ustcomm_request_consumer(pid_t pid, const char *channel);
-
-/* Returns the current users socket directory, must be freed */
-extern char *ustcomm_user_sock_dir(void);
-
-/* Get the st_m_time from proc*/
-extern time_t ustcomm_pid_st_mtime(pid_t pid);
-
-/* Check that a socket is live */
-extern int ustcomm_is_socket_live(char *sock_name, pid_t *read_pid);
-
-extern int ustcomm_connect_app(pid_t pid, int *app_fd);
-extern int ustcomm_connect_path(const char *path, int *connection_fd);
-
-extern int nth_token_is(const char *str, const char *token, int tok_no);
-
-extern char *nth_token(const char *str, int tok_no);
-
-/* String serialising functions, printf straight into a buffer */
-#define USTCOMM_POISON_PTR (void *)0x19831018
-
-extern char * ustcomm_print_data(char *data_field, int field_size,
- int *offset, const char *format, ...);
-extern char * ustcomm_restore_ptr(char *ptr, char *data_field,
- int data_field_size);
-
-#define COMPUTE_MSG_SIZE(struct_ptr, offset) \
- (size_t) (long)(struct_ptr)->data - (long)(struct_ptr) + (offset)
-
-/* Packing and unpacking functions, making life easier */
-extern int ustcomm_pack_single_field(struct ustcomm_header *header,
- struct ustcomm_single_field *sf,
- const char *trace);
-
-extern int ustcomm_unpack_single_field(struct ustcomm_single_field *sf);
-
-extern int ustcomm_pack_channel_info(struct ustcomm_header *header,
- struct ustcomm_channel_info *ch_inf,
- const char *trace,
- const char *channel);
-
-extern int ustcomm_unpack_channel_info(struct ustcomm_channel_info *ch_inf);
-
-extern int ustcomm_pack_buffer_info(struct ustcomm_header *header,
- struct ustcomm_buffer_info *buf_inf,
- const char *trace,
- const char *channel,
- int channel_cpu);
-
-extern int ustcomm_unpack_buffer_info(struct ustcomm_buffer_info *buf_inf);
-
-extern int ustcomm_pack_ust_marker_info(struct ustcomm_header *header,
- struct ustcomm_ust_marker_info *ust_marker_inf,
- const char *trace,
- const char *channel,
- const char *ust_marker);
-
-extern int ustcomm_unpack_ust_marker_info(struct ustcomm_ust_marker_info *ust_marker_inf);
-
-#endif /* USTCOMM_H */
+++ /dev/null
-AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
- -I$(top_srcdir)/include
-AM_CFLAGS = -fno-strict-aliasing
-
-lib_LTLIBRARIES = libustconsumer.la
-
-libustconsumer_la_SOURCES = libustconsumer.c lowlevel.c lowlevel.h
-
-libustconsumer_la_LDFLAGS = -no-undefined -version-info 0:0:0
-
-libustconsumer_la_LIBADD = \
- -lpthread \
- $(top_builddir)/snprintf/libustsnprintf.la \
- $(top_builddir)/libustcomm/libustcomm.la
-
-libustconsumer_la_CFLAGS = -fno-strict-aliasing
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- * 2010 Alexis Halle
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-
-#include <sys/epoll.h>
-#include <sys/shm.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <signal.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#include <ust/ustconsumer.h>
-#include "lowlevel.h"
-#include "usterr_signal_safe.h"
-#include "ustcomm.h"
-
-#define GET_SUBBUF_OK 1
-#define GET_SUBBUF_DONE 0
-#define GET_SUBBUF_DIED 2
-
-#define PUT_SUBBUF_OK 1
-#define PUT_SUBBUF_DIED 0
-#define PUT_SUBBUF_PUSHED 2
-#define PUT_SUBBUF_DONE 3
-
-#define UNIX_PATH_MAX 108
-
-static int get_subbuffer(struct buffer_info *buf)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_buffer_info _send_msg, _recv_msg;
- struct ustcomm_buffer_info *send_msg, *recv_msg;
- int result;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- send_msg = &_send_msg;
- recv_msg = &_recv_msg;
-
- result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
- buf->channel, buf->channel_cpu);
- if (result < 0) {
- return result;
- }
-
- send_hdr->command = GET_SUBBUFFER;
-
- result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
- recv_hdr, (char *)recv_msg);
- if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
- result == 0) {
- DBG("app died while being traced");
- return GET_SUBBUF_DIED;
- } else if (result < 0) {
- ERR("get_subbuffer: ustcomm_req failed");
- return result;
- }
-
- if (!recv_hdr->result) {
- DBG("got subbuffer %s", buf->name);
- buf->consumed_old = recv_msg->consumed_old;
- return GET_SUBBUF_OK;
- } else if (recv_hdr->result == -ENODATA) {
- DBG("For buffer %s, the trace was not found. This likely means"
- " it was destroyed by the user.", buf->name);
- return GET_SUBBUF_DIED;
- }
-
- DBG("error getting subbuffer %s", buf->name);
- return recv_hdr->result;
-}
-
-static int put_subbuffer(struct buffer_info *buf)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_buffer_info _send_msg, *send_msg;
- int result;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- send_msg = &_send_msg;
-
- result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
- buf->channel, buf->channel_cpu);
- if (result < 0) {
- return result;
- }
-
- send_hdr->command = PUT_SUBBUFFER;
- send_msg->consumed_old = buf->consumed_old;
-
- result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
- recv_hdr, NULL);
- if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
- result == 0) {
- DBG("app died while being traced");
- return PUT_SUBBUF_DIED;
- } else if (result < 0) {
- ERR("put_subbuffer: ustcomm_req failed");
- return result;
- }
-
- if (!recv_hdr->result) {
- DBG("put subbuffer %s", buf->name);
- return PUT_SUBBUF_OK;
- } else if (recv_hdr->result == -ENODATA) {
- DBG("For buffer %s, the trace was not found. This likely means"
- " it was destroyed by the user.", buf->name);
- return PUT_SUBBUF_DIED;
- }
-
- DBG("error getting subbuffer %s", buf->name);
- return recv_hdr->result;
-}
-
-void decrement_active_buffers(void *arg)
-{
- struct ustconsumer_instance *instance = arg;
- pthread_mutex_lock(&instance->mutex);
- instance->active_buffers--;
- pthread_mutex_unlock(&instance->mutex);
-}
-
-static int get_pidunique(int sock, int64_t *pidunique)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_pidunique _recv_msg, *recv_msg;
- int result;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- recv_msg = &_recv_msg;
-
- memset(send_hdr, 0, sizeof(*send_hdr));
-
- send_hdr->command = GET_PIDUNIQUE;
- result = ustcomm_req(sock, send_hdr, NULL, recv_hdr, (char *)recv_msg);
- if (result < 1) {
- return -ENOTCONN;
- }
- if (recv_hdr->result < 0) {
- ERR("App responded with error: %s", strerror(recv_hdr->result));
- return recv_hdr->result;
- }
-
- *pidunique = recv_msg->pidunique;
-
- return 0;
-}
-
-static int get_buf_shmid_pipe_fd(int sock, struct buffer_info *buf,
- int *buf_shmid, int *buf_struct_shmid,
- int *buf_pipe_fd)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_buffer_info _send_msg, *send_msg;
- struct ustcomm_buffer_info _recv_msg, *recv_msg;
- int result, recv_pipe_fd;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- send_msg = &_send_msg;
- recv_msg = &_recv_msg;
-
- result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
- buf->channel, buf->channel_cpu);
- if (result < 0) {
- ERR("Failed to pack buffer info");
- return result;
- }
-
- send_hdr->command = GET_BUF_SHMID_PIPE_FD;
-
- result = ustcomm_send(sock, send_hdr, (char *)send_msg);
- if (result < 1) {
- ERR("Failed to send request");
- return -ENOTCONN;
- }
- result = ustcomm_recv_fd(sock, recv_hdr, (char *)recv_msg, &recv_pipe_fd);
- if (result < 1) {
- ERR("Failed to receive message and fd");
- return -ENOTCONN;
- }
- if (recv_hdr->result < 0) {
- ERR("App responded with error %s", strerror(recv_hdr->result));
- return recv_hdr->result;
- }
-
- *buf_shmid = recv_msg->buf_shmid;
- *buf_struct_shmid = recv_msg->buf_struct_shmid;
- *buf_pipe_fd = recv_pipe_fd;
-
- return 0;
-}
-
-static int get_subbuf_num_size(int sock, struct buffer_info *buf,
- int *subbuf_num, int *subbuf_size)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_channel_info _send_msg, *send_msg;
- struct ustcomm_channel_info _recv_msg, *recv_msg;
- int result;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- send_msg = &_send_msg;
- recv_msg = &_recv_msg;
-
- result = ustcomm_pack_channel_info(send_hdr, send_msg, buf->trace,
- buf->channel);
- if (result < 0) {
- return result;
- }
-
- send_hdr->command = GET_SUBBUF_NUM_SIZE;
-
- result = ustcomm_req(sock, send_hdr, (char *)send_msg,
- recv_hdr, (char *)recv_msg);
- if (result < 1) {
- return -ENOTCONN;
- }
-
- *subbuf_num = recv_msg->subbuf_num;
- *subbuf_size = recv_msg->subbuf_size;
-
- return recv_hdr->result;
-}
-
-
-static int notify_buffer_mapped(int sock, struct buffer_info *buf)
-{
- struct ustcomm_header _send_hdr, *send_hdr;
- struct ustcomm_header _recv_hdr, *recv_hdr;
- struct ustcomm_buffer_info _send_msg, *send_msg;
- int result;
-
- send_hdr = &_send_hdr;
- recv_hdr = &_recv_hdr;
- send_msg = &_send_msg;
-
- result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
- buf->channel, buf->channel_cpu);
- if (result < 0) {
- return result;
- }
-
- send_hdr->command = NOTIFY_BUF_MAPPED;
-
- result = ustcomm_req(sock, send_hdr, (char *)send_msg,
- recv_hdr, NULL);
- if (result < 1) {
- return -ENOTCONN;
- }
-
- return recv_hdr->result;
-}
-
-
-struct buffer_info *connect_buffer(struct ustconsumer_instance *instance, pid_t pid,
- const char *trace, const char *channel,
- int channel_cpu)
-{
- struct buffer_info *buf;
- int result;
- struct shmid_ds shmds;
-
- buf = (struct buffer_info *) zmalloc(sizeof(struct buffer_info));
- if(buf == NULL) {
- ERR("add_buffer: insufficient memory");
- return NULL;
- }
-
- buf->trace = strdup(trace);
- if (!buf->trace) {
- goto free_buf;
- }
-
- buf->channel = strdup(channel);
- if (!buf->channel) {
- goto free_buf_trace;
- }
-
- result = asprintf(&buf->name, "%s_%d", channel, channel_cpu);
- if (result < 0 || buf->name == NULL) {
- goto free_buf_channel;
- }
-
- buf->channel_cpu = channel_cpu;
- buf->pid = pid;
-
- result = ustcomm_connect_app(buf->pid, &buf->app_sock);
- if(result) {
- WARN("unable to connect to process, it probably died before we were able to connect");
- goto free_buf_name;
- }
-
- /* get pidunique */
- result = get_pidunique(buf->app_sock, &buf->pidunique);
- if (result < 0) {
- ERR("Failed to get pidunique");
- goto close_app_sock;
- }
-
- /* get shmid and pipe fd */
- result = get_buf_shmid_pipe_fd(buf->app_sock, buf, &buf->shmid,
- &buf->bufstruct_shmid, &buf->pipe_fd);
- if (result < 0) {
- ERR("Failed to get buf_shmid and pipe_fd");
- goto close_app_sock;
- } else {
- struct stat temp;
- fstat(buf->pipe_fd, &temp);
- if (!S_ISFIFO(temp.st_mode)) {
- ERR("Didn't receive a fifo from the app");
- goto close_app_sock;
- }
- }
-
-
- /* get number of subbufs and subbuf size */
- result = get_subbuf_num_size(buf->app_sock, buf, &buf->n_subbufs,
- &buf->subbuf_size);
- if (result < 0) {
- ERR("Failed to get subbuf number and size");
- goto close_fifo;
- }
-
- /* Set subbuffer's information */
- buf->subbuf_size_order = get_count_order(buf->subbuf_size);
- buf->alloc_size = buf->subbuf_size * buf->n_subbufs;
-
- /* attach memory */
- buf->mem = shmat(buf->shmid, NULL, 0);
- if(buf->mem == (void *) 0) {
- PERROR("shmat");
- goto close_fifo;
- }
- DBG("successfully attached buffer memory");
-
- buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0);
- if(buf->bufstruct_mem == (void *) 0) {
- PERROR("shmat");
- goto shmdt_mem;
- }
- DBG("successfully attached buffer bufstruct memory");
-
- /* obtain info on the memory segment */
- result = shmctl(buf->shmid, IPC_STAT, &shmds);
- if(result == -1) {
- PERROR("shmctl");
- goto shmdt_bufstruct_mem;
- }
- buf->memlen = shmds.shm_segsz;
-
- /* Notify the application that we have mapped the buffer */
- result = notify_buffer_mapped(buf->app_sock, buf);
- if (result < 0) {
- goto shmdt_bufstruct_mem;
- }
-
- if(instance->callbacks->on_open_buffer)
- instance->callbacks->on_open_buffer(instance->callbacks, buf);
-
- pthread_mutex_lock(&instance->mutex);
- instance->active_buffers++;
- pthread_mutex_unlock(&instance->mutex);
-
- return buf;
-
-shmdt_bufstruct_mem:
- shmdt(buf->bufstruct_mem);
-
-shmdt_mem:
- shmdt(buf->mem);
-
-close_fifo:
- close(buf->pipe_fd);
-
-close_app_sock:
- close(buf->app_sock);
-
-free_buf_name:
- free(buf->name);
-
-free_buf_channel:
- free(buf->channel);
-
-free_buf_trace:
- free(buf->trace);
-
-free_buf:
- free(buf);
- return NULL;
-}
-
-static void destroy_buffer(struct ustconsumer_callbacks *callbacks,
- struct buffer_info *buf)
-{
- int result;
-
- result = close(buf->pipe_fd);
- if(result == -1) {
- WARN("problem closing the pipe fd");
- }
-
- result = close(buf->app_sock);
- if(result == -1) {
- WARN("problem calling ustcomm_close_app");
- }
-
- result = shmdt(buf->mem);
- if(result == -1) {
- PERROR("shmdt");
- }
-
- result = shmdt(buf->bufstruct_mem);
- if(result == -1) {
- PERROR("shmdt");
- }
-
- if(callbacks->on_close_buffer)
- callbacks->on_close_buffer(callbacks, buf);
-
- free(buf);
-}
-
-int consumer_loop(struct ustconsumer_instance *instance, struct buffer_info *buf)
-{
- int result = 0;
- int read_result;
- char read_buf;
-
- pthread_cleanup_push(decrement_active_buffers, instance);
-
- for(;;) {
- read_result = read(buf->pipe_fd, &read_buf, 1);
- /* get the subbuffer */
- if (read_result == 1) {
- result = get_subbuffer(buf);
- if (result < 0) {
- ERR("error getting subbuffer");
- continue;
- } else if (result == GET_SUBBUF_DIED) {
- finish_consuming_dead_subbuffer(instance->callbacks, buf);
- break;
- }
- } else if ((read_result == -1 && (errno == ECONNRESET || errno == EPIPE)) ||
- result == 0) {
- DBG("App died while being traced");
- finish_consuming_dead_subbuffer(instance->callbacks, buf);
- break;
- } else if (read_result == -1 && errno == EINTR) {
- continue;
- }
-
- if(instance->callbacks->on_read_subbuffer)
- instance->callbacks->on_read_subbuffer(instance->callbacks, buf);
-
- /* put the subbuffer */
- result = put_subbuffer(buf);
- if(result == -1) {
- ERR("unknown error putting subbuffer (channel=%s)", buf->name);
- break;
- }
- else if(result == PUT_SUBBUF_PUSHED) {
- ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name);
- break;
- }
- else if(result == PUT_SUBBUF_DIED) {
- DBG("application died while putting subbuffer");
- /* Skip the first subbuffer. We are not sure it is trustable
- * because the put_subbuffer() did not complete.
- */
- /* TODO: check on_put_error return value */
- if(instance->callbacks->on_put_error)
- instance->callbacks->on_put_error(instance->callbacks, buf);
-
- finish_consuming_dead_subbuffer(instance->callbacks, buf);
- break;
- }
- else if(result == PUT_SUBBUF_DONE) {
- /* Done with this subbuffer */
- /* FIXME: add a case where this branch is used? Upon
- * normal trace termination, at put_subbuf time, a
- * special last-subbuffer code could be returned by
- * the listener.
- */
- break;
- }
- else if(result == PUT_SUBBUF_OK) {
- }
- }
-
- DBG("thread for buffer %s is stopping", buf->name);
-
- /* FIXME: destroy, unalloc... */
-
- pthread_cleanup_pop(1);
-
- return 0;
-}
-
-struct consumer_thread_args {
- pid_t pid;
- const char *trace;
- const char *channel;
- int channel_cpu;
- struct ustconsumer_instance *instance;
-};
-
-void *consumer_thread(void *arg)
-{
- struct buffer_info *buf;
- struct consumer_thread_args *args = (struct consumer_thread_args *) arg;
- int result;
- sigset_t sigset;
-
- pthread_mutex_lock(&args->instance->mutex);
- args->instance->active_threads++;
- pthread_mutex_unlock(&args->instance->mutex);
-
- if(args->instance->callbacks->on_new_thread)
- args->instance->callbacks->on_new_thread(args->instance->callbacks);
-
- /* Block signals that should be handled by the main thread. */
- result = sigemptyset(&sigset);
- if(result == -1) {
- PERROR("sigemptyset");
- goto end;
- }
- result = sigaddset(&sigset, SIGTERM);
- if(result == -1) {
- PERROR("sigaddset");
- goto end;
- }
- result = sigaddset(&sigset, SIGINT);
- if(result == -1) {
- PERROR("sigaddset");
- goto end;
- }
- result = sigprocmask(SIG_BLOCK, &sigset, NULL);
- if(result == -1) {
- PERROR("sigprocmask");
- goto end;
- }
-
- buf = connect_buffer(args->instance, args->pid, args->trace,
- args->channel, args->channel_cpu);
- if(buf == NULL) {
- ERR("failed to connect to buffer");
- goto end;
- }
-
- consumer_loop(args->instance, buf);
-
- destroy_buffer(args->instance->callbacks, buf);
-
- end:
-
- if(args->instance->callbacks->on_close_thread)
- args->instance->callbacks->on_close_thread(args->instance->callbacks);
-
- pthread_mutex_lock(&args->instance->mutex);
- args->instance->active_threads--;
- pthread_mutex_unlock(&args->instance->mutex);
-
- free((void *)args->channel);
- free(args);
- return NULL;
-}
-
-int start_consuming_buffer(struct ustconsumer_instance *instance, pid_t pid,
- const char *trace, const char *channel,
- int channel_cpu)
-{
- pthread_t thr;
- struct consumer_thread_args *args;
- int result;
-
- DBG("beginning of start_consuming_buffer: args: pid %d bufname %s_%d", pid, channel,
- channel_cpu);
-
- args = (struct consumer_thread_args *) zmalloc(sizeof(struct consumer_thread_args));
- if (!args) {
- return -ENOMEM;
- }
-
- args->pid = pid;
- args->trace = strdup(trace);
- args->channel = strdup(channel);
- args->channel_cpu = channel_cpu;
- args->instance = instance;
- DBG("beginning2 of start_consuming_buffer: args: pid %d trace %s"
- " bufname %s_%d", args->pid, args->trace, args->channel, args->channel_cpu);
-
- result = pthread_create(&thr, NULL, consumer_thread, args);
- if(result == -1) {
- ERR("pthread_create failed");
- return -1;
- }
- result = pthread_detach(thr);
- if(result == -1) {
- ERR("pthread_detach failed");
- return -1;
- }
- DBG("end of start_consuming_buffer: args: pid %d trace %s "
- "bufname %s_%d", args->pid, args->channel, args->trace, args->channel_cpu);
-
- return 0;
-}
-static void process_client_cmd(int sock, struct ustcomm_header *req_header,
- char *recvbuf, struct ustconsumer_instance *instance)
-{
- int result;
- struct ustcomm_header _res_header = {0};
- struct ustcomm_header *res_header = &_res_header;
- struct ustcomm_buffer_info *buf_inf;
-
- DBG("Processing client command");
-
- switch (req_header->command) {
- case CONSUME_BUFFER:
-
- buf_inf = (struct ustcomm_buffer_info *)recvbuf;
- result = ustcomm_unpack_buffer_info(buf_inf);
- if (result < 0) {
- ERR("Couldn't unpack buffer info");
- return;
- }
-
- DBG("Going to consume trace %s buffer %s_%d in process %d",
- buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu,
- buf_inf->pid);
- result = start_consuming_buffer(instance, buf_inf->pid,
- buf_inf->trace,
- buf_inf->channel,
- buf_inf->ch_cpu);
- if (result < 0) {
- ERR("error in add_buffer");
- return;
- }
-
- res_header->result = 0;
- break;
- case EXIT:
- res_header->result = 0;
- /* Only there to force poll to return */
- break;
- default:
- res_header->result = -EINVAL;
- WARN("unknown command: %d", req_header->command);
- }
-
- if (ustcomm_send(sock, res_header, NULL) <= 0) {
- ERR("couldn't send command response");
- }
-}
-
-#define MAX_EVENTS 10
-
-int ustconsumer_start_instance(struct ustconsumer_instance *instance)
-{
- struct ustcomm_header recv_hdr;
- char recv_buf[USTCOMM_BUFFER_SIZE];
- struct ustcomm_sock *epoll_sock;
- struct epoll_event events[MAX_EVENTS];
- struct sockaddr addr;
- int result, epoll_fd, accept_fd, nfds, i, addr_size, timeout;
-
- if(!instance->is_init) {
- ERR("libustconsumer instance not initialized");
- return 1;
- }
- epoll_fd = instance->epoll_fd;
-
- timeout = -1;
-
- /* app loop */
- for(;;) {
- nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);
- if (nfds == -1 && errno == EINTR) {
- /* Caught signal */
- } else if (nfds == -1) {
- PERROR("ustconsumer_start_instance: epoll_wait failed");
- continue;
- }
-
- for (i = 0; i < nfds; ++i) {
- epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
- if (epoll_sock == instance->listen_sock) {
- addr_size = sizeof(struct sockaddr);
- accept_fd = accept(epoll_sock->fd,
- &addr,
- (socklen_t *)&addr_size);
- if (accept_fd == -1) {
- PERROR("ustconsumer_start_instance: "
- "accept failed");
- continue;
- }
- ustcomm_init_sock(accept_fd, epoll_fd,
- &instance->connections);
- } else {
- result = ustcomm_recv(epoll_sock->fd, &recv_hdr,
- recv_buf);
- if (result < 1) {
- ustcomm_del_sock(epoll_sock, 0);
- } else {
- process_client_cmd(epoll_sock->fd,
- &recv_hdr, recv_buf,
- instance);
- }
-
- }
- }
-
- if (instance->quit_program) {
- pthread_mutex_lock(&instance->mutex);
- if (instance->active_buffers == 0 && instance->active_threads == 0) {
- pthread_mutex_unlock(&instance->mutex);
- break;
- }
- pthread_mutex_unlock(&instance->mutex);
- timeout = 100;
- }
- }
-
- if(instance->callbacks->on_trace_end)
- instance->callbacks->on_trace_end(instance);
-
- ustconsumer_delete_instance(instance);
-
- return 0;
-}
-
-/* FIXME: threads and connections !? */
-void ustconsumer_delete_instance(struct ustconsumer_instance *instance)
-{
- if (instance->is_init) {
- ustcomm_del_named_sock(instance->listen_sock, 0);
- close(instance->epoll_fd);
- }
-
- pthread_mutex_destroy(&instance->mutex);
- free(instance->sock_path);
- free(instance);
-}
-
-/* FIXME: Do something about the fixed path length, maybe get rid
- * of the whole concept and use a pipe?
- */
-int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg)
-{
- int result;
- int fd;
- int bytes = 0;
-
- char msg[] = "exit";
-
- instance->quit_program = 1;
-
- if(!send_msg)
- return 0;
-
- /* Send a message through the socket to force poll to return */
-
- struct sockaddr_un addr;
-
-socket_again:
- result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if(result == -1) {
- if (errno == EINTR)
- goto socket_again;
- PERROR("socket");
- return 1;
- }
-
- addr.sun_family = AF_UNIX;
-
- strncpy(addr.sun_path, instance->sock_path, UNIX_PATH_MAX);
- addr.sun_path[UNIX_PATH_MAX-1] = '\0';
-
-connect_again:
- result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
- if(result == -1) {
- if (errno == EINTR)
- goto connect_again;
- PERROR("connect");
- }
-
- while(bytes != sizeof(msg)) {
- int inc = send(fd, msg, sizeof(msg), 0);
- if (inc < 0 && errno != EINTR)
- break;
- else
- bytes += inc;
- }
-
- close(fd);
-
- return 0;
-}
-
-struct ustconsumer_instance
-*ustconsumer_new_instance(struct ustconsumer_callbacks *callbacks,
- char *sock_path)
-{
- struct ustconsumer_instance *instance =
- zmalloc(sizeof(struct ustconsumer_instance));
- if(!instance) {
- return NULL;
- }
-
- instance->callbacks = callbacks;
- instance->quit_program = 0;
- instance->is_init = 0;
- instance->active_buffers = 0;
- pthread_mutex_init(&instance->mutex, NULL);
-
- if (sock_path) {
- instance->sock_path = strdup(sock_path);
- } else {
- instance->sock_path = NULL;
- }
-
- return instance;
-}
-
-static int init_ustconsumer_socket(struct ustconsumer_instance *instance)
-{
- char *name;
-
- if (instance->sock_path) {
- if (asprintf(&name, "%s", instance->sock_path) < 0) {
- ERR("ustcomm_init_ustconsumer : asprintf failed (sock_path %s)",
- instance->sock_path);
- return -1;
- }
- } else {
- int result;
-
- /* Only check if socket dir exists if we are using the default directory */
- result = ensure_dir_exists(SOCK_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
- if (result == -1) {
- ERR("Unable to create socket directory %s", SOCK_DIR);
- return -1;
- }
-
- if (asprintf(&name, "%s/%s", SOCK_DIR, "ustconsumer") < 0) {
- ERR("ustcomm_init_ustconsumer : asprintf failed (%s/ustconsumer)",
- SOCK_DIR);
- return -1;
- }
- }
-
- /* Set up epoll */
- instance->epoll_fd = epoll_create(MAX_EVENTS);
- if (instance->epoll_fd == -1) {
- ERR("epoll_create failed, start instance bailing");
- goto free_name;
- }
-
- /* Create the named socket */
- instance->listen_sock = ustcomm_init_named_socket(name,
- instance->epoll_fd);
- if(!instance->listen_sock) {
- ERR("error initializing named socket at %s", name);
- goto close_epoll;
- }
-
- CDS_INIT_LIST_HEAD(&instance->connections);
-
- free(name);
-
- return 0;
-
-close_epoll:
- close(instance->epoll_fd);
-free_name:
- free(name);
-
- return -1;
-}
-
-int ustconsumer_init_instance(struct ustconsumer_instance *instance)
-{
- int result;
- result = init_ustconsumer_socket(instance);
- if(result == -1) {
- ERR("failed to initialize socket");
- return 1;
- }
- instance->is_init = 1;
- return 0;
-}
-
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <byteswap.h>
-
-#include "ust/ustconsumer.h"
-#include "buffers.h"
-#include "tracer.h"
-#include "usterr_signal_safe.h"
-
-/* This truncates to an offset in the buffer. */
-#define USTD_BUFFER_TRUNC(offset, bufinfo) \
- ((offset) & (~(((bufinfo)->subbuf_size*(bufinfo)->n_subbufs)-1)))
-
-#define LTT_MAGIC_NUMBER 0x00D6B7ED
-#define LTT_REV_MAGIC_NUMBER 0xEDB7D600
-
-
-static void ltt_relay_print_subbuffer_errors(
- struct buffer_info *buf,
- long cons_off, int cpu)
-{
- struct ust_buffer *ust_buf = buf->bufstruct_mem;
- long cons_idx, commit_count, commit_count_mask, write_offset;
-
- cons_idx = SUBBUF_INDEX(cons_off, buf);
- commit_count = uatomic_read(&ust_buf->commit_seq[cons_idx]);
- commit_count_mask = (~0UL >> get_count_order(buf->n_subbufs));
-
- /*
- * No need to order commit_count and write_offset reads because we
- * execute after trace is stopped when there are no readers left.
- */
- write_offset = uatomic_read(&ust_buf->offset);
- WARN( "LTT : unread channel %s offset is %ld "
- "and cons_off : %ld (cpu %d)\n",
- buf->channel, write_offset, cons_off, cpu);
- /* Check each sub-buffer for non filled commit count */
- if (((commit_count - buf->subbuf_size) & commit_count_mask)
- - (BUFFER_TRUNC(cons_off, buf) >> get_count_order(buf->n_subbufs)) != 0) {
- ERR("LTT : %s : subbuffer %lu has non filled "
- "commit count [seq] [%lu].\n",
- buf->channel, cons_idx, commit_count);
- }
- ERR("LTT : %s : commit count : %lu, subbuf size %d\n",
- buf->channel, commit_count,
- buf->subbuf_size);
-}
-
-static void ltt_relay_print_errors(struct buffer_info *buf, int cpu)
-{
- struct ust_buffer *ust_buf = buf->bufstruct_mem;
- long cons_off;
-
- for (cons_off = uatomic_read(&ust_buf->consumed);
- (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset), buf)
- - cons_off) > 0;
- cons_off = SUBBUF_ALIGN(cons_off, buf))
- ltt_relay_print_subbuffer_errors(buf, cons_off, cpu);
-}
-
-static void ltt_relay_print_buffer_errors(struct buffer_info *buf, int cpu)
-{
- struct ust_buffer *ust_buf = buf->bufstruct_mem;
-
- if (uatomic_read(&ust_buf->events_lost))
- ERR("channel %s: %ld events lost (cpu %d)",
- buf->channel,
- uatomic_read(&ust_buf->events_lost), cpu);
- if (uatomic_read(&ust_buf->corrupted_subbuffers))
- ERR("channel %s : %ld corrupted subbuffers (cpu %d)",
- buf->channel,
- uatomic_read(&ust_buf->corrupted_subbuffers), cpu);
-
- ltt_relay_print_errors(buf, cpu);
-}
-
-/* Returns the size of a subbuffer size. This is the size that
- * will need to be written to disk.
- *
- * @subbuffer: pointer to the beginning of the subbuffer (the
- * beginning of its header)
- */
-
-size_t subbuffer_data_size(void *subbuf)
-{
- struct ltt_subbuffer_header *header = subbuf;
- int reverse;
- u32 data_size;
-
- if(header->magic_number == LTT_MAGIC_NUMBER) {
- reverse = 0;
- }
- else if(header->magic_number == LTT_REV_MAGIC_NUMBER) {
- reverse = 1;
- }
- else {
- return -1;
- }
-
- data_size = header->sb_size;
- if(reverse)
- data_size = bswap_32(data_size);
-
- return data_size;
-}
-
-
-void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf)
-{
- struct ust_buffer *ust_buf = buf->bufstruct_mem;
- unsigned long n_subbufs_order = get_count_order(buf->n_subbufs);
- unsigned long commit_seq_mask = (~0UL >> n_subbufs_order);
- unsigned long cons_off;
- int ret;
-
- DBG("processing dead buffer (%s)", buf->name);
- DBG("consumed offset is %ld (%s)", uatomic_read(&ust_buf->consumed),
- buf->name);
- DBG("write offset is %ld (%s)", uatomic_read(&ust_buf->offset),
- buf->name);
-
- /*
- * Iterate on subbuffers to recover, including the one the writer
- * just wrote data into. Using write position - 1 since the writer
- * position points into the position that is going to be written.
- */
- for (cons_off = uatomic_read(&ust_buf->consumed);
- (long) (SUBBUF_TRUNC(uatomic_read(&ust_buf->offset) - 1, buf)
- - cons_off) >= 0;
- cons_off = SUBBUF_ALIGN(cons_off, buf)) {
- /*
- * commit_seq is the offset in the buffer of the end of the last sequential commit.
- * Bytes beyond this limit cannot be recovered. This is a free-running counter.
- */
- unsigned long commit_seq =
- uatomic_read(&ust_buf->commit_seq[SUBBUF_INDEX(cons_off, buf)]);
- struct ltt_subbuffer_header *header =
- (struct ltt_subbuffer_header *)((char *) buf->mem
- + SUBBUF_INDEX(cons_off, buf) * buf->subbuf_size);
- unsigned long valid_length;
-
- /* Check if subbuf was fully written. This is from Mathieu's algorithm/paper. */
- if (((commit_seq - buf->subbuf_size) & commit_seq_mask)
- - (USTD_BUFFER_TRUNC(uatomic_read(&ust_buf->consumed), buf) >> n_subbufs_order) == 0
- && header->data_size != 0xffffffff) {
- assert(header->sb_size != 0xffffffff);
- /*
- * If it was fully written, we only check the data_size.
- * This is the amount of valid data at the beginning of
- * the subbuffer.
- */
- valid_length = header->data_size;
- DBG("writing full subbuffer (%ld) with valid_length = %ld",
- SUBBUF_INDEX(cons_off, buf), valid_length);
- } else {
- /*
- * If the subbuffer was not fully written, then we don't
- * check data_size because it hasn't been written yet.
- * Instead we check commit_seq and use it to choose a
- * value for data_size. The viewer will need this value
- * when parsing. Generally, this will happen only for
- * the last subbuffer. However, if we have threads still
- * holding reserved slots in the previous subbuffers,
- * which could happen for other subbuffers prior to the
- * last one. Note that when data_size is set, the
- * commit_seq count is still at a value that shows the
- * amount of valid data to read. It's only _after_
- * writing data_size that commit_seq is updated to
- * include the end-of-buffer padding.
- */
- valid_length = commit_seq & (buf->subbuf_size - 1);
- DBG("writing unfull subbuffer (%ld) with valid_length = %ld",
- SUBBUF_INDEX(cons_off, buf), valid_length);
- header->data_size = valid_length;
- header->sb_size = PAGE_ALIGN(valid_length);
- }
-
- if (callbacks->on_read_partial_subbuffer) {
- ret = callbacks->on_read_partial_subbuffer(callbacks, buf,
- SUBBUF_INDEX(cons_off, buf),
- valid_length);
- if (ret < 0)
- break; /* Error happened */
- }
- }
- /* Increment the consumed offset */
- uatomic_set(&ust_buf->consumed, cons_off);
- ltt_relay_print_buffer_errors(buf, buf->channel_cpu);
-}
-
+++ /dev/null
-/*
- * lowlevel libustd header file
- *
- * Copyright 2005-2010 -
- * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- * Copyright 2010-
- * Oumarou Dicko <oumarou.dicko@polymtl.ca>
- * Michael Sills-Lavoie <michael.sills-lavoie@polymtl.ca>
- * Alexis Halle <alexis.halle@polymtl.ca>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#ifndef LOWLEVEL_H
-#define LOWLEVEL_H
-
-#include "ust/ustconsumer.h"
-
-void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf);
-size_t subbuffer_data_size(void *subbuf);
-
-#endif /* LOWLEVEL_H */
-
+++ /dev/null
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm
-AM_CFLAGS = -fno-strict-aliasing
-
-lib_LTLIBRARIES = libustctl.la
-
-libustctl_la_SOURCES = \
- libustctl.c
-
-libustctl_la_LDFLAGS = -no-undefined -version-info 0:0:0
-
-libustctl_la_LIBADD = \
- $(top_builddir)/libustcomm/libustcomm.la
-
-libustctl_la_CFLAGS = -DUST_COMPONENT="libustctl" -fno-strict-aliasing
+++ /dev/null
-libustctl is a library that provides an API and its implementation to send
-commands to traceable processes.
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette
- * Copyright (C) 2011 Ericsson AB
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <dirent.h>
-
-#include "ustcomm.h"
-#include "ust/ustctl.h"
-#include "usterr.h"
-
-static int do_cmd(int sock,
- const struct ustcomm_header *req_header,
- const char *req_data,
- struct ustcomm_header *res_header,
- char **res_data)
-{
- int result, saved_errno = 0;
- char *recv_buf;
-
- recv_buf = zmalloc(USTCOMM_BUFFER_SIZE);
- if (!recv_buf) {
- saved_errno = ENOMEM;
- goto out;
- }
-
- result = ustcomm_req(sock, req_header, req_data, res_header, recv_buf);
- if (result > 0) {
- saved_errno = -res_header->result;
- if (res_header->size == 0 || saved_errno > 0) {
- free(recv_buf);
- } else {
- if (res_data) {
- *res_data = recv_buf;
- } else {
- free(recv_buf);
- }
- }
- } else {
- ERR("ustcomm req failed");
- if (result == 0) {
- saved_errno = ENOTCONN;
- } else {
- saved_errno = -result;
- }
- free(recv_buf);
- }
-
-out:
- errno = saved_errno;
- if (errno) {
- return -1;
- }
-
- return 0;
-}
-
-int ustctl_connect_pid(pid_t pid)
-{
- int sock;
-
- if (ustcomm_connect_app(pid, &sock)) {
- ERR("could not connect to PID %u", (unsigned int) pid);
- errno = ENOTCONN;
- return -1;
- }
-
- return sock;
-}
-
-static int realloc_pid_list(pid_t **pid_list, unsigned int *pid_list_size)
-{
- pid_t *new_pid_list;
- unsigned int new_pid_list_size = 2 * *pid_list_size;
-
- new_pid_list = realloc(*pid_list,
- new_pid_list_size * sizeof(pid_t));
- if (!*new_pid_list) {
- return -1;
- }
-
- *pid_list = new_pid_list;
- *pid_list_size = new_pid_list_size;
-
- return 0;
-}
-
-static int get_pids_in_dir(DIR *dir, pid_t **pid_list,
- unsigned int *pid_list_index,
- unsigned int *pid_list_size)
-{
- struct dirent *dirent;
- pid_t read_pid;
-
- while ((dirent = readdir(dir))) {
- if (!strcmp(dirent->d_name, ".") ||
- !strcmp(dirent->d_name, "..") ||
- !strcmp(dirent->d_name, "ust-consumer") ||
- dirent->d_type == DT_DIR) {
-
- continue;
- }
-
- if (ustcomm_is_socket_live(dirent->d_name, &read_pid)) {
-
- (*pid_list)[(*pid_list_index)++] = (long) read_pid;
-
- if (*pid_list_index == *pid_list_size) {
- if (realloc_pid_list(pid_list, pid_list_size)) {
- return -1;
- }
- }
- }
- }
-
- (*pid_list)[*pid_list_index] = 0; /* Array end */
-
- return 0;
-}
-
-static pid_t *get_pids_non_root(void)
-{
- char *dir_name;
- DIR *dir;
- unsigned int pid_list_index = 0, pid_list_size = 1;
- pid_t *pid_list = NULL;
-
- dir_name = ustcomm_user_sock_dir();
- if (!dir_name) {
- return NULL;
- }
-
- dir = opendir(dir_name);
- if (!dir) {
- goto free_dir_name;
- }
-
- pid_list = malloc(pid_list_size * sizeof(pid_t));
- if (!pid_list) {
- goto close_dir;
- }
-
- if (get_pids_in_dir(dir, &pid_list, &pid_list_index, &pid_list_size)) {
- /* if any errors are encountered, force freeing of the list */
- pid_list[0] = 0;
- }
-
-close_dir:
- closedir(dir);
-
-free_dir_name:
- free(dir_name);
-
- return pid_list;
-}
-
-static pid_t *get_pids_root(void)
-{
- char *dir_name;
- DIR *tmp_dir, *dir;
- unsigned int pid_list_index = 0, pid_list_size = 1;
- pid_t *pid_list = NULL;
- struct dirent *dirent;
- int result;
-
- tmp_dir = opendir(USER_TMP_DIR);
- if (!tmp_dir) {
- return NULL;
- }
-
- pid_list = malloc(pid_list_size * sizeof(pid_t));
- if (!pid_list) {
- goto close_tmp_dir;
- }
-
- while ((dirent = readdir(tmp_dir))) {
- /* Compare the dir to check for the USER_SOCK_DIR_BASE prefix */
- if (!strncmp(dirent->d_name, USER_SOCK_DIR_BASE,
- strlen(USER_SOCK_DIR_BASE))) {
-
- if (asprintf(&dir_name, USER_TMP_DIR "/%s",
- dirent->d_name) < 0) {
- goto close_tmp_dir;
- }
-
- dir = opendir(dir_name);
-
- free(dir_name);
-
- if (!dir) {
- continue;
- }
-
- result = get_pids_in_dir(dir, &pid_list, &pid_list_index,
- &pid_list_size);
-
- closedir(dir);
-
- if (result) {
- /*
- * if any errors are encountered,
- * force freeing of the list
- */
- pid_list[0] = 0;
- break;
- }
- }
- }
-
-close_tmp_dir:
- closedir(tmp_dir);
-
- return pid_list;
-}
-
-pid_t *ustctl_get_online_pids(void)
-{
- pid_t *pid_list;
-
- if (geteuid()) {
- pid_list = get_pids_non_root();
- } else {
- pid_list = get_pids_root();
- }
-
- if (pid_list && pid_list[0] == 0) {
- /* No PID at all */
- free(pid_list);
- pid_list = NULL;
- }
-
- return pid_list;
-}
-
-/**
- * Sets ust_marker state (USTCTL_MS_ON or USTCTL_MS_OFF).
- *
- * @param mn Marker name
- * @param state Marker's new state
- * @param pid Traced process ID
- * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG}
- */
-int ustctl_set_ust_marker_state(int sock, const char *trace, const char *channel,
- const char *ust_marker, int state)
-{
- struct ustcomm_header req_header, res_header;
- struct ustcomm_ust_marker_info ust_marker_inf;
- int result;
-
- result = ustcomm_pack_ust_marker_info(&req_header,
- &ust_marker_inf,
- trace,
- channel,
- ust_marker);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER;
-
- return do_cmd(sock, &req_header, (char *)&ust_marker_inf,
- &res_header, NULL);
-}
-
-/**
- * Set subbuffer size.
- *
- * @param channel_size Channel name and size
- * @param pid Traced process ID
- * @return 0 if successful, or error
- */
-int ustctl_set_subbuf_size(int sock, const char *trace, const char *channel,
- unsigned int subbuf_size)
-{
- struct ustcomm_header req_header, res_header;
- struct ustcomm_channel_info ch_inf;
- int result;
-
- result = ustcomm_pack_channel_info(&req_header,
- &ch_inf,
- trace,
- channel);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = SET_SUBBUF_SIZE;
- ch_inf.subbuf_size = subbuf_size;
-
- return do_cmd(sock, &req_header, (char *)&ch_inf,
- &res_header, NULL);
-}
-
-/**
- * Set subbuffer num.
- *
- * @param channel_num Channel name and num
- * @param pid Traced process ID
- * @return 0 if successful, or error
- */
-int ustctl_set_subbuf_num(int sock, const char *trace, const char *channel,
- unsigned int num)
-{
- struct ustcomm_header req_header, res_header;
- struct ustcomm_channel_info ch_inf;
- int result;
-
- result = ustcomm_pack_channel_info(&req_header,
- &ch_inf,
- trace,
- channel);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = SET_SUBBUF_NUM;
- ch_inf.subbuf_num = num;
-
- return do_cmd(sock, &req_header, (char *)&ch_inf,
- &res_header, NULL);
-
-}
-
-
-static int ustctl_get_subbuf_num_size(int sock, const char *trace, const char *channel,
- int *num, int *size)
-{
- struct ustcomm_header req_header, res_header;
- struct ustcomm_channel_info ch_inf, *ch_inf_res;
- int result;
-
-
- result = ustcomm_pack_channel_info(&req_header,
- &ch_inf,
- trace,
- channel);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = GET_SUBBUF_NUM_SIZE;
-
- result = do_cmd(sock, &req_header, (char *)&ch_inf,
- &res_header, (char **)&ch_inf_res);
- if (result < 0) {
- return -1;
- }
-
- *num = ch_inf_res->subbuf_num;
- *size = ch_inf_res->subbuf_size;
-
- free(ch_inf_res);
-
- return 0;
-}
-
-/**
- * Get subbuffer num.
- *
- * @param channel Channel name
- * @param pid Traced process ID
- * @return subbuf cnf if successful, or error
- */
-int ustctl_get_subbuf_num(int sock, const char *trace, const char *channel)
-{
- int num, size, result;
-
- result = ustctl_get_subbuf_num_size(sock, trace, channel,
- &num, &size);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- return num;
-}
-
-/**
- * Get subbuffer size.
- *
- * @param channel Channel name
- * @param pid Traced process ID
- * @return subbuf size if successful, or error
- */
-int ustctl_get_subbuf_size(int sock, const char *trace, const char *channel)
-{
- int num, size, result;
-
- result = ustctl_get_subbuf_num_size(sock, trace, channel,
- &num, &size);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- return size;
-}
-
-static int do_trace_cmd(int sock, const char *trace, int command)
-{
- struct ustcomm_header req_header, res_header;
- struct ustcomm_single_field trace_inf;
- int result;
-
- result = ustcomm_pack_single_field(&req_header,
- &trace_inf,
- trace);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = command;
-
- return do_cmd(sock, &req_header, (char *)&trace_inf, &res_header, NULL);
-}
-
-/**
- * Destroys an UST trace according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_destroy_trace(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, DESTROY_TRACE);
-}
-
-/**
- * Starts an UST trace (and setups it) according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_setup_and_start(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, START);
-}
-
-/**
- * Creates an UST trace according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_create_trace(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, CREATE_TRACE);
-}
-
-/**
- * Starts an UST trace according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_start_trace(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, START_TRACE);
-}
-
-/**
- * Alloc an UST trace according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_alloc_trace(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, ALLOC_TRACE);
-}
-
-
-int ustctl_force_switch(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, FORCE_SUBBUF_SWITCH);
-}
-
-/**
- * Stops an UST trace according to a PID.
- *
- * @param pid Traced process ID
- * @return 0 if successful, or error USTCTL_ERR_GEN
- */
-int ustctl_stop_trace(int sock, const char *trace)
-{
- return do_trace_cmd(sock, trace, STOP_TRACE);
-}
-
-/**
- * Counts newlines ('\n') in a string.
- *
- * @param str String to search in
- * @return Total newlines count
- */
-unsigned int ustctl_count_nl(const char *str)
-{
- unsigned int i = 0, tot = 0;
-
- while (str[i] != '\0') {
- if (str[i] == '\n') {
- ++tot;
- }
- ++i;
- }
-
- return tot;
-}
-
-/**
- * Frees a CMSF array.
- *
- * @param cmsf CMSF array to free
- * @return 0 if successful, or error USTCTL_ERR_ARG
- */
-int ustctl_free_cmsf(struct ust_marker_status *cmsf)
-{
- if (cmsf == NULL) {
- return USTCTL_ERR_ARG;
- }
-
- unsigned int i = 0;
- while (cmsf[i].channel != NULL) {
- free(cmsf[i].channel);
- free(cmsf[i].ust_marker);
- free(cmsf[i].fs);
- ++i;
- }
- free(cmsf);
-
- return 0;
-}
-
-/**
- * Gets channel/ust_marker/state/format string for a given PID.
- *
- * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
- * frees with `ustctl_free_cmsf')
- * @param pid Targeted PID
- * @return 0 if successful, or -1 on error
- */
-int ustctl_get_cmsf(int sock, struct ust_marker_status **cmsf)
-{
- struct ustcomm_header req_header, res_header;
- char *big_str = NULL;
- int result;
- struct ust_marker_status *tmp_cmsf = NULL;
- unsigned int i = 0, cmsf_ind = 0;
-
- if (cmsf == NULL) {
- return -1;
- }
-
- req_header.command = LIST_MARKERS;
- req_header.size = 0;
-
- result = ustcomm_send(sock, &req_header, NULL);
- if (result <= 0) {
- PERROR("error while requesting ust_marker list");
- return -1;
- }
-
- result = ustcomm_recv_alloc(sock, &res_header, &big_str);
- if (result <= 0) {
- ERR("error while receiving ust_marker list");
- return -1;
- }
-
- tmp_cmsf = (struct ust_marker_status *) zmalloc(sizeof(struct ust_marker_status) *
- (ustctl_count_nl(big_str) + 1));
- if (tmp_cmsf == NULL) {
- ERR("Failed to allocate CMSF array");
- return -1;
- }
-
- /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
- while (big_str[i] != '\0') {
- char state;
-
- sscanf(big_str + i, "ust_marker: %a[^/]/%a[^ ] %c %a[^\n]",
- &tmp_cmsf[cmsf_ind].channel,
- &tmp_cmsf[cmsf_ind].ust_marker,
- &state,
- &tmp_cmsf[cmsf_ind].fs);
- tmp_cmsf[cmsf_ind].state = (state == USTCTL_MS_CHR_ON ?
- USTCTL_MS_ON : USTCTL_MS_OFF); /* Marker state */
-
- while (big_str[i] != '\n') {
- ++i; /* Go to next '\n' */
- }
- ++i; /* Skip current pointed '\n' */
- ++cmsf_ind;
- }
- tmp_cmsf[cmsf_ind].channel = NULL;
- tmp_cmsf[cmsf_ind].ust_marker = NULL;
- tmp_cmsf[cmsf_ind].fs = NULL;
-
- *cmsf = tmp_cmsf;
-
- free(big_str);
- return 0;
-}
-
-/**
- * Frees a TES array.
- *
- * @param tes TES array to free
- * @return 0 if successful, or error USTCTL_ERR_ARG
- */
-int ustctl_free_tes(struct trace_event_status *tes)
-{
- if (tes == NULL) {
- return USTCTL_ERR_ARG;
- }
-
- unsigned int i = 0;
- while (tes[i].name != NULL) {
- free(tes[i].name);
- ++i;
- }
- free(tes);
-
- return 0;
-}
-
-/**
- * Gets trace_events string for a given PID.
- *
- * @param tes Pointer to TES array to be filled (callee allocates, caller
- * frees with `ustctl_free_tes')
- * @param pid Targeted PID
- * @return 0 if successful, or -1 on error
- */
-int ustctl_get_tes(int sock, struct trace_event_status **tes)
-{
- struct ustcomm_header req_header, res_header;
- char *big_str = NULL;
- int result;
- struct trace_event_status *tmp_tes = NULL;
- unsigned int i = 0, tes_ind = 0;
-
- if (tes == NULL) {
- return -1;
- }
-
- req_header.command = LIST_TRACE_EVENTS;
- req_header.size = 0;
-
- result = ustcomm_send(sock, &req_header, NULL);
- if (result != 1) {
- ERR("error while requesting trace_event list");
- return -1;
- }
-
- result = ustcomm_recv_alloc(sock, &res_header, &big_str);
- if (result != 1) {
- ERR("error while receiving ust_marker list");
- return -1;
- }
-
- tmp_tes = (struct trace_event_status *)
- zmalloc(sizeof(struct trace_event_status) *
- (ustctl_count_nl(big_str) + 1));
- if (tmp_tes == NULL) {
- ERR("Failed to allocate TES array");
- return -1;
- }
-
- /* Parse received reply string (format: "[name]"): */
- while (big_str[i] != '\0') {
- sscanf(big_str + i, "trace_event: %a[^\n]",
- &tmp_tes[tes_ind].name);
- while (big_str[i] != '\n') {
- ++i; /* Go to next '\n' */
- }
- ++i; /* Skip current pointed '\n' */
- ++tes_ind;
- }
- tmp_tes[tes_ind].name = NULL;
-
- *tes = tmp_tes;
-
- free(big_str);
- return 0;
-}
-
-/**
- * Set sock path
- *
- * @param sock_path Sock path
- * @param pid Traced process ID
- * @return 0 if successful, or error
- */
-int ustctl_set_sock_path(int sock, const char *sock_path)
-{
- int result;
- struct ustcomm_header req_header, res_header;
- struct ustcomm_single_field sock_path_msg;
-
- result = ustcomm_pack_single_field(&req_header,
- &sock_path_msg,
- sock_path);
- if (result < 0) {
- errno = -result;
- return -1;
- }
-
- req_header.command = SET_SOCK_PATH;
-
- return do_cmd(sock, &req_header, (char *)&sock_path_msg,
- &res_header, NULL);
-}
-
-/**
- * Get sock path
- *
- * @param sock_path Pointer to where the sock path will be returned
- * @param pid Traced process ID
- * @return 0 if successful, or error
- */
-int ustctl_get_sock_path(int sock, char **sock_path)
-{
- int result;
- struct ustcomm_header req_header, res_header;
- struct ustcomm_single_field *sock_path_msg;
-
- req_header.command = GET_SOCK_PATH;
- req_header.size = 0;
-
- result = do_cmd(sock, &req_header, NULL, &res_header,
- (char **)&sock_path_msg);
- if (result < 0) {
- return -1;
- }
-
- result = ustcomm_unpack_single_field(sock_path_msg);
- if (result < 0) {
- return result;
- }
-
- *sock_path = strdup(sock_path_msg->field);
-
- free(sock_path_msg);
-
- return 0;
-}
+++ /dev/null
-AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
- -I$(top_srcdir)/include -I$(top_srcdir)/libustconsumer
-AM_CFLAGS = -fno-strict-aliasing
-
-bin_PROGRAMS = ust-consumerd
-
-ust_consumerd_SOURCES = ust-consumerd.c
-
-ust_consumerd_LDADD = \
- $(top_builddir)/snprintf/libustsnprintf.la \
- $(top_builddir)/libustcomm/libustcomm.la \
- $(top_builddir)/libustconsumer/libustconsumer.la
-
-ust_consumerd_CFLAGS = -DUST_COMPONENT=ust-consumerd -fno-strict-aliasing
+++ /dev/null
-This is ust-consumerd, the UST consumer daemon.
-
-This daemon is used to collect the traces for the traced programs and write them to disk.
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- * 2010 Alexis Halle
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/shm.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <inttypes.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <getopt.h>
-
-#include "ust/ustconsumer.h"
-#include "../libustconsumer/lowlevel.h"
-#include "usterr.h"
-
-char *sock_path=NULL;
-char *trace_path=NULL;
-int daemon_mode = 0;
-char *pidfile = NULL;
-
-struct ustconsumer_instance *instance;
-
-struct buffer_info_local {
- /* output file */
- int file_fd;
- /* the offset we must truncate to, to unput the last subbuffer */
- off_t previous_offset;
-};
-
-static int write_pidfile(const char *file_name, pid_t pid)
-{
- FILE *pidfp;
-
- pidfp = fopen(file_name, "w");
- if(!pidfp) {
- PERROR("fopen (%s)", file_name);
- WARN("killing child process");
- return -1;
- }
-
- fprintf(pidfp, "%d\n", pid);
-
- fclose(pidfp);
-
- return 0;
-}
-
-int create_dir_if_needed(char *dir)
-{
- int result;
- result = mkdir(dir, 0777);
- if(result == -1) {
- if(errno != EEXIST) {
- PERROR("mkdir");
- return -1;
- }
- }
-
- return 0;
-}
-
-int unwrite_last_subbuffer(struct buffer_info *buf)
-{
- int result;
- struct buffer_info_local *buf_local = buf->user_data;
-
- result = ftruncate(buf_local->file_fd, buf_local->previous_offset);
- if(result == -1) {
- PERROR("ftruncate");
- return -1;
- }
-
- result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET);
- if(result == (int)(off_t)-1) {
- PERROR("lseek");
- return -1;
- }
-
- return 0;
-}
-
-int write_current_subbuffer(struct buffer_info *buf)
-{
- int result;
- struct buffer_info_local *buf_local = buf->user_data;
-
- void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1));
-
- size_t cur_sb_size = subbuffer_data_size(subbuf_mem);
-
- off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR);
- if(cur_offset == (off_t)-1) {
- PERROR("lseek");
- return -1;
- }
-
- buf_local->previous_offset = cur_offset;
- DBG("previous_offset: %ld", cur_offset);
-
- result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size);
- if(result == -1) {
- PERROR("write");
- return -1;
- }
-
- return 0;
-}
-
-int on_read_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
-{
- return write_current_subbuffer(buf);
-}
-
-int on_read_partial_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf,
- long subbuf_index, unsigned long valid_length)
-{
- struct buffer_info_local *buf_local = buf->user_data;
- char *tmp;
- int result;
- unsigned long pad_size;
-
- result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length);
- if(result == -1) {
- ERR("Error writing to buffer file");
- return result;
- }
-
- /* pad with empty bytes */
- pad_size = PAGE_ALIGN(valid_length)-valid_length;
- if(pad_size) {
- tmp = zmalloc(pad_size);
- result = patient_write(buf_local->file_fd, tmp, pad_size);
- if(result == -1) {
- ERR("Error writing to buffer file");
- return result;
- }
- free(tmp);
- }
- return result;
-}
-
-int on_open_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
-{
- char *tmp;
- int result;
- int fd;
- struct buffer_info_local *buf_local =
- zmalloc(sizeof(struct buffer_info_local));
-
- if(!buf_local) {
- ERR("could not allocate buffer_info_local struct");
- return 1;
- }
-
- buf->user_data = buf_local;
-
- /* open file for output */
- if(!trace_path) {
- /* Only create the directory if using the default path, because
- * of the risk of typo when using trace path override. We don't
- * want to risk creating plenty of useless directories in that case.
- */
- result = create_dir_if_needed(USTCONSUMER_DEFAULT_TRACE_PATH);
- if(result == -1) {
- ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH);
- return 1;
- }
-
- trace_path = USTCONSUMER_DEFAULT_TRACE_PATH;
- }
-
- if (asprintf(&tmp, "%s/%u_%" PRId64 "", trace_path, buf->pid, buf->pidunique) < 0) {
- ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 ")",
- trace_path, buf->pid, buf->pidunique);
- return 1;
- }
- result = create_dir_if_needed(tmp);
- if(result == -1) {
- ERR("could not create directory %s", tmp);
- free(tmp);
- return 1;
- }
- free(tmp);
-
- if (asprintf(&tmp, "%s/%u_%" PRId64 "/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) {
- ERR("on_open_buffer : asprintf failed (%s/%u_%" PRId64 "/%s)",
- trace_path, buf->pid, buf->pidunique, buf->name);
- return 1;
- }
-again:
- result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
- if (result == -1 && errno == EINTR)
- goto again;
-
- if(result == -1) {
- PERROR("open");
- ERR("failed opening trace file %s", tmp);
- return 1;
- }
- buf_local->file_fd = fd;
- free(tmp);
-
- return 0;
-}
-
-int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
-{
- struct buffer_info_local *buf_local = buf->user_data;
- int result;
-
-again:
- result = close(buf_local->file_fd);
- if (result == -1 && errno == EINTR)
- goto again;
- free(buf_local);
- if(result == -1) {
- PERROR("close");
- }
- return 0;
-}
-
-int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf)
-{
- return unwrite_last_subbuffer(buf);
-}
-
-struct ustconsumer_callbacks *new_callbacks()
-{
- struct ustconsumer_callbacks *callbacks =
- zmalloc(sizeof(struct ustconsumer_callbacks));
-
- if(!callbacks)
- return NULL;
-
- callbacks->on_open_buffer = on_open_buffer;
- callbacks->on_close_buffer = on_close_buffer;
- callbacks->on_read_subbuffer = on_read_subbuffer;
- callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer;
- callbacks->on_put_error = on_put_error;
- callbacks->on_new_thread = NULL;
- callbacks->on_close_thread = NULL;
- callbacks->on_trace_end = NULL;
-
- return callbacks;
-
-}
-
-int is_directory(const char *dir)
-{
- int result;
- struct stat st;
-
- result = stat(dir, &st);
- if(result == -1) {
- PERROR("stat");
- return 0;
- }
-
- if(!S_ISDIR(st.st_mode)) {
- return 0;
- }
-
- return 1;
-}
-
-void usage(void)
-{
- fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n"
- "\t-h\t\tDisplay this usage.\n"
- "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
- "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
- "\t-d\t\tStart as a daemon.\n"
- "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
-}
-
-int parse_args(int argc, char **argv)
-{
- int c;
-
- while (1) {
- int option_index = 0;
- static struct option long_options[] = {
- {"pidfile", 1, 0, 'p'},
- {"help", 0, 0, 'h'},
- {"version", 0, 0, 'V'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 0:
- printf("option %s", long_options[option_index].name);
- if (optarg)
- printf(" with arg %s", optarg);
- printf("\n");
- break;
- case 's':
- sock_path = optarg;
- break;
- case 'o':
- trace_path = optarg;
- if(!is_directory(trace_path)) {
- ERR("Not a valid directory. (%s)", trace_path);
- return -1;
- }
- break;
- case 'd':
- daemon_mode = 1;
- break;
- case 'p':
- pidfile = strdup(optarg);
- break;
- case 'h':
- usage();
- exit(0);
- case 'V':
- printf("Version 0.0\n");
- break;
-
- default:
- /* unknown option or other error; error is
- printed by getopt, just return */
- return -1;
- }
- }
-
- return 0;
-}
-
-void sigterm_handler(int sig)
-{
- ustconsumer_stop_instance(instance, 0);
-}
-
-int start_ustconsumer(int fd)
-{
- int result;
- sigset_t sigset;
- struct sigaction sa;
-
- struct ustconsumer_callbacks *callbacks = new_callbacks();
- if(!callbacks) {
- PERROR("new_callbacks");
- return 1;
- }
-
- result = sigemptyset(&sigset);
- if(result == -1) {
- PERROR("sigemptyset");
- return 1;
- }
- sa.sa_handler = sigterm_handler;
- sa.sa_mask = sigset;
- sa.sa_flags = 0;
- result = sigaction(SIGTERM, &sa, NULL);
- if(result == -1) {
- PERROR("sigaction");
- return 1;
- }
- result = sigaction(SIGINT, &sa, NULL);
- if(result == -1) {
- PERROR("sigaction");
- return 1;
- }
-
- instance = ustconsumer_new_instance(callbacks, sock_path);
- if(!instance) {
- ERR("failed to create ustconsumer instance");
- return 1;
- }
-
- result = ustconsumer_init_instance(instance);
- if(result) {
- ERR("failed to initialize ustconsumer instance");
- return 1;
- }
-
- /* setup handler for SIGPIPE */
- result = sigemptyset(&sigset);
- if(result == -1) {
- PERROR("sigemptyset");
- return 1;
- }
- result = sigaddset(&sigset, SIGPIPE);
- if(result == -1) {
- PERROR("sigaddset");
- return 1;
- }
- result = sigprocmask(SIG_BLOCK, &sigset, NULL);
- if(result == -1) {
- PERROR("sigprocmask");
- return 1;
- }
-
- /* Write pidfile */
- if(pidfile) {
- result = write_pidfile(pidfile, getpid());
- if(result == -1) {
- ERR("failed to write pidfile");
- return 1;
- }
- }
-
- /* Notify parent that we are successfully started. */
- if(fd != -1) {
- /* write any one character */
- result = write(fd, "!", 1);
- if(result == -1) {
- PERROR("write");
- return -1;
- }
- if(result != 1) {
- ERR("Problem sending confirmation of daemon start to parent");
- return -1;
- }
- result = close(fd);
- if(result == -1) {
- PERROR("close");
- }
- }
-
- ustconsumer_start_instance(instance);
-
- free(callbacks);
-
- return 0;
-}
-
-int start_ustconsumer_daemon()
-{
- int result;
- int fd[2];
- pid_t child_pid;
-
- result = pipe(fd);
-
- result = child_pid = fork();
- if(result == -1) {
- PERROR("fork");
- return -1;
- }
- else if(result == 0) {
- return start_ustconsumer(fd[1]);
- }
- else {
- char buf;
-
- result = read(fd[0], &buf, 1);
- if(result == -1) {
- PERROR("read");
- return -1;
- }
- if(result != 1) {
- ERR("did not receive valid confirmation that the daemon is started");
- return -1;
- }
-
- result = close(fd[0]);
- if(result == -1) {
- PERROR("close");
- }
-
- DBG("The daemon is now successfully started");
- }
-
- /* Wait for confirmation that the server is ready. */
-
-
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int result;
-
- result = parse_args(argc, argv);
- if(result == -1) {
- exit(1);
- }
-
- if(daemon_mode) {
- result = start_ustconsumer_daemon();
- }
- else {
- result = start_ustconsumer(-1);
- }
-
- return result;
-}
+++ /dev/null
-/*
- * libustconsumer header file
- *
- * Copyright 2005-2010 -
- * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- * Copyright 2010-
- * Oumarou Dicko <oumarou.dicko@polymtl.ca>
- * Michael Sills-Lavoie <michael.sills-lavoie@polymtl.ca>
- * Alexis Halle <alexis.halle@polymtl.ca>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#ifndef _USTCONSUMER_H
-#define _USTCONSUMER_H
-
-#include <pthread.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <urcu/list.h>
-
-#define USTCONSUMER_DEFAULT_TRACE_PATH "/tmp/usttrace"
-
-struct ustcomm_sock;
-
-struct buffer_info {
- char *name;
- char *trace;
- char *channel;
- int channel_cpu;
-
- pid_t pid;
- int app_sock;
- /* The pipe file descriptor */
- int pipe_fd;
-
- int shmid;
- int bufstruct_shmid;
-
- /* the buffer memory */
- void *mem;
- /* buffer size */
- int memlen;
- /* number of subbuffers in buffer */
- int n_subbufs;
- /* size of each subbuffer */
- int subbuf_size;
- /* subbuf size count order */
- int subbuf_size_order;
- /* alloc size of all subbuf */
- int alloc_size;
-
- /* the buffer information struct */
- void *bufstruct_mem;
-
- long consumed_old;
-
- int64_t pidunique;
-
- void *user_data;
-};
-
-struct ustconsumer_callbacks;
-
-/**
- * struct ustconsumer_instance - Contains the data associated with a trace instance.
- * The lib user can read but MUST NOT change any attributes but callbacks.
- * @callbacks: Contains the necessary callbacks for a tracing session.
- */
-struct ustconsumer_instance {
- struct ustconsumer_callbacks *callbacks;
- int quit_program;
- int is_init;
- struct cds_list_head connections;
- int epoll_fd;
- struct ustcomm_sock *listen_sock;
- char *sock_path;
- pthread_mutex_t mutex;
- int active_buffers;
- int active_threads;
-};
-
-/**
-* struct ustconsumer_callbacks - Contains the necessary callbacks for a tracing
-* session. The user can set the unnecessary functions to NULL if he does not
-* need them.
-*/
-struct ustconsumer_callbacks {
- /**
- * on_open_buffer - Is called after a buffer is attached to process memory
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- * @buf: structure that contains the data associated with the buffer
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_open_buffer)(struct ustconsumer_callbacks *data,
- struct buffer_info *buf);
-
- /**
- * on_close_buffer - Is called after a buffer is detached from process memory
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- * @buf: structure that contains the data associated with the buffer
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_close_buffer)(struct ustconsumer_callbacks *data,
- struct buffer_info *buf);
-
- /**
- * on_read_subbuffer - Is called after a subbuffer is a reserved.
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- * @buf: structure that contains the data associated with the buffer
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_read_subbuffer)(struct ustconsumer_callbacks *data,
- struct buffer_info *buf);
-
- /**
- * on_read_partial_subbuffer - Is called when an incomplete subbuffer
- * is being salvaged from an app crash
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- * @buf: structure that contains the data associated with the buffer
- * @subbuf_index: index of the subbuffer to read in the buffer
- * @valid_length: number of bytes considered safe to read
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_read_partial_subbuffer)(struct ustconsumer_callbacks *data,
- struct buffer_info *buf,
- long subbuf_index,
- unsigned long valid_length);
-
- /**
- * on_put_error - Is called when a put error has occured and the last
- * subbuffer read is no longer safe to keep
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- * @buf: structure that contains the data associated with the buffer
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_put_error)(struct ustconsumer_callbacks *data,
- struct buffer_info *buf);
-
- /**
- * on_new_thread - Is called when a new thread is created
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_new_thread)(struct ustconsumer_callbacks *data);
-
- /**
- * on_close_thread - Is called just before a thread is destroyed
- *
- * @data: pointer to the callbacks structure that has been passed to the
- * library.
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * It has to be thread safe, because it is called by many threads.
- */
- int (*on_close_thread)(struct ustconsumer_callbacks *data);
-
- /**
- * on_trace_end - Is called at the very end of the tracing session. At
- * this time, everything has been closed and the threads have
- * been destroyed.
- *
- * @instance: pointer to the instance structure that has been passed to
- * the library.
- *
- * Returns 0 if the callback succeeds else not 0.
- *
- * After this callback is called, no other callback will be called
- * again and the tracing instance will be deleted automatically by
- * libustconsumer. After this call, the user must not use the libustconsumer instance.
- */
- int (*on_trace_end)(struct ustconsumer_instance *instance);
-
- /**
- * The library's data.
- */
- void *user_data;
-};
-
-/**
- * ustconsumer_new_instance - Is called to create a new tracing session.
- *
- * @callbacks: Pointer to a callbacks structure that contain the user
- * callbacks and data.
- * @sock_path: Path to the socket used for communication with the traced app
- *
- * Returns the instance if the function succeeds else NULL.
- */
-struct ustconsumer_instance *
-ustconsumer_new_instance(
- struct ustconsumer_callbacks *callbacks, char *sock_path);
-
-/**
- * ustconsumer_delete_instance - Is called to free a ustconsumer_instance struct
- *
- * @instance: The tracing session instance that needs to be freed.
- *
- * This function should only be called if the instance has not been started,
- * as it will automatically be called at the end of ustconsumer_start_instance.
- */
-void ustconsumer_delete_instance(struct ustconsumer_instance *instance);
-
-/**
- * ustconsumer_init_instance - Is called to initiliaze a new tracing session
- *
- * @instance: The tracing session instance that needs to be started.
- *
- * Returns 0 if the function succeeds.
- *
- * This function must be called between ustconsumer_new_instance and
- * ustconsumer_start_instance. It sets up the communication between the library
- * and the tracing application.
- */
-int ustconsumer_init_instance(struct ustconsumer_instance *instance);
-
-/**
- * ustconsumer_start_instance - Is called to start a new tracing session.
- *
- * @instance: The tracing session instance that needs to be started.
- *
- * Returns 0 if the function succeeds.
- *
- * This is a blocking function. The caller will be blocked on it until the
- * tracing session is stopped by the user using ustconsumer_stop_instance or until
- * the traced application terminates
- */
-int ustconsumer_start_instance(struct ustconsumer_instance *instance);
-
-/**
- * ustconsumer_stop_instance - Is called to stop a tracing session.
- *
- * @instance: The tracing session instance that needs to be stoped.
- * @send_msg: If true, a message will be sent to the listening thread through
- * the daemon socket to force it to return from the poll syscall
- * and realize that it must close. This is not necessary if the
- * instance is being stopped as part of an interrupt handler, as
- * the interrupt itself will cause poll to return.
- *
- * Returns 0 if the function succeeds.
- *
- * This function returns immediately, it only tells libustconsumer to stop the
- * instance. The on_trace_end callback will be called when the tracing session
- * will really be stopped. The instance is deleted automatically by libustconsumer
- * after on_trace_end is called.
- */
-int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg);
-
-#endif /* _USTCONSUMER_H */
-
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#ifndef _USTCTL_H
-#define _USTCTL_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#define USTCTL_ERR_CONN 1 /* Process connection error */
-#define USTCTL_ERR_ARG 2 /* Invalid function argument */
-#define USTCTL_ERR_GEN 3 /* General ustctl error */
-
-#define USTCTL_MS_CHR_OFF '0' /* Marker state 'on' character */
-#define USTCTL_MS_CHR_ON '1' /* Marker state 'on' character */
-#define USTCTL_MS_OFF 0 /* Marker state 'on' value */
-#define USTCTL_MS_ON 1 /* Marker state 'on' value */
-
-#define USTCTL_SOCK_PATH "/tmp/socks/"
-
-/* Channel/marker/state/format string (cmsf) info. structure */
-struct ust_marker_status {
- char *channel; /* Channel name (end of ust_marker_status array if NULL) */
- char *ust_marker; /* Marker name (end of ust_marker_status array if NULL) */
- int state; /* State (0 := marker disabled, 1 := marker enabled) */
- char *fs; /* Format string (end of ust_marker_status array if NULL) */
-};
-
-struct trace_event_status {
- char *name;
-};
-
-extern pid_t *ustctl_get_online_pids(void);
-
-extern int ustctl_connect_pid(pid_t pid);
-
-extern int ustctl_set_ust_marker_state(int sock, const char *trace,
- const char *channel, const char *ust_marker,
- int state);
-
-extern int ustctl_set_subbuf_size(int sock, const char *trace,
- const char *channel,
- unsigned int subbuf_size);
-
-extern int ustctl_set_subbuf_num(int sock, const char *trace,
- const char *channel,
- unsigned int num);
-
-extern int ustctl_get_subbuf_size(int sock, const char *trace,
- const char *channel);
-
-extern int ustctl_get_subbuf_num(pid_t pid, const char *trace,
- const char *channel);
-
-extern int ustctl_destroy_trace(int sock, const char *trace);
-
-extern int ustctl_setup_and_start(int sock, const char *trace);
-
-extern int ustctl_stop_trace(int sock, const char *trace);
-
-extern int ustctl_create_trace(int sock, const char *trace);
-
-extern int ustctl_start_trace(int sock, const char *trace);
-
-extern int ustctl_alloc_trace(int sock, const char *trace);
-
-extern int ustctl_free_cmsf(struct ust_marker_status *);
-extern int ustctl_free_tes(struct trace_event_status *);
-extern unsigned int ustctl_count_nl(const char *);
-
-extern int ustctl_get_cmsf(int sock, struct ust_marker_status **);
-
-extern int ustctl_get_tes(int sock, struct trace_event_status **);
-
-extern int ustctl_set_sock_path(int sock, const char *sock_path);
-
-extern int ustctl_get_sock_path(int sock, char **sock_path);
-
-extern int ustctl_force_switch(int sock, const char *trace);
-
-#endif /* _USTCTL_H */
+++ /dev/null
-AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libustcomm \
- -I$(top_srcdir)/libustctl $(KCOMPAT_CFLAGS)
-AM_CFLAGS = -fno-strict-aliasing
-
-bin_PROGRAMS = ustctl
-
-ustctl_SOURCES = \
- ustctl.c marker_cmds.c trace_cmds.c channel_cmds.c cli.c cli.h scanning_functions.c scanning_functions.h
-
-ustctl_CFLAGS = -DUST_COMPONENT=ustctl -fno-strict-aliasing
-
-ustctl_LDADD = \
- $(top_builddir)/snprintf/libustsnprintf.la \
- $(top_builddir)/libustcomm/libustcomm.la \
- $(top_builddir)/libustctl/libustctl.la
+++ /dev/null
-ustctl is a helper application used to control tracing on programs that support tracing.
-
-It can list markers, enable/disable markers, start tracing and stop tracing.
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <ust/ustctl.h>
-#include "scanning_functions.h"
-#include "usterr.h"
-#include "cli.h"
-
-static int set_subbuf_size(int argc, char *argv[])
-{
- int sock, result = 0;
- char *channel = NULL;
- unsigned int size;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (scan_ch_and_num(argv[3], &channel, &size)) {
- fprintf(stderr, "Failed to scan channel and size from"
- " %s\n", argv[3]);
- if (channel)
- free(channel);
- return -1;
- }
- if (ustctl_set_subbuf_size(sock, argv[2], channel, size)) {
- ERR("error while trying to set the size of subbuffers "
- "for PID %s\n",
- argv[1]);
- result = -1;
- }
-
- free(channel);
-
- return result;
-}
-
-static int set_subbuf_num(int argc, char *argv[])
-{
- int sock, result = 0;
- char *channel = NULL;
- unsigned int num;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (scan_ch_and_num(argv[3], &channel, &num)) {
- fprintf(stderr, "Failed to scan channel and number from"
- " %s\n", argv[3]);
- if (channel)
- free(channel);
- return -1;
- }
- if (ustctl_set_subbuf_num(sock, argv[2], channel, num)) {
- ERR("error while trying to set the number of subbuffers for PID %s\n",
- argv[1]);
- result = -1;
- }
-
- free(channel);
-
- return result;
-}
-
-static int get_subbuf_size(int argc, char *argv[])
-{
- int sock;
- unsigned int size;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if ((size = ustctl_get_subbuf_size(sock, argv[2], argv[3])) < 0) {
- ERR("error while trying to get the subbuffer size from PID %s\n",
- argv[1]);
- return -1;
- }
-
- printf("The subbufer size is %d bytes\n", size);
-
- return 0;
-}
-
-static int get_subbuf_num(int argc, char *argv[])
-{
- int sock;
- unsigned int num;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if ((num = ustctl_get_subbuf_num(sock, argv[2], argv[3])) < 0) {
- ERR("error while trying to get the subbuffer size from PID %s\n",
- argv[1]);
- return -1;
- }
-
- printf("There are %u subbufers in each buffer\n", num);
-
- return 0;
-}
-
-struct cli_cmd __cli_cmds channel_cmds[] = {
- {
- .name = "set-subbuf-size",
- .description = "Set the subbuffer size for a channel",
- .help_text = "set-subbuf-size <pid> <trace> <channel>/<size> \n"
- "Set the subbuffer size for a channel\n",
- .function = set_subbuf_size,
- .desired_args = 3,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "set-subbuf-num",
- .description = "Set the number of subbuffers for a channel",
- .help_text = "set-subbuf-num <pid> <trace> <channel>/<num> \n"
- "Set the number of subbuffers for a channel\n",
- .function = set_subbuf_num,
- .desired_args = 3,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "get-subbuf-size",
- .description = "Get the subbuffer size for a channel",
- .help_text = "get-subbuf-size <pid> <trace> <channel>\n"
- "Get the subbuffer size for a channel\n",
- .function = get_subbuf_size,
- .desired_args = 3,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "get-subbuf-num",
- .description = "Get the number of subbuffers for a channel",
- .help_text = "get-subbuf-num <pid> <trace> <channel>\n"
- "Get the number of subbuffers for a channel\n",
- .function = get_subbuf_num,
- .desired_args = 3,
- .desired_args_op = CLI_EQ,
- },
-};
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "cli.h"
-
-/* This dummy command is needed to create the sections in cli.o before
- * other .o files have these sections, usefull for development.
- */
-static int _dummy(int argc, char *argv[]) {
- return 0;
-}
-
-/* Define a dummy cmd to guarantee existence of the builtin variables */
-struct cli_cmd __cli_cmds __dummy_cli_cmd[] = {
- {
- .name = "_dummy",
- .description = NULL,
- .help_text = NULL,
- .function = _dummy,
- .desired_args = 0,
- .desired_args_op = 0,
- },
-};
-
-extern struct cli_cmd __start___cli_cmds[] __attribute__((visibility("hidden")));
-extern struct cli_cmd __stop___cli_cmds[] __attribute__((visibility("hidden")));
-
-static struct cli_cmd **cli_cmd_list;
-static int cli_cmd_list_size;
-
-static char *process_name;
-
-static int compute_cli_cmds_size(void)
-{
- long cli_cmds_start, cli_cmds_end;
-
- cli_cmds_start = (long)__start___cli_cmds;
- cli_cmds_end = (long)__stop___cli_cmds;
-
- return (cli_cmds_end - cli_cmds_start) / sizeof(struct cli_cmd);
-}
-
-static void __attribute__((constructor)) generate_cli_cmd_list(int argc, char *argv[])
-{
- struct cli_cmd *cli_cmd;
- int section_size, i;
-
- process_name = basename(argv[0]);
-
- section_size = compute_cli_cmds_size();
-
- cli_cmd_list = malloc(section_size * sizeof(void *));
- if (!cli_cmd_list) {
- fprintf(stderr, "Failed to allocate command list!");
- exit(EXIT_FAILURE);
- }
-
- cli_cmd_list_size = 0;
-
- cli_cmd = __start___cli_cmds;
- for (i = 0; i < section_size; i++) {
- if (&cli_cmd[i] == &__dummy_cli_cmd[0]) {
- continue;
- }
-
- if (cli_cmd[i].name) {
- cli_cmd_list[cli_cmd_list_size++] = &cli_cmd[i];
- }
- }
-}
-
-struct cli_cmd *find_cli_cmd(const char *command)
-{
- int i;
-
- for (i = 0; i < cli_cmd_list_size; i++) {
- if (!strcmp(cli_cmd_list[i]->name, command)) {
- return cli_cmd_list[i];
- }
- }
-
- return NULL;
-}
-
-static int cmpcli_cmds(const void *p1, const void *p2)
-{
- return strcmp(* (char * const *) ((struct cli_cmd *)p1)->name,
- * (char * const *) ((struct cli_cmd *)p2)->name);
-}
-
-#define HELP_BUFFER_SIZE 4096
-
-static void print_cmd_help(const char *prefix, const char *infix,
- struct cli_cmd *cli_cmd)
-{
- if (cli_cmd->help_text) {
- fprintf(stderr, "%s%s%s",
- prefix,
- infix,
- cli_cmd->help_text);
- } else if (cli_cmd->description) {
- fprintf(stderr, "%s%s%s\n%s\n",
- prefix,
- infix,
- cli_cmd->name,
- cli_cmd->description);
- } else {
- fprintf(stderr, "No help available for %s\n",
- cli_cmd->name);
- }
-}
-
-void list_cli_cmds(int option)
-{
- int i;
-
- qsort(cli_cmd_list, cli_cmd_list_size, sizeof(void *), cmpcli_cmds);
-
- for (i = 0; i < cli_cmd_list_size; i++) {
- switch (option) {
- case CLI_SIMPLE_LIST:
- fprintf(stderr, "%s ", cli_cmd_list[i]->name);
- break;
- case CLI_DESCRIPTIVE_LIST:
- fprintf(stderr, " %-25s%s\n", cli_cmd_list[i]->name,
- cli_cmd_list[i]->description);
- break;
- case CLI_EXTENDED_LIST:
- print_cmd_help("", "", cli_cmd_list[i]);
- fprintf(stderr, "\n");
- break;
- }
- }
-
- if (option == CLI_SIMPLE_LIST) {
- fprintf(stderr, "\n");
- }
-}
-
-int cli_print_help(const char *command)
-{
- struct cli_cmd *cli_cmd;
-
- cli_cmd = find_cli_cmd(command);
- if (!cli_cmd) {
- return -1;
- }
-
- print_cmd_help(process_name, " ", cli_cmd);
-
- return 0;
-}
-
-static void cli_check_argc(const char *command, int args,
- int operator, int desired_args)
-{
- switch(operator) {
- case CLI_EQ:
- if (args != desired_args)
- goto print_error;
- break;
- case CLI_GE:
- if (args < desired_args)
- goto print_error;
- break;
- }
-
- return;
-
-print_error:
- fprintf(stderr, "%s %s requires %s%d argument%s, see usage.\n",
- process_name, command, operator == CLI_EQ ? "" : "at least ",
- desired_args, desired_args > 1 ? "s" : "");
- cli_print_help(command);
- exit(EXIT_FAILURE);
-}
-
-
-void cli_dispatch_cmd(struct cli_cmd *cmd, int argc, char *argv[])
-{
- cli_check_argc(cmd->name, argc - 1, cmd->desired_args_op,
- cmd->desired_args);
-
- if (cmd->function(argc, argv)) {
- exit(EXIT_FAILURE);
- }
-
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-#ifndef _CLI_H
-#define _CLI_H
-
-struct cli_cmd {
- const char *name;
- const char *description;
- const char *help_text;
- int (*function)(int, char **);
- int desired_args;
- int desired_args_op;
-} __attribute__((aligned(8)));
-
-#define __cli_cmds __attribute__((section("__cli_cmds"), aligned(8), used))
-
-struct cli_cmd *find_cli_cmd(const char *command);
-
-enum cli_list_opts {
- CLI_SIMPLE_LIST,
- CLI_DESCRIPTIVE_LIST,
- CLI_EXTENDED_LIST,
-};
-
-void list_cli_cmds(int option);
-
-int cli_print_help(const char *command);
-
-enum cli_arg_ops {
- CLI_EQ,
- CLI_GE,
-};
-
-void cli_dispatch_cmd(struct cli_cmd *cmd, int argc, char *argv[]);
-
-#endif /* _CLI_H */
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <ust/ustctl.h>
-#include "scanning_functions.h"
-#include "usterr.h"
-#include "cli.h"
-
-static int list_markers(int argc, char *argv[])
-{
- struct ust_marker_status *cmsf = NULL;
- int i, sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_get_cmsf(sock, &cmsf)) {
- ERR("error while trying to list markers for PID %s\n", argv[1]);
- return -1;
- }
- for (i = 0; cmsf[i].channel; i++) {
- printf("{PID: %s, channel/marker: %s/%s, "
- "state: %u, fmt: %s}\n",
- argv[1],
- cmsf[i].channel,
- cmsf[i].ust_marker,
- cmsf[i].state,
- cmsf[i].fs);
- }
- ustctl_free_cmsf(cmsf);
- return 0;
-}
-
-static int enable_marker(int argc, char *argv[])
-{
- int i, sock, result = 0;
- char *channel, *marker;
-
- sock = parse_and_connect_pid(argv[1]);
-
- for (i = 3; i < argc; i++) {
- channel = NULL;
- marker = NULL;
- if (scan_ch_marker(argv[i],
- &channel, &marker)) {
- result = -1;
- fprintf(stderr, "Failed to scan channel and marker from"
- " %s\n", argv[i]);
- if (channel)
- free(channel);
- if (marker)
- free(marker);
- }
- if (ustctl_set_ust_marker_state(sock, argv[2], channel, marker, 1)) {
- PERROR("error while trying to enable marker %s with PID %s",
- argv[i], argv[1]);
- result = -1;
- }
- free(channel);
- free(marker);
- }
-
- return result;
-}
-
-static int disable_marker(int argc, char *argv[])
-{
- int i, sock, result = 0;
- char *channel, *marker;
-
- sock = parse_and_connect_pid(argv[1]);
-
- for (i = 3; i < argc; i++) {
- channel = NULL;
- marker = NULL;
- if (scan_ch_marker(argv[i],
- &channel, &marker)) {
- fprintf(stderr, "Failed to scan channel and marker from"
- " %s\n", argv[i]);
- if (channel)
- free(channel);
- if (marker)
- free(marker);
- return -1;
- }
- if (ustctl_set_ust_marker_state(sock, argv[2], channel, marker, 0)) {
- PERROR("error while trying to disable marker %s with PID %s",
- argv[i], argv[1]);
- result = -1;
- }
- free(channel);
- free(marker);
- }
-
- return result;
-}
-
-struct cli_cmd __cli_cmds ust_marker_cmds[] = {
- {
- .name = "list-markers",
- .description = "List markers for a given pid",
- .help_text = "list-markers <pid>\n"
- "List the markers in a process\n",
- .function = list_markers,
- .desired_args = 1,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "enable-marker",
- .description = "Enable markers for a given pid",
- .help_text = "enable-marker <pid> <trace> <channel>/<marker>... \n"
- "Enable the listed markers for the trace in process pid\n",
- .function = enable_marker,
- .desired_args = 3,
- .desired_args_op = CLI_GE,
- },
- {
- .name = "disable-marker",
- .description = "Disable markers for a given pid",
- .help_text = "disable-marker <pid> <trace> <channel>/<marker>... \n"
- "Disable the listed markers for the trace in process pid\n",
- .function = disable_marker,
- .desired_args = 3,
- .desired_args_op = CLI_GE,
- }
-};
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ust/ustctl.h>
-#include "usterr.h"
-
-
-int parse_and_connect_pid(const char *pid_string)
-{
- pid_t pid;
- int sock;
-
- errno = 0;
- pid = strtoull(pid_string, NULL, 10);
- if (errno) {
- perror("Failed to parse pid");
- exit(EXIT_FAILURE);
- }
-
- sock = ustctl_connect_pid(pid);
- if (sock < 0) {
- perror("Failed to connect to process");
- exit(EXIT_FAILURE);
- }
-
- return sock;
-}
-
-int scan_ch_marker(const char *channel_marker, char **channel, char **marker)
-{
- int result;
-
- *channel = NULL;
- *marker = NULL;
-
- result = sscanf(channel_marker, "%a[^/]/%as", channel, marker);
- if (result != 2) {
- if (errno) {
- PERROR("Failed to read channel and marker names");
- } else {
- ERR("Failed to parse marker and channel names");
- }
- if (*channel) {
- free(*channel);
- }
- if (*marker) {
- free(*marker);
- }
- return -1;
- }
-
- return 0;
-}
-
-int scan_ch_and_num(const char *ch_num, char **channel, unsigned int *num)
-{
- int result;
-
- *channel = NULL;
-
- result = sscanf(ch_num, "%a[^/]/%u", channel, num);
- if (result != 2) {
- if (errno) {
- PERROR("Failed to parse channel and number");
- } else {
- ERR("Failed to parse channel and number");
- }
- if (*channel) {
- free(*channel);
- }
- return -1;
- }
-
- return 0;
-}
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-#ifndef __SCANNING_FUNCTIONS_H
-#define __SCANNING_FUNCTIONS_H
-
-int parse_and_connect_pid(const char *pid_string);
-
-int scan_ch_marker(const char *channel_marker, char **channel, char **marker);
-
-int scan_ch_and_num(const char *ch_num, char **channel, unsigned int *num);
-
-#endif /* __SCANNING_FUNCTIONS_H */
+++ /dev/null
-/* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <ust/ustctl.h>
-#include "scanning_functions.h"
-#include "usterr.h"
-#include "cli.h"
-
-
-static int create_trace(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_create_trace(sock, argv[2])) {
- ERR("Failed to create trace %s for PID %s\n", argv[2], argv[1]);
- return -1;
- }
-
- return 0;
-}
-
-static int alloc_trace(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_alloc_trace(sock, argv[2])) {
- ERR("Failed to allocate trace %s for PID %s\n", argv[2], argv[1]);
- return -1;
- }
- return 0;
-}
-
-static int start_trace(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_start_trace(sock, argv[2])) {
- ERR("Failed to start trace %s for PID %s\n", argv[2], argv[1]);
- return -1;
- }
- return 0;
-}
-
-static int stop_trace(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_stop_trace(sock, argv[2])) {
- ERR("Failed to stop trace %s for PID %s\n", argv[2], argv[1]);
- return -1;
- }
- return 0;
-}
-
-static int destroy_trace(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_destroy_trace(sock, argv[2])) {
- ERR("Failed to destroy trace %s for PID %s\n", argv[2], argv[1]);
- return -1;
- }
- return 0;
-}
-
-static int force_subbuf_switch(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_force_switch(sock, argv[2])) {
- ERR("error while trying to force switch for PID %s\n", argv[1]);
- return -1;
- }
-
- return 0;
-}
-
-struct cli_cmd __cli_cmds trace_cmds[] = {
- {
- .name = "create-trace",
- .description = "Create a trace for a process",
- .help_text = "create-trace <pid> <trace>\n"
- "Create a trace for a process\n",
- .function = create_trace,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "alloc-trace",
- .description = "Allocate a trace for a process",
- .help_text = "alloc-trace <pid> <trace>\n"
- "Allocate a trace for a process\n",
- .function = alloc_trace,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "start-trace",
- .description = "Start a trace for a process",
- .help_text = "start-trace <pid> <trace>\n"
- "Start a trace for a process\n",
- .function = start_trace,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "stop-trace",
- .description = "Stop a trace for a process",
- .help_text = "stop-trace <pid> <trace>\n"
- "Stop a trace for a process\n",
- .function = stop_trace,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "destroy-trace",
- .description = "Destroy a trace for a process",
- .help_text = "destroy-trace <pid> <trace>\n"
- "Destroy a trace for a process\n",
- .function = destroy_trace,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "force-subbuf-switch",
- .description = "Force a subbuffer switch",
- .help_text = "force-subbuf-switch <pid> <trace>\n"
- "Force a subbuffer switch for a trace, currently this forces\n"
- "a subbuffer switch for all traces in a process\n",
- .function = force_subbuf_switch,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
-};
+++ /dev/null
-/* Copyright (C) 2009 Pierre-Marc Fournier
- * Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
- *
- * 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 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
- * Lesser General Public License for more details.
- *
- * 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
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include "ust/ustctl.h"
-#include "usterr.h"
-#include "cli.h"
-#include "scanning_functions.h"
-
-void usage(const char *process_name)
-{
- fprintf(stderr, "Usage: %s COMMAND [ARGS]...\n", process_name);
- fprintf(stderr,
- "Control tracing within a process that supports UST,\n"
- " the Userspace Tracing libary\n"
- "Options:\n"
- " -h[<cmd>], --help[=<cmd>] "
- "help, for a command if provided\n"
- " -l, --list "
- "short list of commands\n"
- " -e, --extended-list "
- "extented list of commands with help\n"
- "Commands:\n");
- list_cli_cmds(CLI_DESCRIPTIVE_LIST);
-}
-
-/*
- * Provide backward compatibility for scripts that make use of the
- * --commands in ustctl version <= 0.11
- */
-enum command {
- CREATE_TRACE=1000,
- ALLOC_TRACE,
- START_TRACE,
- STOP_TRACE,
- DESTROY_TRACE,
- LIST_MARKERS,
- LIST_TRACE_EVENTS,
- ENABLE_MARKER,
- DISABLE_MARKER,
-};
-
-struct option options[] =
-{
- { "create-trace", 0, 0, CREATE_TRACE },
- { "alloc-trace", 0, 0, ALLOC_TRACE },
- { "start-trace", 0, 0, START_TRACE },
- { "stop-trace", 0, 0, STOP_TRACE },
- { "destroy-trace", 0, 0, DESTROY_TRACE },
- { "list-markers", 0, 0, LIST_MARKERS },
- { "list-trace-events", 0, 0, LIST_TRACE_EVENTS},
- { "enable-marker", 0, 0, ENABLE_MARKER },
- { "disable-marker", 0, 0, DISABLE_MARKER },
- {"help", 2, NULL, 'h'},
- {"list", 0, NULL, 'l'},
- {"extended-list", 0, NULL, 'e'},
- {NULL, 0, NULL, 0},
-};
-
-int main(int argc, char *argv[])
-{
- struct cli_cmd *cli_cmd;
- char **args = argv;
- int opt;
- int i;
-
- if(argc <= 1) {
- fprintf(stderr, "No operation specified.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- while ((opt = getopt_long(argc, argv, "+h::le",
- options, NULL)) != -1) {
- switch (opt) {
- case 'h':
- if (!optarg) {
- usage(argv[0]);
- } else {
- if (cli_print_help(optarg)) {
- fprintf(stderr, "No such command %s\n",
- optarg);
- }
- }
- exit(EXIT_FAILURE);
- break;
- case 'l':
- list_cli_cmds(CLI_SIMPLE_LIST);
- exit(EXIT_FAILURE);
- break;
- case 'e':
- list_cli_cmds(CLI_EXTENDED_LIST);
- exit(EXIT_FAILURE);
- case LIST_MARKERS:
- case LIST_TRACE_EVENTS:
- case CREATE_TRACE:
- case ALLOC_TRACE:
- case START_TRACE:
- case STOP_TRACE:
- case DESTROY_TRACE:
- case ENABLE_MARKER:
- case DISABLE_MARKER:
- args = (char **)malloc(sizeof(char *) * (argc + 3));
- optind--;
- args[optind] = strdup(&argv[optind][2]);
- for (i = optind + 1; i < argc; i++) {
- args[i] = argv[i];
- }
- if (opt >= CREATE_TRACE && opt <= DESTROY_TRACE) {
- args[argc] = strdup("auto");
- argc++;
- }
- if (opt >= ENABLE_MARKER && opt <= DISABLE_MARKER) {
- args[argc] = args[argc - 2];
- args[argc - 2] = args[argc - 1];
- args[argc - 1] = strdup("auto");
- argc++;
- }
- args[argc] = NULL;
- goto do_cli;
- default:
- fprintf(stderr, "Unknown option\n");
- break;
- }
- }
-
-do_cli:
- cli_cmd = find_cli_cmd(args[optind]);
- if (!cli_cmd) {
- fprintf(stderr, "No such command %s\n",
- args[optind]);
- exit(EXIT_FAILURE);
- }
-
- cli_dispatch_cmd(cli_cmd, argc - optind, &args[optind]);
-
- return 0;
-}
-
-static int list_trace_events(int argc, char *argv[])
-{
- struct trace_event_status *tes = NULL;
- int i, sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_get_tes(sock, &tes)) {
- ERR("error while trying to list "
- "trace_events for PID %s\n",
- argv[1]);
- return -1;
- }
- i = 0;
- for (i = 0; tes[i].name; i++) {
- printf("{PID: %s, trace_event: %s}\n",
- argv[1],
- tes[i].name);
- }
- ustctl_free_tes(tes);
-
- return 0;
-}
-
-static int set_sock_path(int argc, char *argv[])
-{
- int sock;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_set_sock_path(sock, argv[2])) {
- ERR("error while trying to set sock path for PID %s\n", argv[1]);
- return -1;
- }
-
- return 0;
-}
-
-static int get_sock_path(int argc, char *argv[])
-{
- int sock;
- char *sock_path;
-
- sock = parse_and_connect_pid(argv[1]);
-
- if (ustctl_get_sock_path(sock, &sock_path)) {
- ERR("error while trying to get sock path for PID %s\n", argv[1]);
- return -1;
- }
- printf("The socket path is %s\n", sock_path);
- free(sock_path);
-
- return 0;
-}
-
-static int list_pids(int argc, char *argv[])
-{
- pid_t *pid_list;
- int i;
-
- pid_list = ustctl_get_online_pids();
- if (!pid_list) {
- return -1;
- }
-
- for (i = 0; pid_list[i]; i++) {
- printf("%ld\n", (long)pid_list[i]);
- }
-
- free(pid_list);
-
- return 0;
-}
-
-struct cli_cmd __cli_cmds general_cmds[] = {
- {
- .name = "list-trace-events",
- .description = "List trace-events for a given pid",
- .help_text = "list-trace-events <pid>\n"
- "List the trace-events in a process\n",
- .function = list_trace_events,
- .desired_args = 1,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "set-sock-path",
- .description = "Set the path to the consumer daemon socket",
- .help_text = "set-sock-path <pid> <sock-path>\n"
- "Set the path to the consumer daemon socket\n",
- .function = set_sock_path,
- .desired_args = 2,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "get-sock-path",
- .description = "Get the path to the consumer daemon socket",
- .help_text = "get-sock-path <pid>\n"
- "Get the path to the consumer daemon socket\n",
- .function = get_sock_path,
- .desired_args = 1,
- .desired_args_op = CLI_EQ,
- },
- {
- .name = "list-pids",
- .description = "List traceable pids",
- .help_text = "list-pids\n"
- "List the traceable pids for the current user\n",
- .function = list_pids,
- .desired_args = 0,
- .desired_args_op = CLI_EQ,
- },
-};