Refactoring: UST types public interfaces
[lttng-ust.git] / liblttng-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 <ust-context-provider.h>
16
17 #include "context-internal.h"
18 #include "lttng-tracer-core.h"
19 #include "jhash.h"
20 #include "context-provider-internal.h"
21 #include <ust-helper.h>
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
63 lttng_ust_fixup_tls();
64
65 /* Provider name starts with "$app.". */
66 if (strncmp("$app.", provider->name, strlen("$app.")) != 0)
67 return -EINVAL;
68 /* Provider name cannot contain a colon character. */
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);
82
83 lttng_ust_context_set_session_provider(provider->name,
84 provider->get_size, provider->record,
85 provider->get_value);
86
87 lttng_ust_context_set_event_notifier_group_provider(provider->name,
88 provider->get_size, provider->record,
89 provider->get_value);
90 end:
91 ust_unlock();
92 return ret;
93 }
94
95 void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *provider)
96 {
97 lttng_ust_fixup_tls();
98
99 if (ust_lock())
100 goto end;
101 lttng_ust_context_set_session_provider(provider->name,
102 lttng_ust_dummy_get_size, lttng_ust_dummy_record,
103 lttng_ust_dummy_get_value);
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
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_ust_ctx **ctx)
124 {
125 struct lttng_ust_context_provider *provider;
126 struct lttng_ust_ctx_field *new_field = NULL;
127 int ret;
128
129 if (*ctx && lttng_find_context(*ctx, name))
130 return -EEXIST;
131 new_field = zmalloc(sizeof(struct lttng_ust_ctx_field));
132 if (!new_field) {
133 ret = -ENOMEM;
134 goto error_field_alloc;
135 }
136 new_field->struct_size = sizeof(struct lttng_ust_ctx_field);
137 new_field->event_field = zmalloc(sizeof(struct lttng_ust_event_field));
138 if (!new_field->event_field) {
139 ret = -ENOMEM;
140 goto error_event_field_alloc;
141 }
142 new_field->event_field->name = strdup(name);
143 if (!new_field->event_field->name) {
144 ret = -ENOMEM;
145 goto error_field_name_alloc;
146 }
147 new_field->event_field->type = zmalloc(sizeof(struct lttng_ust_type_common));
148 if (!new_field->event_field->type) {
149 ret = -ENOMEM;
150 goto error_field_type_alloc;
151 }
152 new_field->event_field->type->type = lttng_ust_type_dynamic;
153 /*
154 * If provider is not found, we add the context anyway, but
155 * it will provide a dummy context.
156 */
157 provider = lookup_provider_by_name(name);
158 if (provider) {
159 new_field->get_size = provider->get_size;
160 new_field->record = provider->record;
161 new_field->get_value = provider->get_value;
162 } else {
163 new_field->get_size = lttng_ust_dummy_get_size;
164 new_field->record = lttng_ust_dummy_record;
165 new_field->get_value = lttng_ust_dummy_get_value;
166 }
167 /*
168 * For application context, add it by expanding
169 * ctx array. Ownership of new_field is passed to the callee on
170 * success.
171 */
172 ret = lttng_context_add_rcu(ctx, new_field);
173 if (ret) {
174 free(new_field->event_field->type);
175 free((char *) new_field->event_field->name);
176 free(new_field->event_field);
177 free(new_field);
178 return ret;
179 }
180 return 0;
181
182 error_field_type_alloc:
183 free((char *) new_field->event_field->name);
184 error_field_name_alloc:
185 free(new_field->event_field);
186 error_event_field_alloc:
187 free(new_field);
188 error_field_alloc:
189 return ret;
190 }
This page took 0.0335 seconds and 5 git commands to generate.