137 lines
3.6 KiB
C++
137 lines
3.6 KiB
C++
//
|
|
// Copyright (C) 2012 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "shill/net/shill_time.h"
|
|
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include <base/format_macros.h>
|
|
#include <base/strings/stringprintf.h>
|
|
|
|
using std::string;
|
|
|
|
namespace shill {
|
|
|
|
namespace {
|
|
|
|
// As Time may be instantiated by MemoryLogMessage during a callback of
|
|
// AtExitManager, it needs to be a leaky singleton to avoid
|
|
// AtExitManager::RegisterCallback() from potentially being called within a
|
|
// callback of AtExitManager, which will lead to a crash. Making Time leaky is
|
|
// fine as it does not need to clean up or release any resource at destruction.
|
|
base::LazyInstance<Time>::Leaky g_time = LAZY_INSTANCE_INITIALIZER;
|
|
|
|
} // namespace
|
|
|
|
Time::Time() { }
|
|
|
|
Time::~Time() { }
|
|
|
|
Time* Time::GetInstance() {
|
|
return g_time.Pointer();
|
|
}
|
|
|
|
bool Time::GetSecondsMonotonic(time_t* seconds) {
|
|
struct timeval now;
|
|
if (GetTimeMonotonic(&now) < 0) {
|
|
return false;
|
|
} else {
|
|
*seconds = now.tv_sec;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Time::GetSecondsBoottime(time_t* seconds) {
|
|
struct timeval now;
|
|
if (GetTimeBoottime(&now) < 0) {
|
|
return false;
|
|
} else {
|
|
*seconds = now.tv_sec;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int Time::GetTimeMonotonic(struct timeval* tv) {
|
|
struct timespec ts;
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
tv->tv_sec = ts.tv_sec;
|
|
tv->tv_usec = ts.tv_nsec / 1000;
|
|
return 0;
|
|
}
|
|
|
|
int Time::GetTimeBoottime(struct timeval* tv) {
|
|
struct timespec ts;
|
|
if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
tv->tv_sec = ts.tv_sec;
|
|
tv->tv_usec = ts.tv_nsec / 1000;
|
|
return 0;
|
|
}
|
|
|
|
int Time::GetTimeOfDay(struct timeval* tv, struct timezone* tz) {
|
|
return gettimeofday(tv, tz);
|
|
}
|
|
|
|
Timestamp Time::GetNow() {
|
|
struct timeval now_monotonic = {};
|
|
struct timeval now_boottime = {};
|
|
struct timeval now_wall_clock = {};
|
|
struct tm local_time = {};
|
|
string wall_clock_string;
|
|
|
|
GetTimeMonotonic(&now_monotonic);
|
|
GetTimeBoottime(&now_boottime);
|
|
GetTimeOfDay(&now_wall_clock, nullptr);
|
|
localtime_r(&now_wall_clock.tv_sec, &local_time);
|
|
wall_clock_string = FormatTime(local_time, now_wall_clock.tv_usec);
|
|
|
|
return Timestamp(now_monotonic, now_boottime, wall_clock_string);
|
|
}
|
|
|
|
// static
|
|
string Time::FormatTime(const struct tm& date_time, suseconds_t usec) {
|
|
char date_time_string[64];
|
|
size_t date_time_length;
|
|
date_time_length = strftime(date_time_string, sizeof(date_time_string),
|
|
"%Y-%m-%dT%H:%M:%S %z", &date_time);
|
|
|
|
// Stitch in the microseconds, to provider finer resolution than
|
|
// strftime allows.
|
|
string full_string = "<unknown>";
|
|
char* split_pos = static_cast<char*>(
|
|
memchr(date_time_string, ' ', sizeof(date_time_string)));
|
|
if (date_time_length && date_time_length < sizeof(date_time_string) &&
|
|
split_pos) {
|
|
*split_pos = '\0';
|
|
full_string =
|
|
base::StringPrintf("%s.%06" PRIu64 "%s", date_time_string,
|
|
static_cast<uint64_t>(usec), split_pos + 1);
|
|
}
|
|
|
|
return full_string;
|
|
}
|
|
|
|
time_t Time::GetSecondsSinceEpoch() const {
|
|
return time(nullptr);
|
|
}
|
|
|
|
} // namespace shill
|