Fix: java application context segmentation fault
[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_alloc_tls();
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, provider->priv);
93
94 lttng_ust_context_set_event_notifier_group_provider(provider->name,
95 provider->get_size, provider->record,
96 provider->get_value, provider->priv);
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_alloc_tls();
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, NULL);
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, NULL);
115
116 cds_hlist_del(&reg_provider->node);
117 end:
118 ust_unlock();
119 free(reg_provider);
120 }
121
122 /*
123 * Called with ust mutex held.
124 * Add application context to array of context, even if the application
125 * context is not currently loaded by application. It will then use the
126 * dummy callbacks in that case.
127 * Always performed before tracing is started, since it modifies
128 * metadata describing the context.
129 */
130 int lttng_ust_add_app_context_to_ctx_rcu(const char *name,
131 struct lttng_ust_ctx **ctx)
132 {
133 const struct lttng_ust_context_provider *provider;
134 struct lttng_ust_ctx_field new_field = { 0 };
135 struct lttng_ust_event_field *event_field = NULL;
136 struct lttng_ust_type_common *type = NULL;
137 char *ctx_name;
138 int ret;
139
140 if (*ctx && lttng_find_context(*ctx, name))
141 return -EEXIST;
142 event_field = zmalloc(sizeof(struct lttng_ust_event_field));
143 if (!event_field) {
144 ret = -ENOMEM;
145 goto error_event_field_alloc;
146 }
147 ctx_name = strdup(name);
148 if (!ctx_name) {
149 ret = -ENOMEM;
150 goto error_field_name_alloc;
151 }
152 type = zmalloc(sizeof(struct lttng_ust_type_common));
153 if (!type) {
154 ret = -ENOMEM;
155 goto error_field_type_alloc;
156 }
157 event_field->name = ctx_name;
158 type->type = lttng_ust_type_dynamic;
159 event_field->type = type;
160 new_field.event_field = event_field;
161 /*
162 * If provider is not found, we add the context anyway, but
163 * it will provide a dummy context.
164 */
165 provider = lookup_provider_by_name(name);
166 if (provider) {
167 new_field.get_size = provider->get_size;
168 new_field.record = provider->record;
169 new_field.get_value = provider->get_value;
170 new_field.priv = provider->priv;
171 } else {
172 new_field.get_size = lttng_ust_dummy_get_size;
173 new_field.record = lttng_ust_dummy_record;
174 new_field.get_value = lttng_ust_dummy_get_value;
175 new_field.priv = NULL;
176 }
177 /*
178 * For application context, add it by expanding
179 * ctx array.
180 */
181 ret = lttng_ust_context_append_rcu(ctx, &new_field);
182 if (ret) {
183 goto error_append;
184 }
185 return 0;
186
187 error_append:
188 free(type);
189 error_field_type_alloc:
190 free(ctx_name);
191 error_field_name_alloc:
192 free(event_field);
193 error_event_field_alloc:
194 return ret;
195 }
This page took 0.032946 seconds and 4 git commands to generate.