Add a bit of locking around timecounter attachment / selection.

This commit is contained in:
ad 2007-11-15 20:12:04 +00:00
parent e4df9c1dd8
commit 0239b151ae
4 changed files with 47 additions and 104 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: init_main.c,v 1.329 2007/11/14 19:45:44 ad Exp $ */
/* $NetBSD: init_main.c,v 1.330 2007/11/15 20:12:04 ad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.329 2007/11/14 19:45:44 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.330 2007/11/15 20:12:04 ad Exp $");
#include "opt_ipsec.h"
#include "opt_ntp.h"
@ -344,6 +344,9 @@ main(void)
/* Charge root for one process. */
(void)chgproccnt(0, 1);
/* Initialize timekeeping. */
time_init();
/* Initialize the run queues, turnstiles and sleep queues. */
mutex_init(&cpu_lock, MUTEX_DEFAULT, IPL_NONE);
sched_rqinit();

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_tc.c,v 1.21 2007/10/21 14:55:09 simonb Exp $ */
/* $NetBSD: kern_tc.c,v 1.22 2007/11/15 20:12:04 ad Exp $ */
/*-
* ----------------------------------------------------------------------------
@ -11,7 +11,7 @@
#include <sys/cdefs.h>
/* __FBSDID("$FreeBSD: src/sys/kern/kern_tc.c,v 1.166 2005/09/19 22:16:31 andre Exp $"); */
__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.21 2007/10/21 14:55:09 simonb Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.22 2007/11/15 20:12:04 ad Exp $");
#include "opt_ntp.h"
@ -132,26 +132,21 @@ sysctl_kern_timecounter_hardware(SYSCTLFN_ARGS)
KAUTH_GENERIC_ISSUSER, NULL)) != 0)
return (error);
/* XXX locking */
if (!cold)
mutex_enter(&time_lock);
for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
if (strcmp(newname, newtc->tc_name) != 0)
continue;
/* Warm up new timecounter. */
(void)newtc->tc_get_timecount(newtc);
(void)newtc->tc_get_timecount(newtc);
timecounter = newtc;
/* XXX unlock */
return (0);
}
/* XXX unlock */
return (EINVAL);
error = 0;
} else
error = EINVAL;
if (!cold)
mutex_exit(&time_lock);
return error;
}
static int
@ -174,8 +169,7 @@ sysctl_kern_timecounter_choice(SYSCTLFN_ARGS)
needed = 0;
left = *oldlenp;
/* XXX locking */
mutex_enter(&time_lock);
for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) {
if (where == NULL) {
needed += sizeof(buf); /* be conservative */
@ -186,6 +180,7 @@ sysctl_kern_timecounter_choice(SYSCTLFN_ARGS)
if (left < slen + 1)
break;
/* XXX use sysctl_copyout? (from sysctl_hw_disknames) */
/* XXX copyout with held lock. */
error = copyout(buf, where, slen + 1);
spc = " ";
where += slen;
@ -193,8 +188,7 @@ sysctl_kern_timecounter_choice(SYSCTLFN_ARGS)
left -= slen;
}
}
/* XXX unlock */
mutex_exit(&time_lock);
*oldlenp = needed;
return (error);
@ -459,8 +453,8 @@ tc_init(struct timecounter *tc)
tc->tc_quality);
}
s = splclock();
mutex_enter(&time_lock);
s = splsched();
tc->tc_next = timecounters;
timecounters = tc;
/*
@ -468,20 +462,15 @@ tc_init(struct timecounter *tc)
* Even though we run on the dummy counter, switching here may be
* worse since this timecounter may not be monotonous.
*/
if (tc->tc_quality < 0)
goto out;
if (tc->tc_quality < timecounter->tc_quality)
goto out;
if (tc->tc_quality == timecounter->tc_quality &&
tc->tc_frequency < timecounter->tc_frequency)
goto out;
(void)tc->tc_get_timecount(tc);
(void)tc->tc_get_timecount(tc);
timecounter = tc;
tc_windup();
out:
if (tc->tc_quality >= 0 && (tc->tc_quality > timecounter->tc_quality ||
tc->tc_frequency > timecounter->tc_frequency)) {
(void)tc->tc_get_timecount(tc);
(void)tc->tc_get_timecount(tc);
timecounter = tc;
tc_windup();
}
splx(s);
mutex_exit(&time_lock);
}
/* Report the frequency of the current timecounter. */
@ -660,64 +649,6 @@ tc_windup(void)
timehands = th;
}
#ifdef __FreeBSD__
/* Report or change the active timecounter hardware. */
static int
sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
{
char newname[32];
struct timecounter *newtc, *tc;
int error;
tc = timecounter;
strlcpy(newname, tc->tc_name, sizeof(newname));
error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
if (error != 0 || req->newptr == NULL ||
strcmp(newname, tc->tc_name) == 0)
return (error);
for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
if (strcmp(newname, newtc->tc_name) != 0)
continue;
/* Warm up new timecounter. */
(void)newtc->tc_get_timecount(newtc);
(void)newtc->tc_get_timecount(newtc);
timecounter = newtc;
return (0);
}
return (EINVAL);
}
SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
0, 0, sysctl_kern_timecounter_hardware, "A", "");
/* Report or change the active timecounter hardware. */
static int
sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
{
char buf[32], *spc;
struct timecounter *tc;
int error;
spc = "";
error = 0;
for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) {
sprintf(buf, "%s%s(%d)",
spc, tc->tc_name, tc->tc_quality);
error = SYSCTL_OUT(req, buf, strlen(buf));
spc = " ";
}
return (error);
}
SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
0, 0, sysctl_kern_timecounter_choice, "A", "");
#endif /* __FreeBSD__ */
/*
* RFC 2783 PPS-API implementation.
*/
@ -893,9 +824,6 @@ pps_event(struct pps_state *pps, int event)
*/
static int tc_tick;
#ifdef __FreeBSD__
SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, "");
#endif /* __FreeBSD__ */
void
tc_ticktock(void)
@ -934,7 +862,4 @@ inittimecounter(void)
(void)timecounter->tc_get_timecount(timecounter);
}
#ifdef __FreeBSD__
SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL)
#endif /* __FreeBSD__ */
#endif /* __HAVE_TIMECOUNTER */

