lttng_ust_init_thread: initialise cached context values
[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 #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];
34 };
35
36 static struct context_provider_ht context_provider_ht;
37
38 static const struct lttng_ust_context_provider *
39 lookup_provider_by_name(const char *name)
40 {
41 struct cds_hlist_head *head;
42 struct cds_hlist_node *node;
43 struct lttng_ust_registered_context_provider *reg_provider;
44 uint32_t hash;
45 const char *end;
46 size_t len;
47
48 /* Lookup using everything before first ':' as key. */
49 end = strchr(name, ':');
50 if (end)
51 len = end - name;
52 else
53 len = strlen(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(reg_provider, node, head, node) {
57 if (!strncmp(reg_provider->provider->name, name, len))
58 return reg_provider->provider;
59 }
60 return NULL;
61 }
62
63 struct lttng_ust_registered_context_provider *lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider)
64 {
65 struct lttng_ust_registered_context_provider *reg_provider = NULL;
66 struct cds_hlist_head *head;
67 size_t name_len = strlen(provider->name);
68 uint32_t hash;
69
70 lttng_ust_common_init_thread(0);
71
72 /* Provider name starts with "$app.". */
73 if (strncmp("$app.", provider->name, strlen("$app.")) != 0)
74 return NULL;
75 /* Provider name cannot contain a colon character. */
76 if (strchr(provider->name, ':'))
77 return NULL;
78 if (ust_lock())
79 goto end;
80 if (lookup_provider_by_name(provider->name))
81 goto end;
82 reg_provider = zmalloc(sizeof(struct lttng_ust_registered_context_provider));
83 if (!reg_provider)
84 goto end;
85 reg_provider->provider = provider;
86 hash = jhash(provider->name, name_len, 0);
87 head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)];
88 cds_hlist_add_head(&reg_provider->node, head);
89
90 lttng_ust_context_set_session_provider(provider->name,
91 provider->get_size, provider->record,
92 provider->get_value);
93
94 lttng_ust_context_set_event_notifier_group_provider(provider->name,
95 provider->get_size, provider->record,
96 provider->get_value);
97 end:
98 ust_unlock();
99 return reg_provider;
100 }
101
102 void lttng_ust_context_provider_unregister(struct lttng_ust_registered_context_provider *reg_provider)
103 {
104 lttng_ust_common_init_thread(0);
105
106 if (ust_lock())
107 goto end;
108 lttng_ust_context_set_session_provider(reg_provider->provider->name,
109 lttng_ust_dummy_get_size, lttng_ust_dummy_record,
110 lttng_ust_dummy_get_value);
111
112 lttng_ust_context_set_event_notifier_group_provider(reg_provider->provider->name,
113 lttng_ust_dummy_get_size, lttng_ust_dummy_record,
114 lttng_ust_dummy_get_value);
115
116 cds_hlist_del(&reg_provider->node);
117 end:
118 ust_unlock();
119 free(reg_provider);
120 }
121
122 static
123 void app_context_destroy(void *priv)
124 {
125 struct lttng_ust_app_context *app_ctx = (struct lttng_ust_app_context *) priv;
126
127 free(app_ctx->ctx_name);
128 free(app_ctx->event_field);
129 }
130
131 static
132 const struct lttng_ust_type_common app_ctx_type = {
133 .type = lttng_ust_type_dynamic,
134 };
135
136 /*
137 * Called with ust mutex held.
138 * Add application context to array of context, even if the application
139 * context is not currently loaded by application. It will then use the
140 * dummy callbacks in that case.
141 * Always performed before tracing is started, since it modifies
142 * metadata describing the context.
143 */
144 int lttng_ust_add_app_context_to_ctx_rcu(const char *name,
145 struct lttng_ust_ctx **ctx)
146 {
147 const struct lttng_ust_context_provider *provider;
148 struct lttng_ust_ctx_field new_field = { 0 };
149 struct lttng_ust_event_field *event_field = NULL;
150 struct lttng_ust_app_context *app_ctx = NULL;
151 char *ctx_name;
152 int ret;
153
154 if (*ctx && lttng_find_context(*ctx, name))
155 return -EEXIST;
156 event_field = zmalloc(sizeof(struct lttng_ust_event_field));
157 if (!event_field) {
158 ret = -ENOMEM;
159 goto error_event_field_alloc;
160 }
161 ctx_name = strdup(name);
162 if (!ctx_name) {
163 ret = -ENOMEM;
164 goto error_field_name_alloc;
165 }
166 app_ctx = zmalloc(sizeof(struct lttng_ust_app_context));
167 if (!app_ctx) {
168 ret = -ENOMEM;
169 goto error_app_ctx_alloc;
170 }
171 app_ctx->struct_size = sizeof(struct lttng_ust_app_context);
172 app_ctx->event_field = event_field;
173 app_ctx->ctx_name = ctx_name;
174
175 event_field->name = ctx_name;
176 event_field->type = &app_ctx_type;
177 new_field.event_field = event_field;
178 /*
179 * If provider is not found, we add the context anyway, but
180 * it will provide a dummy context.
181 */
182 provider = lookup_provider_by_name(name);
183 if (provider) {
184 new_field.get_size = provider->get_size;
185 new_field.record = provider->record;
186 new_field.get_value = provider->get_value;
187 } else {
188 new_field.get_size = lttng_ust_dummy_get_size;
189 new_field.record = lttng_ust_dummy_record;
190 new_field.get_value = lttng_ust_dummy_get_value;
191 }
192 new_field.priv = app_ctx;
193 new_field.destroy = app_context_destroy;
194 /*
195 * For application context, add it by expanding
196 * ctx array.
197 */
198 ret = lttng_ust_context_append_rcu(ctx, &new_field);
199 if (ret) {
200 goto error_append;
201 }
202 return 0;
203
204 error_append:
205 free(app_ctx);
206 error_app_ctx_alloc:
207 free(ctx_name);
208 error_field_name_alloc:
209 free(event_field);
210 error_event_field_alloc:
211 return ret;
212 }
This page took 0.035845 seconds and 4 git commands to generate.