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