time.c revision 1193
98N/A/*
98N/A * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
1276N/A *
98N/A * Permission is hereby granted, free of charge, to any person obtaining a
1276N/A * copy of this software and associated documentation files (the "Software"),
98N/A * to deal in the Software without restriction, including without limitation
98N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
919N/A * and/or sell copies of the Software, and to permit persons to whom the
919N/A * Software is furnished to do so, subject to the following conditions:
919N/A *
919N/A * The above copyright notice and this permission notice (including the next
919N/A * paragraph) shall be included in all copies or substantial portions of the
919N/A * Software.
919N/A *
919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
919N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
919N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
919N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
919N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
919N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
919N/A * DEALINGS IN THE SOFTWARE.
919N/A */
919N/A
919N/A/*
98N/A * This compiles to a module that can be preloaded during a build. If this
98N/A * is preloaded, it interposes on time(2), gettimeofday(3C), and
98N/A * clock_gethrtime(3C) and returns a constant number of seconds since epoch
98N/A * when the execname matches one of the desired "programs" and TIME_CONSTANT
98N/A * contains an integer value to be returned.
98N/A */
156N/A
493N/A#include <stdlib.h>
98N/A#include <ucontext.h>
970N/A#include <dlfcn.h>
970N/A#include <strings.h>
970N/A#include <time.h>
970N/A
98N/A/* The list of programs that we want to use a constant time. */
1276N/Astatic char *programs[] = { "autogen", "bash", "cpp", "cc1", "date", "doxygen",
98N/A "erl", "javadoc", "ksh", "ksh93", "ld", "perl", "perl5.8.4", "perl5.10",
911N/A "ruby", "sh", "uil", NULL };
1276N/A
1276N/Astatic int
1276N/Astack_info(uintptr_t pc, int signo, void *arg)
911N/A{
98N/A Dl_info info;
1291N/A void *sym;
1291N/A
1276N/A if (dladdr1((void *)pc, &info, &sym, RTLD_DL_SYMENT) != NULL) {
1276N/A if (strstr(info.dli_fname, ".so") == NULL)
98N/A *(char **)arg = (char *)info.dli_fname;
98N/A }
98N/A
98N/A return (0);
98N/A}
98N/A
963N/Astatic char *
963N/Amy_execname()
963N/A{
963N/A static char *execname;
963N/A
963N/A if (execname == NULL) {
963N/A ucontext_t ctx;
98N/A
156N/A if (getcontext(&ctx) == 0)
walkcontext(&ctx, stack_info, &execname);
if (execname != NULL) {
char *s = strrchr(execname, '/');
if (s != NULL)
execname = ++s;
}
}
return (execname);
}
static time_t
time_constant()
{
char *execname = my_execname();
time_t result = -1;
if (execname != NULL) {
int i;
for (i = 0; programs[i] != NULL; i++)
if (strcmp(execname, programs[i]) == 0) {
static char *time_string;
if (time_string == NULL)
time_string = getenv("TIME_CONSTANT");
if (time_string != NULL)
result = atoll(time_string);
break;
}
}
return (result);
}
time_t
time(time_t *ptr)
{
time_t result = time_constant();
if (result == (time_t)-1) {
static time_t (*fptr)(time_t *);
if (fptr == NULL)
fptr = (time_t (*)(time_t *))dlsym(RTLD_NEXT, "time");
result = (fptr)(ptr);
} else if (ptr != NULL)
*ptr = result;
return (result);
}
int
gettimeofday(struct timeval *tp, void *tzp)
{
static int (*fptr)(struct timeval *, void *);
int result = -1;
if (fptr == NULL)
fptr = (int (*)(struct timeval *, void *))dlsym(RTLD_NEXT,
"gettimeofday");
if ((result = (fptr)(tp, tzp)) == 0) {
time_t curtime = time_constant();
if (curtime != (time_t)-1)
tp->tv_sec = curtime;
}
return (result);
}
int
clock_gettime(clockid_t clock_id, struct timespec *tp)
{
static int (*fptr)(clockid_t, struct timespec *);
int result = -1;
if (fptr == NULL)
fptr = (int (*)(clockid_t, struct timespec *))dlsym(RTLD_NEXT,
"clock_gettime");
if ((result = (fptr)(clock_id, tp)) == 0) {
time_t curtime = time_constant();
if (curtime != (time_t)-1)
tp->tv_sec = curtime;
}
return (result);
}