Move the ringbuffer and counter clients to 'src/common/'
[lttng-ust.git] / src / lib / lttng-ust / lttng-context-provider.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng UST application context provider.
7 */
8
9 #define _LGPL_SOURCE
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include <common/ust-context-provider.h>
16
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"
23
24 struct lttng_ust_registered_context_provider {
25 const struct lttng_ust_context_provider *provider;
26
27 struct cds_hlist_node node;
28 };
29
30 struct lttng_ust_app_ctx {
31 char *name;
32 struct lttng_ust_event_field *event_field;
33 struct lttng_ust_type_common *type;
34 };
35
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];
40 };
41
42 static struct context_provider_ht context_provider_ht;
43
44 static const struct lttng_ust_context_provider *
45 lookup_provider_by_name(const char *name)
46 {
47 struct cds_hlist_head *head;
48 struct cds_hlist_node *node;
49 struct lttng_ust_registered_context_provider *reg_provider;
50 uint32_t hash;
51 const char *end;
52 size_t len;
53
54 /* Lookup using everything before first ':' as key. */
55 end = strchr(name, ':');
56 if (end)
57 len = end - name;
58 else
59 len = strlen(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;
65 }
66 return NULL;
67 }
68
69 struct lttng_ust_registered_context_provider *lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider)
70 {
71 struct lttng_ust_registered_context_provider *reg_provider = NULL;
72 struct cds_hlist_head *head;
73 size_t name_len = strlen(provider->name);
74 uint32_t hash;
75
76 lttng_ust_alloc_tls();
77
78 /* Provider name starts with "$app.". */
79 if (strncmp("$app.", provider->name, strlen("$app.")) != 0)
80 return NULL;
81 /* Provider name cannot contain a colon character. */
82 if (strchr(provider->name, ':'))
83 return NULL;
84 if (ust_lock())
85 goto end;
86 if (lookup_provider_by_name(provider->name))
87 goto end;
88 reg_provider = zmalloc(sizeof(struct lttng_ust_registered_context_provider));
89 if (!reg_provider)
90 goto end;
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(&reg_provider->node, head);
95
96 lttng_ust_context_set_session_provider(provider->name,
97 provider->get_size, provider->record,
98 provider->get_value, provider->priv);
99
100 lttng_ust_context_set_event_notifier_group_provider(provider->name,
101 provider->get_size, provider->record,
102 provider->get_value, provider->priv);
103 end:
104 ust_unlock();
105 return reg_provider;
106 }
107
108 void lttng_ust_context_provider_unregister(struct lttng_ust_registered_context_provider *reg_provider)
109 {
110 lttng_ust_alloc_tls();
111
112 if (ust_lock())
113 goto end;
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);
117
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);
121
122 cds_hlist_del(&reg_provider->node);
123 end:
124 ust_unlock();
125 free(reg_provider);
126 }
127
128 static void destroy_app_ctx(void *priv)
129 {
130 struct lttng_ust_app_ctx *app_ctx = (struct lttng_ust_app_ctx *) priv;
131
132 free(app_ctx->name);
133 free(app_ctx->event_field);
134 free(app_ctx->type);
135 free(app_ctx);
136 }
137
138 /*
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.
145 */
146 int lttng_ust_add_app_context_to_ctx_rcu(const char *name,
147 struct lttng_ust_ctx **ctx)
148 {
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;
154 char *ctx_name;
155 int ret;
156
157 if (*ctx && lttng_find_context(*ctx, name))
158 return -EEXIST;
159 event_field = zmalloc(sizeof(struct lttng_ust_event_field));
160 if (!event_field) {
161 ret = -ENOMEM;
162 goto error_event_field_alloc;
163 }
164 ctx_name = strdup(name);
165 if (!ctx_name) {
166 ret = -ENOMEM;
167 goto error_field_name_alloc;
168 }
169 type = zmalloc(sizeof(struct lttng_ust_type_common));
170 if (!type) {
171 ret = -ENOMEM;
172 goto error_field_type_alloc;
173 }
174 app_ctx = zmalloc(sizeof(struct lttng_ust_app_ctx));
175 if (!app_ctx) {
176 ret = -ENOMEM;
177 goto error_app_ctx_alloc;
178 }
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;
183 /*
184 * If provider is not found, we add the context anyway, but
185 * it will provide a dummy context.
186 */
187 provider = lookup_provider_by_name(name);
188 if (provider) {
189 new_field.get_size = provider->get_size;
190 new_field.record = provider->record;
191 new_field.get_value = provider->get_value;
192 } else {
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;
196 }
197 new_field.destroy = destroy_app_ctx;
198 new_field.priv = app_ctx;
199 /*
200 * For application context, add it by expanding
201 * ctx array.
202 */
203 ret = lttng_ust_context_append_rcu(ctx, &new_field);
204 if (ret) {
205 destroy_app_ctx(app_ctx);
206 return ret;
207 }
208 return 0;
209
210 error_app_ctx_alloc:
211 free(type);
212 error_field_type_alloc:
213 free(ctx_name);
214 error_field_name_alloc:
215 free(event_field);
216 error_event_field_alloc:
217 return ret;
218 }
This page took 0.0333 seconds and 4 git commands to generate.