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 | |
ae4b659d | 15 | #include <ust-context-provider.h> |
d8d2416d | 16 | |
fc80554e | 17 | #include "context-internal.h" |
53569322 MD |
18 | #include "lttng-tracer-core.h" |
19 | #include "jhash.h" | |
d8d2416d | 20 | #include "context-provider-internal.h" |
864a1eda | 21 | #include <ust-helper.h> |
53569322 MD |
22 | |
23 | #define CONTEXT_PROVIDER_HT_BITS 12 | |
24 | #define CONTEXT_PROVIDER_HT_SIZE (1U << CONTEXT_PROVIDER_HT_BITS) | |
25 | struct context_provider_ht { | |
26 | struct cds_hlist_head table[CONTEXT_PROVIDER_HT_SIZE]; | |
27 | }; | |
28 | ||
29 | static struct context_provider_ht context_provider_ht; | |
30 | ||
31 | static struct lttng_ust_context_provider * | |
32 | lookup_provider_by_name(const char *name) | |
33 | { | |
34 | struct cds_hlist_head *head; | |
35 | struct cds_hlist_node *node; | |
36 | struct lttng_ust_context_provider *provider; | |
37 | uint32_t hash; | |
38 | const char *end; | |
39 | size_t len; | |
40 | ||
41 | /* Lookup using everything before first ':' as key. */ | |
42 | end = strchr(name, ':'); | |
43 | if (end) | |
44 | len = end - name; | |
45 | else | |
46 | len = strlen(name); | |
47 | hash = jhash(name, len, 0); | |
48 | head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)]; | |
49 | cds_hlist_for_each_entry(provider, node, head, node) { | |
50 | if (!strncmp(provider->name, name, len)) | |
51 | return provider; | |
52 | } | |
53 | return NULL; | |
54 | } | |
55 | ||
56 | int lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider) | |
57 | { | |
58 | struct cds_hlist_head *head; | |
59 | size_t name_len = strlen(provider->name); | |
60 | uint32_t hash; | |
61 | int ret = 0; | |
62 | ||
c362addf MD |
63 | lttng_ust_fixup_tls(); |
64 | ||
53569322 | 65 | /* Provider name starts with "$app.". */ |
fe94775b | 66 | if (strncmp("$app.", provider->name, strlen("$app.")) != 0) |
53569322 | 67 | return -EINVAL; |
8b05d0d4 | 68 | /* Provider name cannot contain a colon character. */ |
53569322 MD |
69 | if (strchr(provider->name, ':')) |
70 | return -EINVAL; | |
71 | if (ust_lock()) { | |
72 | ret = -EBUSY; | |
73 | goto end; | |
74 | } | |
75 | if (lookup_provider_by_name(provider->name)) { | |
76 | ret = -EBUSY; | |
77 | goto end; | |
78 | } | |
79 | hash = jhash(provider->name, name_len, 0); | |
80 | head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)]; | |
81 | cds_hlist_add_head(&provider->node, head); | |
d8d2416d | 82 | |
53569322 MD |
83 | lttng_ust_context_set_session_provider(provider->name, |
84 | provider->get_size, provider->record, | |
85 | provider->get_value); | |
d8d2416d FD |
86 | |
87 | lttng_ust_context_set_event_notifier_group_provider(provider->name, | |
88 | provider->get_size, provider->record, | |
89 | provider->get_value); | |
53569322 MD |
90 | end: |
91 | ust_unlock(); | |
92 | return ret; | |
93 | } | |
94 | ||
53569322 MD |
95 | void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *provider) |
96 | { | |
c362addf MD |
97 | lttng_ust_fixup_tls(); |
98 | ||
53569322 MD |
99 | if (ust_lock()) |
100 | goto end; | |
101 | lttng_ust_context_set_session_provider(provider->name, | |
ce7352a2 MD |
102 | lttng_ust_dummy_get_size, lttng_ust_dummy_record, |
103 | lttng_ust_dummy_get_value); | |
d8d2416d FD |
104 | |
105 | lttng_ust_context_set_event_notifier_group_provider(provider->name, | |
106 | lttng_ust_dummy_get_size, lttng_ust_dummy_record, | |
107 | lttng_ust_dummy_get_value); | |
108 | ||
53569322 MD |
109 | cds_hlist_del(&provider->node); |
110 | end: | |
111 | ust_unlock(); | |
112 | } | |
113 | ||
114 | /* | |
115 | * Called with ust mutex held. | |
116 | * Add application context to array of context, even if the application | |
117 | * context is not currently loaded by application. It will then use the | |
118 | * dummy callbacks in that case. | |
119 | * Always performed before tracing is started, since it modifies | |
120 | * metadata describing the context. | |
121 | */ | |
122 | int lttng_ust_add_app_context_to_ctx_rcu(const char *name, | |
123 | struct lttng_ctx **ctx) | |
124 | { | |
125 | struct lttng_ust_context_provider *provider; | |
126 | struct lttng_ctx_field new_field; | |
127 | int ret; | |
128 | ||
129 | if (*ctx && lttng_find_context(*ctx, name)) | |
130 | return -EEXIST; | |
131 | /* | |
132 | * For application context, add it by expanding | |
133 | * ctx array. | |
134 | */ | |
135 | memset(&new_field, 0, sizeof(new_field)); | |
136 | new_field.field_name = strdup(name); | |
137 | if (!new_field.field_name) | |
138 | return -ENOMEM; | |
139 | new_field.event_field.name = new_field.field_name; | |
140 | new_field.event_field.type.atype = atype_dynamic; | |
141 | /* | |
142 | * If provider is not found, we add the context anyway, but | |
143 | * it will provide a dummy context. | |
144 | */ | |
145 | provider = lookup_provider_by_name(name); | |
146 | if (provider) { | |
147 | new_field.get_size = provider->get_size; | |
148 | new_field.record = provider->record; | |
149 | new_field.get_value = provider->get_value; | |
150 | } else { | |
ce7352a2 MD |
151 | new_field.get_size = lttng_ust_dummy_get_size; |
152 | new_field.record = lttng_ust_dummy_record; | |
153 | new_field.get_value = lttng_ust_dummy_get_value; | |
53569322 MD |
154 | } |
155 | ret = lttng_context_add_rcu(ctx, &new_field); | |
156 | if (ret) { | |
157 | free(new_field.field_name); | |
158 | return ret; | |
159 | } | |
160 | return 0; | |
161 | } |