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