-#ifdef CLOCK_REALTIME_COARSE
- std::call_once(gVdsoInitOnce, []{
- void* h = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
-
- typedef int64_t (*GettimeNsFunc)(clockid_t);
-
- auto getcpuFunc = Getcpu::Func(
- !h ? nullptr : dlsym(h, "__vdso_getcpu"));
- auto gettimeNsFunc = GettimeNsFunc(
- !h ? nullptr : dlsym(h, "__vdso_clock_gettime_ns"));
-
- bool coarseGettimeDetected = false;
- if (gettimeNsFunc != nullptr) {
- // The TLS cache of getcpu results only is an optimization if the
- // __vdso_clock_gettime_ns implementation is fast and actually
- // coarse. The slow fallback implementation is not coarse, so if
- // we detect a coarse clock we are set. If CLOCK_REALTIME_COARSE
- // has the right properties, then so long as there is no context
- // switch between two calls the returned time will be identical.
- // Dynamically verify this. An unlikely context switch while we're
- // testing can lead to a false negative, but not a false positive,
- // so we just run the test multiple times. This ensures that we
- // will get two calls to gettimeNsFunc in a row with no intervening
- // context switch.
- auto prev = gettimeNsFunc(CLOCK_REALTIME_COARSE);
- for (int i = 0; i < 10 && !coarseGettimeDetected; ++i) {
- auto next = gettimeNsFunc(CLOCK_REALTIME_COARSE);
- coarseGettimeDetected = next == prev;
- prev = next;
- }
- }
-
- if (getcpuFunc == nullptr || !coarseGettimeDetected) {
- // technically a null getcpuFunc could either be a failure or
- // a successful lookup of a symbol with the null value, but the
- // second can't actually happen for this symbol. No point holding
- // the handle forever if we don't need the code
- if (h) {
- dlclose(h);
- }
- } else {
- gVdsoGetcpuFunc = getcpuFunc;
- gVdsoGettimeNsFunc = gettimeNsFunc;
- }
- });
-
- if (gVdsoGetcpuFunc != nullptr) {
- return cachingVdsoGetcpu;
- }
-#endif
-
- return nullptr;