xpcom/ds/TimeStamp_posix.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 //
     8 // Implement TimeStamp::Now() with POSIX clocks.
     9 //
    10 // The "tick" unit for POSIX clocks is simply a nanosecond, as this is
    11 // the smallest unit of time representable by struct timespec.  That
    12 // doesn't mean that a nanosecond is the resolution of TimeDurations
    13 // obtained with this API; see TimeDuration::Resolution;
    14 //
    16 #include <sys/syscall.h>
    17 #include <time.h>
    18 #include <unistd.h>
    20 #if defined(__DragonFly__) || defined(__FreeBSD__) \
    21     || defined(__NetBSD__) || defined(__OpenBSD__)
    22 #include <sys/param.h>
    23 #include <sys/sysctl.h>
    24 #endif
    26 #if defined(__DragonFly__) || defined(__FreeBSD__)
    27 #include <sys/user.h>
    28 #endif
    30 #if defined(__NetBSD__)
    31 #undef KERN_PROC
    32 #define KERN_PROC KERN_PROC2
    33 #define KINFO_PROC struct kinfo_proc2
    34 #else
    35 #define KINFO_PROC struct kinfo_proc
    36 #endif
    38 #if defined(__DragonFly__)
    39 #define KP_START_SEC kp_start.tv_sec
    40 #define KP_START_USEC kp_start.tv_usec
    41 #elif defined(__FreeBSD__)
    42 #define KP_START_SEC ki_start.tv_sec
    43 #define KP_START_USEC ki_start.tv_usec
    44 #else
    45 #define KP_START_SEC p_ustart_sec
    46 #define KP_START_USEC p_ustart_usec
    47 #endif
    49 #include "mozilla/TimeStamp.h"
    50 #include "nsCRT.h"
    51 #include "prprf.h"
    52 #include "prthread.h"
    53 #include "nsDebug.h"
    55 // Estimate of the smallest duration of time we can measure.
    56 static uint64_t sResolution;
    57 static uint64_t sResolutionSigDigs;
    59 static const uint16_t kNsPerUs   =       1000;
    60 static const uint64_t kNsPerMs   =    1000000;
    61 static const uint64_t kNsPerSec  = 1000000000; 
    62 static const double kNsPerMsd    =    1000000.0;
    63 static const double kNsPerSecd   = 1000000000.0;
    65 static uint64_t
    66 TimespecToNs(const struct timespec& ts)
    67 {
    68   uint64_t baseNs = uint64_t(ts.tv_sec) * kNsPerSec;
    69   return baseNs + uint64_t(ts.tv_nsec);
    70 }
    72 static uint64_t
    73 ClockTimeNs()
    74 {
    75   struct timespec ts;
    76   // this can't fail: we know &ts is valid, and TimeStamp::Startup()
    77   // checks that CLOCK_MONOTONIC is supported (and aborts if not)
    78   clock_gettime(CLOCK_MONOTONIC, &ts);
    80   // tv_sec is defined to be relative to an arbitrary point in time,
    81   // but it would be madness for that point in time to be earlier than
    82   // the Epoch.  So we can safely assume that even if time_t is 32
    83   // bits, tv_sec won't overflow while the browser is open.  Revisit
    84   // this argument if we're still building with 32-bit time_t around
    85   // the year 2037.
    86   return TimespecToNs(ts);
    87 }
    89 static uint64_t
    90 ClockResolutionNs()
    91 {
    92   // NB: why not rely on clock_getres()?  Two reasons: (i) it might
    93   // lie, and (ii) it might return an "ideal" resolution that while
    94   // theoretically true, could never be measured in practice.  Since
    95   // clock_gettime() likely involves a system call on your platform,
    96   // the "actual" timing resolution shouldn't be lower than syscall
    97   // overhead.
    99   uint64_t start = ClockTimeNs();
   100   uint64_t end = ClockTimeNs();
   101   uint64_t minres = (end - start);
   103   // 10 total trials is arbitrary: what we're trying to avoid by
   104   // looping is getting unlucky and being interrupted by a context
   105   // switch or signal, or being bitten by paging/cache effects
   106   for (int i = 0; i < 9; ++i) {
   107     start = ClockTimeNs();
   108     end = ClockTimeNs();
   110     uint64_t candidate = (start - end);
   111     if (candidate < minres)
   112       minres = candidate;
   113   }
   115   if (0 == minres) {
   116     // measurable resolution is either incredibly low, ~1ns, or very
   117     // high.  fall back on clock_getres()
   118     struct timespec ts;
   119     if (0 == clock_getres(CLOCK_MONOTONIC, &ts)) {
   120       minres = TimespecToNs(ts);
   121     }
   122   }
   124   if (0 == minres) {
   125     // clock_getres probably failed.  fall back on NSPR's resolution
   126     // assumption
   127     minres = 1 * kNsPerMs;
   128   }
   130   return minres;
   131 }
   133 namespace mozilla {
   135 double
   136 TimeDuration::ToSeconds() const
   137 {
   138   return double(mValue) / kNsPerSecd;
   139 }
   141 double
   142 TimeDuration::ToSecondsSigDigits() const
   143 {
   144   // don't report a value < mResolution ...
   145   int64_t valueSigDigs = sResolution * (mValue / sResolution);
   146   // and chop off insignificant digits
   147   valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
   148   return double(valueSigDigs) / kNsPerSecd;
   149 }
   151 TimeDuration
   152 TimeDuration::FromMilliseconds(double aMilliseconds)
   153 {
   154   return TimeDuration::FromTicks(aMilliseconds * kNsPerMsd);
   155 }
   157 TimeDuration
   158 TimeDuration::Resolution()
   159 {
   160   return TimeDuration::FromTicks(int64_t(sResolution));
   161 }
   163 static bool gInitialized = false;
   165 nsresult
   166 TimeStamp::Startup()
   167 {
   168   if (gInitialized)
   169     return NS_OK;
   171   struct timespec dummy;
   172   if (0 != clock_gettime(CLOCK_MONOTONIC, &dummy))
   173       NS_RUNTIMEABORT("CLOCK_MONOTONIC is absent!");
   175   sResolution = ClockResolutionNs();
   177   // find the number of significant digits in sResolution, for the
   178   // sake of ToSecondsSigDigits()
   179   for (sResolutionSigDigs = 1;
   180        !(sResolutionSigDigs == sResolution
   181          || 10*sResolutionSigDigs > sResolution);
   182        sResolutionSigDigs *= 10);
   184   gInitialized = true;
   186   return NS_OK;
   187 }
   189 void
   190 TimeStamp::Shutdown()
   191 {
   192 }
   194 TimeStamp
   195 TimeStamp::Now(bool aHighResolution)
   196 {
   197   return TimeStamp(ClockTimeNs());
   198 }
   200 #if defined(LINUX) || defined(ANDROID)
   202 // Calculates the amount of jiffies that have elapsed since boot and up to the
   203 // starttime value of a specific process as found in its /proc/*/stat file.
   204 // Returns 0 if an error occurred.
   206 static uint64_t
   207 JiffiesSinceBoot(const char *aFile)
   208 {
   209   char stat[512];
   211   FILE *f = fopen(aFile, "r");
   212   if (!f)
   213     return 0;
   215   int n = fread(&stat, 1, sizeof(stat) - 1, f);
   217   fclose(f);
   219   if (n <= 0)
   220     return 0;
   222   stat[n] = 0;
   224   long long unsigned startTime = 0; // instead of uint64_t to keep GCC quiet
   225   char *s = strrchr(stat, ')');
   227   if (!s)
   228     return 0;
   230   int rv = sscanf(s + 2,
   231                   "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u "
   232                   "%*u %*u %*u %*d %*d %*d %*d %*d %*d %llu",
   233                   &startTime);
   235   if (rv != 1 || !startTime)
   236     return 0;
   238   return startTime;
   239 }
   241 // Computes the interval that has elapsed between the thread creation and the
   242 // process creation by comparing the starttime fields in the respective
   243 // /proc/*/stat files. The resulting value will be a good approximation of the
   244 // process uptime. This value will be stored at the address pointed by aTime;
   245 // if an error occurred 0 will be stored instead.
   247 static void
   248 ComputeProcessUptimeThread(void *aTime)
   249 {
   250   uint64_t *uptime = static_cast<uint64_t *>(aTime);
   251   long hz = sysconf(_SC_CLK_TCK);
   253   *uptime = 0;
   255   if (!hz)
   256     return;
   258   char threadStat[40];
   259   sprintf(threadStat, "/proc/self/task/%d/stat", (pid_t) syscall(__NR_gettid));
   261   uint64_t threadJiffies = JiffiesSinceBoot(threadStat);
   262   uint64_t selfJiffies = JiffiesSinceBoot("/proc/self/stat");
   264   if (!threadJiffies || !selfJiffies)
   265     return;
   267   *uptime = ((threadJiffies - selfJiffies) * kNsPerSec) / hz;
   268 }
   270 // Computes and returns the process uptime in us on Linux & its derivatives.
   271 // Returns 0 if an error was encountered.
   273 uint64_t
   274 TimeStamp::ComputeProcessUptime()
   275 {
   276   uint64_t uptime = 0;
   277   PRThread *thread = PR_CreateThread(PR_USER_THREAD,
   278                                      ComputeProcessUptimeThread,
   279                                      &uptime,
   280                                      PR_PRIORITY_NORMAL,
   281                                      PR_GLOBAL_THREAD,
   282                                      PR_JOINABLE_THREAD,
   283                                      0);
   285   PR_JoinThread(thread);
   287   return uptime / kNsPerUs;
   288 }
   290 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
   291       || defined(__NetBSD__) || defined(__OpenBSD__)
   293 // Computes and returns the process uptime in us on various BSD flavors.
   294 // Returns 0 if an error was encountered.
   296 uint64_t
   297 TimeStamp::ComputeProcessUptime()
   298 {
   299   struct timespec ts;
   300   int rv = clock_gettime(CLOCK_REALTIME, &ts);
   302   if (rv == -1) {
   303     return 0;
   304   }
   306   int mib[] = {
   307     CTL_KERN,
   308     KERN_PROC,
   309     KERN_PROC_PID,
   310     getpid(),
   311 #if defined(__NetBSD__) || defined(__OpenBSD__)
   312     sizeof(KINFO_PROC),
   313     1,
   314 #endif
   315   };
   316   u_int mibLen = sizeof(mib) / sizeof(mib[0]);
   318   KINFO_PROC proc;
   319   size_t bufferSize = sizeof(proc);
   320   rv = sysctl(mib, mibLen, &proc, &bufferSize, nullptr, 0);
   322   if (rv == -1)
   323     return 0;
   325   uint64_t startTime = ((uint64_t)proc.KP_START_SEC * kNsPerSec)
   326     + (proc.KP_START_USEC * kNsPerUs);
   327   uint64_t now = ((uint64_t)ts.tv_sec * kNsPerSec) + ts.tv_nsec;
   329   if (startTime > now)
   330     return 0;
   332   return (now - startTime) / kNsPerUs;
   333 }
   335 #else
   337 uint64_t
   338 TimeStamp::ComputeProcessUptime()
   339 {
   340   return 0;
   341 }
   343 #endif
   345 } // namespace mozilla

mercurial