Commit | Line | Data |
---|---|---|
e11fcffc | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
e11fcffc | 3 | * |
c0c0989a | 4 | * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
e11fcffc MD |
5 | */ |
6 | ||
3fbec7dc | 7 | #define _LGPL_SOURCE |
e11fcffc MD |
8 | #include <dlfcn.h> |
9 | #include <stdlib.h> | |
fb31eb73 | 10 | #include <stdint.h> |
33b563d6 | 11 | #include <stdio.h> |
9d315d6d | 12 | |
e11fcffc | 13 | #include <lttng/ust-clock.h> |
f41a6b5f | 14 | #include <lttng/ust-events.h> |
e11fcffc MD |
15 | #include <urcu/system.h> |
16 | #include <urcu/arch.h> | |
17 | ||
9d315d6d | 18 | #include "common/logging.h" |
910dcd72 | 19 | #include "common/getenv.h" |
e11fcffc | 20 | |
f41a6b5f MJ |
21 | #include "lib/lttng-ust-common/clock.h" |
22 | ||
33b563d6 | 23 | struct lttng_ust_trace_clock *lttng_ust_trace_clock; |
e11fcffc MD |
24 | |
25 | static | |
33b563d6 | 26 | struct lttng_ust_trace_clock user_tc; |
e11fcffc | 27 | |
4bc1ccd7 MD |
28 | static |
29 | void *clock_handle; | |
30 | ||
33b563d6 MD |
31 | static |
32 | uint64_t trace_clock_freq_monotonic(void) | |
e11fcffc | 33 | { |
33b563d6 MD |
34 | return 1000000000ULL; |
35 | } | |
36 | ||
37 | static | |
38 | int trace_clock_uuid_monotonic(char *uuid) | |
39 | { | |
40 | int ret = 0; | |
41 | size_t len; | |
42 | FILE *fp; | |
43 | ||
44 | /* | |
45 | * boot_id needs to be read once before being used concurrently | |
46 | * to deal with a Linux kernel race. A fix is proposed for | |
47 | * upstream, but the work-around is needed for older kernels. | |
48 | */ | |
49 | fp = fopen("/proc/sys/kernel/random/boot_id", "r"); | |
50 | if (!fp) { | |
51 | return -ENOENT; | |
52 | } | |
53 | len = fread(uuid, 1, LTTNG_UST_UUID_STR_LEN - 1, fp); | |
54 | if (len < LTTNG_UST_UUID_STR_LEN - 1) { | |
55 | ret = -EINVAL; | |
56 | goto end; | |
57 | } | |
58 | uuid[LTTNG_UST_UUID_STR_LEN - 1] = '\0'; | |
59 | end: | |
60 | fclose(fp); | |
61 | return ret; | |
62 | } | |
63 | ||
64 | static | |
65 | const char *trace_clock_name_monotonic(void) | |
66 | { | |
67 | return "monotonic"; | |
68 | } | |
69 | ||
70 | static | |
71 | const char *trace_clock_description_monotonic(void) | |
72 | { | |
73 | return "Monotonic Clock"; | |
74 | } | |
75 | ||
76 | int lttng_ust_trace_clock_set_read64_cb(lttng_ust_clock_read64_function read64_cb) | |
77 | { | |
78 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) | |
e11fcffc | 79 | return -EBUSY; |
33b563d6 MD |
80 | user_tc.read64 = read64_cb; |
81 | return 0; | |
82 | } | |
83 | ||
84 | int lttng_ust_trace_clock_get_read64_cb(lttng_ust_clock_read64_function *read64_cb) | |
85 | { | |
86 | struct lttng_ust_trace_clock *ltc = CMM_LOAD_SHARED(lttng_ust_trace_clock); | |
87 | ||
88 | if (caa_likely(!ltc)) { | |
89 | *read64_cb = &trace_clock_read64_monotonic; | |
90 | } else { | |
91 | cmm_read_barrier_depends(); /* load ltc before content */ | |
92 | *read64_cb = ltc->read64; | |
93 | } | |
e11fcffc MD |
94 | return 0; |
95 | } | |
96 | ||
33b563d6 | 97 | int lttng_ust_trace_clock_set_freq_cb(lttng_ust_clock_freq_function freq_cb) |
e11fcffc | 98 | { |
33b563d6 | 99 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) |
e11fcffc | 100 | return -EBUSY; |
33b563d6 | 101 | user_tc.freq = freq_cb; |
e11fcffc MD |
102 | return 0; |
103 | } | |
104 | ||
33b563d6 | 105 | int lttng_ust_trace_clock_get_freq_cb(lttng_ust_clock_freq_function *freq_cb) |
e11fcffc | 106 | { |
33b563d6 MD |
107 | struct lttng_ust_trace_clock *ltc = CMM_LOAD_SHARED(lttng_ust_trace_clock); |
108 | ||
109 | if (caa_likely(!ltc)) { | |
110 | *freq_cb = &trace_clock_freq_monotonic; | |
111 | } else { | |
112 | cmm_read_barrier_depends(); /* load ltc before content */ | |
113 | *freq_cb = ltc->freq; | |
114 | } | |
115 | return 0; | |
116 | } | |
117 | ||
118 | int lttng_ust_trace_clock_set_uuid_cb(lttng_ust_clock_uuid_function uuid_cb) | |
119 | { | |
120 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) | |
e11fcffc | 121 | return -EBUSY; |
33b563d6 MD |
122 | user_tc.uuid = uuid_cb; |
123 | return 0; | |
124 | } | |
125 | ||
126 | int lttng_ust_trace_clock_get_uuid_cb(lttng_ust_clock_uuid_function *uuid_cb) | |
127 | { | |
128 | struct lttng_ust_trace_clock *ltc = CMM_LOAD_SHARED(lttng_ust_trace_clock); | |
129 | ||
130 | if (caa_likely(!ltc)) { | |
131 | *uuid_cb = &trace_clock_uuid_monotonic; | |
132 | } else { | |
133 | cmm_read_barrier_depends(); /* load ltc before content */ | |
134 | *uuid_cb = ltc->uuid; | |
135 | } | |
e11fcffc MD |
136 | return 0; |
137 | } | |
138 | ||
33b563d6 | 139 | int lttng_ust_trace_clock_set_name_cb(lttng_ust_clock_name_function name_cb) |
e11fcffc | 140 | { |
33b563d6 | 141 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) |
e11fcffc | 142 | return -EBUSY; |
33b563d6 | 143 | user_tc.name = name_cb; |
e11fcffc MD |
144 | return 0; |
145 | } | |
146 | ||
33b563d6 | 147 | int lttng_ust_trace_clock_get_name_cb(lttng_ust_clock_name_function *name_cb) |
e11fcffc | 148 | { |
33b563d6 MD |
149 | struct lttng_ust_trace_clock *ltc = CMM_LOAD_SHARED(lttng_ust_trace_clock); |
150 | ||
151 | if (caa_likely(!ltc)) { | |
152 | *name_cb = &trace_clock_name_monotonic; | |
153 | } else { | |
154 | cmm_read_barrier_depends(); /* load ltc before content */ | |
155 | *name_cb = ltc->name; | |
156 | } | |
157 | return 0; | |
158 | } | |
159 | ||
160 | int lttng_ust_trace_clock_set_description_cb(lttng_ust_clock_description_function description_cb) | |
161 | { | |
162 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) | |
e11fcffc | 163 | return -EBUSY; |
33b563d6 MD |
164 | user_tc.description = description_cb; |
165 | return 0; | |
166 | } | |
167 | ||
168 | int lttng_ust_trace_clock_get_description_cb(lttng_ust_clock_description_function *description_cb) | |
169 | { | |
170 | struct lttng_ust_trace_clock *ltc = CMM_LOAD_SHARED(lttng_ust_trace_clock); | |
171 | ||
172 | if (caa_likely(!ltc)) { | |
173 | *description_cb = &trace_clock_description_monotonic; | |
174 | } else { | |
175 | cmm_read_barrier_depends(); /* load ltc before content */ | |
176 | *description_cb = ltc->description; | |
177 | } | |
e11fcffc MD |
178 | return 0; |
179 | } | |
180 | ||
181 | int lttng_ust_enable_trace_clock_override(void) | |
182 | { | |
33b563d6 | 183 | if (CMM_LOAD_SHARED(lttng_ust_trace_clock)) |
e11fcffc MD |
184 | return -EBUSY; |
185 | if (!user_tc.read64) | |
186 | return -EINVAL; | |
187 | if (!user_tc.freq) | |
188 | return -EINVAL; | |
189 | if (!user_tc.name) | |
190 | return -EINVAL; | |
191 | if (!user_tc.description) | |
192 | return -EINVAL; | |
193 | /* Use default uuid cb when NULL */ | |
194 | cmm_smp_mb(); /* Store callbacks before trace clock */ | |
33b563d6 | 195 | CMM_STORE_SHARED(lttng_ust_trace_clock, &user_tc); |
e11fcffc MD |
196 | return 0; |
197 | } | |
198 | ||
199 | void lttng_ust_clock_init(void) | |
200 | { | |
201 | const char *libname; | |
e11fcffc MD |
202 | void (*libinit)(void); |
203 | ||
4bc1ccd7 MD |
204 | if (clock_handle) |
205 | return; | |
4c41b460 | 206 | libname = lttng_ust_getenv("LTTNG_UST_CLOCK_PLUGIN"); |
e11fcffc MD |
207 | if (!libname) |
208 | return; | |
4bc1ccd7 MD |
209 | clock_handle = dlopen(libname, RTLD_NOW); |
210 | if (!clock_handle) { | |
e11fcffc MD |
211 | PERROR("Cannot load LTTng UST clock override library %s", |
212 | libname); | |
213 | return; | |
214 | } | |
215 | dlerror(); | |
4bc1ccd7 | 216 | libinit = (void (*)(void)) dlsym(clock_handle, |
e11fcffc MD |
217 | "lttng_ust_clock_plugin_init"); |
218 | if (!libinit) { | |
219 | PERROR("Cannot find LTTng UST clock override library %s initialization function lttng_ust_clock_plugin_init()", | |
220 | libname); | |
221 | return; | |
222 | } | |
223 | libinit(); | |
224 | } |