gettimeofday: avoid per-cpu data in calculation
Because it is difficult to safely update per-cpu data of other cpus in settimeofday().
This commit is contained in:
@ -73,11 +73,6 @@ struct cpu_local_var {
|
||||
int in_interrupt;
|
||||
int no_preempt;
|
||||
int timer_enabled;
|
||||
|
||||
unsigned long tv_sec;
|
||||
unsigned long tv_nsec;
|
||||
unsigned long last_tsc;
|
||||
|
||||
} __attribute__((aligned(64)));
|
||||
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <ihk/context.h>
|
||||
#include <ihk/memconst.h>
|
||||
#include <rlimit.h>
|
||||
#include <time.h>
|
||||
|
||||
#define NUM_SYSCALLS 255
|
||||
|
||||
@ -286,4 +287,9 @@ struct procfs_file {
|
||||
};
|
||||
|
||||
extern void terminate(int, int);
|
||||
|
||||
/* kernel/syscall.c */
|
||||
extern struct timespec origin_ts; /* realtime when tsc=0 */
|
||||
extern unsigned long clocks_per_sec;
|
||||
|
||||
#endif
|
||||
|
||||
@ -201,11 +201,21 @@ static void pc_test(void)
|
||||
}
|
||||
|
||||
extern void ihk_mc_get_boot_time(unsigned long *tv_sec, unsigned long *tv_nsec);
|
||||
extern unsigned long ihk_mc_get_ns_per_tsc(void);
|
||||
|
||||
static void time_init(void)
|
||||
{
|
||||
ihk_mc_get_boot_time(&cpu_local_var(tv_sec),
|
||||
&cpu_local_var(tv_nsec));
|
||||
cpu_local_var(last_tsc) = 0;
|
||||
unsigned long tv_sec, tv_nsec;
|
||||
unsigned long ns_per_kclock;
|
||||
|
||||
ihk_mc_get_boot_time(&tv_sec, &tv_nsec);
|
||||
ns_per_kclock = ihk_mc_get_ns_per_tsc();
|
||||
|
||||
origin_ts.tv_sec = tv_sec;
|
||||
origin_ts.tv_nsec = tv_nsec;
|
||||
clocks_per_sec = (1000L * NS_PER_SEC) / ns_per_kclock;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void rest_init(void)
|
||||
@ -233,11 +243,9 @@ static void rest_init(void)
|
||||
int host_ikc_inited = 0;
|
||||
extern int num_processors;
|
||||
extern void zero_tsc(void);
|
||||
extern void update_cpu_local_time(void);
|
||||
|
||||
static void post_init(void)
|
||||
{
|
||||
int i;
|
||||
cpu_enable_interrupt();
|
||||
|
||||
while (!host_ikc_inited) {
|
||||
@ -253,16 +261,9 @@ static void post_init(void)
|
||||
ihk_mc_spinlock_init(&syscall_lock);
|
||||
}
|
||||
|
||||
/* Update time elapsed so far during boot, distribute the current
|
||||
* date to all cores and zero TSC.
|
||||
/* Zero TSC.
|
||||
* All AP cores are wait spinning for ap_start() and they will zero
|
||||
* their TSC immediatly. */
|
||||
update_cpu_local_time();
|
||||
cpu_local_var(last_tsc) = 0;
|
||||
for (i = 0; i < num_processors; ++i) {
|
||||
get_cpu_local_var(i)->tv_sec = cpu_local_var(tv_sec);
|
||||
get_cpu_local_var(i)->tv_nsec = cpu_local_var(tv_nsec);
|
||||
}
|
||||
zero_tsc();
|
||||
ap_start();
|
||||
|
||||
|
||||
@ -94,6 +94,9 @@ static char *syscall_name[] MCKERNEL_UNUSED = {
|
||||
#undef SYSCALL_DELEGATED
|
||||
};
|
||||
|
||||
struct timespec origin_ts;
|
||||
unsigned long clocks_per_sec;
|
||||
|
||||
void check_signal(unsigned long, void *, int);
|
||||
void do_signal(long rc, void *regs, struct thread *thread, struct sig_pending *pending, int num);
|
||||
extern unsigned long do_kill(struct thread *thread, int pid, int tid, int sig, struct siginfo *info, int ptracecont);
|
||||
@ -4786,30 +4789,26 @@ SYSCALL_DECLARE(get_cpu_id)
|
||||
return ihk_mc_get_processor_id();
|
||||
}
|
||||
|
||||
void __update_time_from_tsc_delta(unsigned long *tv_sec,
|
||||
unsigned long *tv_nsec,
|
||||
unsigned long tsc_delta)
|
||||
static void calculate_time_from_tsc(struct timespec *ts)
|
||||
{
|
||||
unsigned long ns_delta = tsc_delta * ihk_mc_get_ns_per_tsc() / 1000;
|
||||
unsigned long current_tsc;
|
||||
time_t sec_delta;
|
||||
long ns_delta;
|
||||
|
||||
*tv_sec += (ns_delta / NS_PER_SEC);
|
||||
*tv_nsec += (ns_delta % NS_PER_SEC);
|
||||
if (*tv_nsec > NS_PER_SEC) {
|
||||
*tv_nsec -= NS_PER_SEC;
|
||||
++*tv_sec;
|
||||
current_tsc = rdtsc();
|
||||
sec_delta = current_tsc / clocks_per_sec;
|
||||
ns_delta = NS_PER_SEC * (current_tsc % clocks_per_sec)
|
||||
/ clocks_per_sec;
|
||||
/* calc. of ns_delta overflows if clocks_per_sec exceeds 18.44 GHz */
|
||||
|
||||
ts->tv_sec = origin_ts.tv_sec + sec_delta;
|
||||
ts->tv_nsec = origin_ts.tv_nsec + ns_delta;
|
||||
if (ts->tv_nsec >= NS_PER_SEC) {
|
||||
ts->tv_nsec -= NS_PER_SEC;
|
||||
++ts->tv_sec;
|
||||
}
|
||||
}
|
||||
|
||||
void update_cpu_local_time(void)
|
||||
{
|
||||
unsigned long tsc = rdtsc();
|
||||
|
||||
__update_time_from_tsc_delta(
|
||||
&cpu_local_var(tv_sec),
|
||||
&cpu_local_var(tv_nsec),
|
||||
tsc - cpu_local_var(last_tsc));
|
||||
|
||||
cpu_local_var(last_tsc) = tsc;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -4820,6 +4819,7 @@ SYSCALL_DECLARE(gettimeofday)
|
||||
struct timezone *tz = (struct timezone *)ihk_mc_syscall_arg1(ctx);
|
||||
struct timeval atv;
|
||||
int error;
|
||||
struct timespec ats;
|
||||
|
||||
if (!tv && !tz) {
|
||||
/* nothing to do */
|
||||
@ -4828,10 +4828,10 @@ SYSCALL_DECLARE(gettimeofday)
|
||||
|
||||
/* Do it locally if supported */
|
||||
if (!tz && gettime_local_support) {
|
||||
update_cpu_local_time();
|
||||
calculate_time_from_tsc(&ats);
|
||||
|
||||
atv.tv_sec = cpu_local_var(tv_sec);
|
||||
atv.tv_usec = cpu_local_var(tv_nsec) / 1000;
|
||||
atv.tv_sec = ats.tv_sec;
|
||||
atv.tv_usec = ats.tv_nsec / 1000;
|
||||
|
||||
error = copy_to_user(tv, &atv, sizeof(atv));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user