Commit | Line | Data |
---|---|---|
53569322 | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
53569322 MD |
3 | * |
4 | * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
5 | * | |
c0c0989a | 6 | * LTTng UST application context provider. |
53569322 MD |
7 | */ |
8 | ||
3fbec7dc | 9 | #define _LGPL_SOURCE |
b4051ad8 | 10 | #include <stddef.h> |
fb31eb73 | 11 | #include <stdint.h> |
53569322 MD |
12 | #include <sys/types.h> |
13 | #include <unistd.h> | |
fb31eb73 | 14 | |
9d315d6d | 15 | #include <common/ust-context-provider.h> |
d8d2416d | 16 | |
fc80554e | 17 | #include "context-internal.h" |
53569322 | 18 | #include "lttng-tracer-core.h" |
e58e5ad5 | 19 | #include "common/jhash.h" |
d8d2416d | 20 | #include "context-provider-internal.h" |
9d315d6d | 21 | #include "common/macros.h" |
8cd08025 | 22 | #include "common/tracer.h" |
53569322 | 23 | |
4e48b5d2 MD |
24 | struct lttng_ust_registered_context_provider { |
25 | const struct lttng_ust_context_provider *provider; | |
26 | ||
27 | struct cds_hlist_node node; | |
28 | }; | |
29 | ||
f26f2f9b MD |
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 | ||
53569322 MD |
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 | ||
4e48b5d2 | 44 | static const struct lttng_ust_context_provider * |
53569322 MD |
45 | lookup_provider_by_name(const char *name) |
46 | { | |
47 | struct cds_hlist_head *head; | |
48 | struct cds_hlist_node *node; | |
4e48b5d2 | 49 | struct lttng_ust_registered_context_provider *reg_provider; |
53569322 MD |
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)]; | |
4e48b5d2 MD |
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; | |
53569322 MD |
65 | } |
66 | return NULL; | |
67 | } | |
68 | ||
4e48b5d2 | 69 | struct lttng_ust_registered_context_provider *lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider) |
53569322 | 70 | { |
4e48b5d2 | 71 | struct lttng_ust_registered_context_provider *reg_provider = NULL; |
53569322 MD |
72 | struct cds_hlist_head *head; |
73 | size_t name_len = strlen(provider->name); | |
74 | uint32_t hash; | |
53569322 | 75 | |
a9fd951a | 76 | lttng_ust_alloc_tls(); |
c362addf | 77 | |
53569322 | 78 | /* Provider name starts with "$app.". */ |
fe94775b | 79 | if (strncmp("$app.", provider->name, strlen("$app.")) != 0) |
4e48b5d2 | 80 | return NULL; |
8b05d0d4 | 81 | /* Provider name cannot contain a colon character. */ |
53569322 | 82 | if (strchr(provider->name, ':')) |
4e48b5d2 MD |
83 | return NULL; |
84 | if (ust_lock()) | |
53569322 | 85 | goto end; |
4e48b5d2 | 86 | if (lookup_provider_by_name(provider->name)) |
53569322 | 87 | goto end; |
4e48b5d2 MD |
88 | reg_provider = zmalloc(sizeof(struct lttng_ust_registered_context_provider)); |
89 | if (!reg_provider) | |
90 | goto end; | |
91 | reg_provider->provider = provider; | |
53569322 MD |
92 | hash = jhash(provider->name, name_len, 0); |
93 | head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)]; | |
4e48b5d2 | 94 | cds_hlist_add_head(®_provider->node, head); |
d8d2416d | 95 | |
53569322 MD |
96 | lttng_ust_context_set_session_provider(provider->name, |
97 | provider->get_size, provider->record, | |
4e48b5d2 | 98 | provider->get_value, provider->priv); |
d8d2416d FD |
99 | |
100 | lttng_ust_context_set_event_notifier_group_provider(provider->name, | |
101 | provider->get_size, provider->record, | |
4e48b5d2 | 102 | provider->get_value, provider->priv); |
53569322 MD |
103 | end: |
104 | ust_unlock(); | |
4e48b5d2 | 105 | return reg_provider; |
53569322 MD |
106 | } |
107 | ||
4e48b5d2 | 108 | void lttng_ust_context_provider_unregister(struct lttng_ust_registered_context_provider *reg_provider) |
53569322 | 109 | { |
a9fd951a | 110 | lttng_ust_alloc_tls(); |
c362addf | 111 | |
53569322 MD |
112 | if (ust_lock()) |
113 | goto end; | |
4e48b5d2 | 114 | lttng_ust_context_set_session_provider(reg_provider->provider->name, |
ce7352a2 | 115 | lttng_ust_dummy_get_size, lttng_ust_dummy_record, |
4e48b5d2 | 116 | lttng_ust_dummy_get_value, NULL); |
d8d2416d | 117 | |
4e48b5d2 | 118 | lttng_ust_context_set_event_notifier_group_provider(reg_provider->provider->name, |
d8d2416d | 119 | lttng_ust_dummy_get_size, lttng_ust_dummy_record, |
4e48b5d2 | 120 | lttng_ust_dummy_get_value, NULL); |
d8d2416d | 121 | |
4e48b5d2 | 122 | cds_hlist_del(®_provider->node); |
53569322 MD |
123 | end: |
124 | ust_unlock(); | |
4e48b5d2 | 125 | free(reg_provider); |
53569322 MD |
126 | } |
127 | ||
f26f2f9b MD |
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 | ||
53569322 MD |
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, | |
daacdbfc | 147 | struct lttng_ust_ctx **ctx) |
53569322 | 148 | { |
4e48b5d2 | 149 | const struct lttng_ust_context_provider *provider; |
f26f2f9b | 150 | struct lttng_ust_ctx_field new_field = { 0 }; |
4e48b5d2 MD |
151 | struct lttng_ust_event_field *event_field = NULL; |
152 | struct lttng_ust_type_common *type = NULL; | |
f26f2f9b MD |
153 | struct lttng_ust_app_ctx *app_ctx = NULL; |
154 | char *ctx_name; | |
53569322 MD |
155 | int ret; |
156 | ||
157 | if (*ctx && lttng_find_context(*ctx, name)) | |
158 | return -EEXIST; | |
4e48b5d2 MD |
159 | event_field = zmalloc(sizeof(struct lttng_ust_event_field)); |
160 | if (!event_field) { | |
daacdbfc MD |
161 | ret = -ENOMEM; |
162 | goto error_event_field_alloc; | |
163 | } | |
f26f2f9b MD |
164 | ctx_name = strdup(name); |
165 | if (!ctx_name) { | |
daacdbfc MD |
166 | ret = -ENOMEM; |
167 | goto error_field_name_alloc; | |
168 | } | |
4e48b5d2 MD |
169 | type = zmalloc(sizeof(struct lttng_ust_type_common)); |
170 | if (!type) { | |
a084756d MD |
171 | ret = -ENOMEM; |
172 | goto error_field_type_alloc; | |
173 | } | |
f26f2f9b MD |
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; | |
4e48b5d2 MD |
180 | type->type = lttng_ust_type_dynamic; |
181 | event_field->type = type; | |
f26f2f9b | 182 | new_field.event_field = event_field; |
53569322 MD |
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) { | |
f26f2f9b MD |
189 | new_field.get_size = provider->get_size; |
190 | new_field.record = provider->record; | |
191 | new_field.get_value = provider->get_value; | |
53569322 | 192 | } else { |
f26f2f9b MD |
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; | |
53569322 | 196 | } |
f26f2f9b MD |
197 | new_field.destroy = destroy_app_ctx; |
198 | new_field.priv = app_ctx; | |
daacdbfc MD |
199 | /* |
200 | * For application context, add it by expanding | |
f26f2f9b | 201 | * ctx array. |
daacdbfc | 202 | */ |
f26f2f9b | 203 | ret = lttng_ust_context_append_rcu(ctx, &new_field); |
53569322 | 204 | if (ret) { |
f26f2f9b | 205 | destroy_app_ctx(app_ctx); |
53569322 MD |
206 | return ret; |
207 | } | |
208 | return 0; | |
daacdbfc | 209 | |
f26f2f9b MD |
210 | error_app_ctx_alloc: |
211 | free(type); | |
a084756d | 212 | error_field_type_alloc: |
f26f2f9b | 213 | free(ctx_name); |
daacdbfc | 214 | error_field_name_alloc: |
4e48b5d2 | 215 | free(event_field); |
daacdbfc | 216 | error_event_field_alloc: |
daacdbfc | 217 | return ret; |
53569322 | 218 | } |