1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*
* lttng-context-procname.c
*
* LTTng UST procname context.
*
* Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.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; only
* 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 <lttng/ust-events.h>
#include <lttng/ust-tracer.h>
#include <lttng/ringbuffer-config.h>
#include <urcu/tls-compat.h>
#include <assert.h>
#include "compat.h"
/* Maximum number of nesting levels for the procname cache. */
#define PROCNAME_NESTING_MAX 2
/*
* We cache the result to ensure we don't trigger a system call for
* each event.
* Upon exec, procname changes, but exec takes care of throwing away
* this cached version.
* The procname can also change by calling prctl(). The procname should
* be set for a thread before the first event is logged within this
* thread.
*/
typedef char procname_array[PROCNAME_NESTING_MAX][17];
static DEFINE_URCU_TLS(procname_array, cached_procname);
static DEFINE_URCU_TLS(int, procname_nesting);
static inline
char *wrapper_getprocname(void)
{
int nesting = CMM_LOAD_SHARED(URCU_TLS(procname_nesting));
if (caa_unlikely(nesting >= PROCNAME_NESTING_MAX))
return "<unknown>";
if (caa_unlikely(!URCU_TLS(cached_procname)[nesting][0])) {
CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting + 1);
/* Increment nesting before updating cache. */
cmm_barrier();
lttng_ust_getprocname(URCU_TLS(cached_procname)[nesting]);
URCU_TLS(cached_procname)[nesting][LTTNG_UST_PROCNAME_LEN - 1] = '\0';
/* Decrement nesting after updating cache. */
cmm_barrier();
CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting);
}
return URCU_TLS(cached_procname)[nesting];
}
/* Reset should not be called from a signal handler. */
void lttng_context_procname_reset(void)
{
CMM_STORE_SHARED(URCU_TLS(cached_procname)[1][0], '\0');
CMM_STORE_SHARED(URCU_TLS(procname_nesting), 1);
CMM_STORE_SHARED(URCU_TLS(cached_procname)[0][0], '\0');
CMM_STORE_SHARED(URCU_TLS(procname_nesting), 0);
}
static
size_t procname_get_size(struct lttng_ctx_field *field, size_t offset)
{
return LTTNG_UST_PROCNAME_LEN;
}
static
void procname_record(struct lttng_ctx_field *field,
struct lttng_ust_lib_ring_buffer_ctx *ctx,
struct lttng_channel *chan)
{
char *procname;
procname = wrapper_getprocname();
chan->ops->event_write(ctx, procname, LTTNG_UST_PROCNAME_LEN);
}
static
void procname_get_value(struct lttng_ctx_field *field,
struct lttng_ctx_value *value)
{
value->u.str = wrapper_getprocname();
}
int lttng_add_procname_to_ctx(struct lttng_ctx **ctx)
{
struct lttng_ctx_field *field;
field = lttng_append_context(ctx);
if (!field)
return -ENOMEM;
if (lttng_find_context(*ctx, "procname")) {
lttng_remove_context_field(ctx, field);
return -EEXIST;
}
field->event_field.name = "procname";
field->event_field.type.atype = atype_array;
field->event_field.type.u.array.elem_type.atype = atype_integer;
field->event_field.type.u.array.elem_type.u.basic.integer.size = sizeof(char) * CHAR_BIT;
field->event_field.type.u.array.elem_type.u.basic.integer.alignment = lttng_alignof(char) * CHAR_BIT;
field->event_field.type.u.array.elem_type.u.basic.integer.signedness = lttng_is_signed_type(char);
field->event_field.type.u.array.elem_type.u.basic.integer.reverse_byte_order = 0;
field->event_field.type.u.array.elem_type.u.basic.integer.base = 10;
field->event_field.type.u.array.elem_type.u.basic.integer.encoding = lttng_encode_UTF8;
field->event_field.type.u.array.length = LTTNG_UST_PROCNAME_LEN;
field->get_size = procname_get_size;
field->record = procname_record;
field->get_value = procname_get_value;
lttng_context_update(*ctx);
return 0;
}
/*
* Force a read (imply TLS fixup for dlopen) of TLS variables.
*/
void lttng_fixup_procname_tls(void)
{
asm volatile ("" : : "m" (URCU_TLS(cached_procname)[0]));
}
|