2 * lttng-context-provider.c
4 * LTTng UST application context provider.
6 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <sys/types.h>
25 #include <lttng/ust-context-provider.h>
26 #include "lttng-tracer-core.h"
30 #define CONTEXT_PROVIDER_HT_BITS 12
31 #define CONTEXT_PROVIDER_HT_SIZE (1U << CONTEXT_PROVIDER_HT_BITS)
32 struct context_provider_ht
{
33 struct cds_hlist_head table
[CONTEXT_PROVIDER_HT_SIZE
];
36 static struct context_provider_ht context_provider_ht
;
38 static struct lttng_ust_context_provider
*
39 lookup_provider_by_name(const char *name
)
41 struct cds_hlist_head
*head
;
42 struct cds_hlist_node
*node
;
43 struct lttng_ust_context_provider
*provider
;
48 /* Lookup using everything before first ':' as key. */
49 end
= strchr(name
, ':');
54 hash
= jhash(name
, len
, 0);
55 head
= &context_provider_ht
.table
[hash
& (CONTEXT_PROVIDER_HT_SIZE
- 1)];
56 cds_hlist_for_each_entry(provider
, node
, head
, node
) {
57 if (!strncmp(provider
->name
, name
, len
))
63 int lttng_ust_context_provider_register(struct lttng_ust_context_provider
*provider
)
65 struct cds_hlist_head
*head
;
66 size_t name_len
= strlen(provider
->name
);
70 /* Provider name starts with "$app.". */
71 if (strncmp("$app.", provider
->name
, strlen("$app.") != 0))
73 /* Provider name cannot contain a column character. */
74 if (strchr(provider
->name
, ':'))
80 if (lookup_provider_by_name(provider
->name
)) {
84 hash
= jhash(provider
->name
, name_len
, 0);
85 head
= &context_provider_ht
.table
[hash
& (CONTEXT_PROVIDER_HT_SIZE
- 1)];
86 cds_hlist_add_head(&provider
->node
, head
);
87 lttng_ust_context_set_session_provider(provider
->name
,
88 provider
->get_size
, provider
->record
,
95 size_t lttng_ust_dummy_get_size(struct lttng_ctx_field
*field
, size_t offset
)
99 size
+= lib_ring_buffer_align(offset
, lttng_alignof(char));
100 size
+= sizeof(char); /* tag */
104 void lttng_ust_dummy_record(struct lttng_ctx_field
*field
,
105 struct lttng_ust_lib_ring_buffer_ctx
*ctx
,
106 struct lttng_channel
*chan
)
108 char sel_char
= (char) LTTNG_UST_DYNAMIC_TYPE_NONE
;
110 lib_ring_buffer_align_ctx(ctx
, lttng_alignof(sel_char
));
111 chan
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
));
114 void lttng_ust_dummy_get_value(struct lttng_ctx_field
*field
,
115 struct lttng_ctx_value
*value
)
117 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
120 void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider
*provider
)
124 lttng_ust_context_set_session_provider(provider
->name
,
125 lttng_ust_dummy_get_size
, lttng_ust_dummy_record
,
126 lttng_ust_dummy_get_value
);
127 cds_hlist_del(&provider
->node
);
133 * Called with ust mutex held.
134 * Add application context to array of context, even if the application
135 * context is not currently loaded by application. It will then use the
136 * dummy callbacks in that case.
137 * Always performed before tracing is started, since it modifies
138 * metadata describing the context.
140 int lttng_ust_add_app_context_to_ctx_rcu(const char *name
,
141 struct lttng_ctx
**ctx
)
143 struct lttng_ust_context_provider
*provider
;
144 struct lttng_ctx_field new_field
;
147 if (*ctx
&& lttng_find_context(*ctx
, name
))
150 * For application context, add it by expanding
153 memset(&new_field
, 0, sizeof(new_field
));
154 new_field
.field_name
= strdup(name
);
155 if (!new_field
.field_name
)
157 new_field
.event_field
.name
= new_field
.field_name
;
158 new_field
.event_field
.type
.atype
= atype_dynamic
;
160 * If provider is not found, we add the context anyway, but
161 * it will provide a dummy context.
163 provider
= lookup_provider_by_name(name
);
165 new_field
.get_size
= provider
->get_size
;
166 new_field
.record
= provider
->record
;
167 new_field
.get_value
= provider
->get_value
;
169 new_field
.get_size
= lttng_ust_dummy_get_size
;
170 new_field
.record
= lttng_ust_dummy_record
;
171 new_field
.get_value
= lttng_ust_dummy_get_value
;
173 ret
= lttng_context_add_rcu(ctx
, &new_field
);
175 free(new_field
.field_name
);