View File

@ -1,7 +1,7 @@
/* $NetBSD: kern_time.c,v 1.130 2007/10/19 12:16:43 ad Exp $ */
/* $NetBSD: kern_time.c,v 1.131 2007/11/15 20:12:04 ad Exp $ */
/*-
* Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2004, 2005, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.130 2007/10/19 12:16:43 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.131 2007/11/15 20:12:04 ad Exp $");
#include <sys/param.h>
#include <sys/resourcevar.h>
@ -91,11 +91,23 @@ __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.130 2007/10/19 12:16:43 ad Exp $");
#include <sys/cpu.h>
kmutex_t time_lock;
POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl",
&pool_allocator_nointr, IPL_NONE);
POOL_INIT(ptimers_pool, sizeof(struct ptimers), 0, 0, 0, "ptimerspl",
&pool_allocator_nointr, IPL_NONE);
/*
* Initialize timekeeping.
*/
void
time_init(void)
{
mutex_init(&time_lock, MUTEX_DEFAULT, IPL_NONE);
}
/* Time of day and interval timer support.
*
* These routines provide the kernel entry points to get and set

View File

@ -1,4 +1,4 @@
/* $NetBSD: timevar.h,v 1.15 2007/10/22 05:26:42 simonb Exp $ */
/* $NetBSD: timevar.h,v 1.16 2007/11/15 20:12:04 ad Exp $ */
/*
* Copyright (c) 2005 The NetBSD Foundation.
@ -67,6 +67,7 @@
#include <sys/queue.h>
#include <sys/signal.h>
#include <sys/systm.h>
#include <sys/mutex.h>
/*
* Structure used to manage timers in a process.
@ -191,7 +192,9 @@ int tvtohz(struct timeval *);
int inittimeleft(struct timeval *, struct timeval *);
int gettimeleft(struct timeval *, struct timeval *);
void timerupcall(struct lwp *);
void time_init(void);
extern kmutex_t time_lock;
#ifdef __HAVE_TIMECOUNTER
extern time_t time_second; /* current second in the epoch */
extern time_t time_uptime; /* system uptime in seconds */