2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * LTTng UST application context provider.
12 #include <sys/types.h>
15 #include <common/ust-context-provider.h>
17 #include "context-internal.h"
18 #include "lttng-tracer-core.h"
19 #include "common/jhash.h"
20 #include "context-provider-internal.h"
21 #include "common/macros.h"
22 #include "common/tracer.h"
24 struct lttng_ust_registered_context_provider
{
25 const struct lttng_ust_context_provider
*provider
;
27 struct cds_hlist_node node
;
30 struct lttng_ust_app_ctx
{
32 struct lttng_ust_event_field
*event_field
;
33 struct lttng_ust_type_common
*type
;
36 #define CONTEXT_PROVIDER_HT_BITS 12
37 #define CONTEXT_PROVIDER_HT_SIZE (1U << CONTEXT_PROVIDER_HT_BITS)
38 struct context_provider_ht
{
39 struct cds_hlist_head table
[CONTEXT_PROVIDER_HT_SIZE
];
42 static struct context_provider_ht context_provider_ht
;
44 static const struct lttng_ust_context_provider
*
45 lookup_provider_by_name(const char *name
)
47 struct cds_hlist_head
*head
;
48 struct cds_hlist_node
*node
;
49 struct lttng_ust_registered_context_provider
*reg_provider
;
54 /* Lookup using everything before first ':' as key. */
55 end
= strchr(name
, ':');
60 hash
= jhash(name
, len
, 0);
61 head
= &context_provider_ht
.table
[hash
& (CONTEXT_PROVIDER_HT_SIZE
- 1)];
62 cds_hlist_for_each_entry(reg_provider
, node
, head
, node
) {
63 if (!strncmp(reg_provider
->provider
->name
, name
, len
))
64 return reg_provider
->provider
;
69 struct lttng_ust_registered_context_provider
*lttng_ust_context_provider_register(struct lttng_ust_context_provider
*provider
)
71 struct lttng_ust_registered_context_provider
*reg_provider
= NULL
;
72 struct cds_hlist_head
*head
;
73 size_t name_len
= strlen(provider
->name
);
76 lttng_ust_alloc_tls();
78 /* Provider name starts with "$app.". */
79 if (strncmp("$app.", provider
->name
, strlen("$app.")) != 0)
81 /* Provider name cannot contain a colon character. */
82 if (strchr(provider
->name
, ':'))
86 if (lookup_provider_by_name(provider
->name
))
88 reg_provider
= zmalloc(sizeof(struct lttng_ust_registered_context_provider
));
91 reg_provider
->provider
= provider
;
92 hash
= jhash(provider
->name
, name_len
, 0);
93 head
= &context_provider_ht
.table
[hash
& (CONTEXT_PROVIDER_HT_SIZE
- 1)];
94 cds_hlist_add_head(®_provider
->node
, head
);
96 lttng_ust_context_set_session_provider(provider
->name
,
97 provider
->get_size
, provider
->record
,
98 provider
->get_value
, provider
->priv
);
100 lttng_ust_context_set_event_notifier_group_provider(provider
->name
,
101 provider
->get_size
, provider
->record
,
102 provider
->get_value
, provider
->priv
);
108 void lttng_ust_context_provider_unregister(struct lttng_ust_registered_context_provider
*reg_provider
)
110 lttng_ust_alloc_tls();
114 lttng_ust_context_set_session_provider(reg_provider
->provider
->name
,
115 lttng_ust_dummy_get_size
, lttng_ust_dummy_record
,
116 lttng_ust_dummy_get_value
, NULL
);
118 lttng_ust_context_set_event_notifier_group_provider(reg_provider
->provider
->name
,
119 lttng_ust_dummy_get_size
, lttng_ust_dummy_record
,
120 lttng_ust_dummy_get_value
, NULL
);
122 cds_hlist_del(®_provider
->node
);
128 static void destroy_app_ctx(void *priv
)
130 struct lttng_ust_app_ctx
*app_ctx
= (struct lttng_ust_app_ctx
*) priv
;
133 free(app_ctx
->event_field
);
139 * Called with ust mutex held.
140 * Add application context to array of context, even if the application
141 * context is not currently loaded by application. It will then use the
142 * dummy callbacks in that case.
143 * Always performed before tracing is started, since it modifies
144 * metadata describing the context.
146 int lttng_ust_add_app_context_to_ctx_rcu(const char *name
,
147 struct lttng_ust_ctx
**ctx
)
149 const struct lttng_ust_context_provider
*provider
;
150 struct lttng_ust_ctx_field new_field
= { 0 };
151 struct lttng_ust_event_field
*event_field
= NULL
;
152 struct lttng_ust_type_common
*type
= NULL
;
153 struct lttng_ust_app_ctx
*app_ctx
= NULL
;
157 if (*ctx
&& lttng_find_context(*ctx
, name
))
159 event_field
= zmalloc(sizeof(struct lttng_ust_event_field
));
162 goto error_event_field_alloc
;
164 ctx_name
= strdup(name
);
167 goto error_field_name_alloc
;
169 type
= zmalloc(sizeof(struct lttng_ust_type_common
));
172 goto error_field_type_alloc
;
174 app_ctx
= zmalloc(sizeof(struct lttng_ust_app_ctx
));
177 goto error_app_ctx_alloc
;
179 event_field
->name
= ctx_name
;
180 type
->type
= lttng_ust_type_dynamic
;
181 event_field
->type
= type
;
182 new_field
.event_field
= event_field
;
184 * If provider is not found, we add the context anyway, but
185 * it will provide a dummy context.
187 provider
= lookup_provider_by_name(name
);
189 new_field
.get_size
= provider
->get_size
;
190 new_field
.record
= provider
->record
;
191 new_field
.get_value
= provider
->get_value
;
193 new_field
.get_size
= lttng_ust_dummy_get_size
;
194 new_field
.record
= lttng_ust_dummy_record
;
195 new_field
.get_value
= lttng_ust_dummy_get_value
;
197 new_field
.destroy
= destroy_app_ctx
;
198 new_field
.priv
= app_ctx
;
200 * For application context, add it by expanding
203 ret
= lttng_ust_context_append_rcu(ctx
, &new_field
);
205 destroy_app_ctx(app_ctx
);
212 error_field_type_alloc
:
214 error_field_name_alloc
:
216 error_event_field_alloc
: