/proc/uptime logic needs to sample timer in case multiple reads are used to read the time

This commit is contained in:
Gregory Nutt 2013-12-14 15:25:23 -06:00
parent 46b77e2544
commit 7a173d58b5
3 changed files with 69 additions and 31 deletions

View File

@ -641,7 +641,7 @@ static int process_dup(FAR const struct file *oldp, FAR struct file *newp)
/* Allocate a new container to hold the task and attribute selection */ /* Allocate a new container to hold the task and attribute selection */
newattr = (FAR struct process_file_s *)kzalloc(sizeof(struct process_file_s)); newattr = (FAR struct process_file_s *)kmalloc(sizeof(struct process_file_s));
if (!newattr) if (!newattr)
{ {
fdbg("ERROR: Failed to allocate file attributes\n"); fdbg("ERROR: Failed to allocate file attributes\n");

View File

@ -80,6 +80,11 @@
struct uptime_file_s struct uptime_file_s
{ {
struct procfs_file_s base; /* Base open file structure */ struct procfs_file_s base; /* Base open file structure */
#ifdef CONFIG_SYSTEM_TIME64
uint64_t ticktime; /* Sampled 64-bit timer */
#else
uint32_t ticktime; /* Sampled 32-bit timer */
#endif
char line[UPTIME_LINELEN]; /* Pre-allocated buffer for formatted lines */ char line[UPTIME_LINELEN]; /* Pre-allocated buffer for formatted lines */
}; };
@ -213,33 +218,23 @@ static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
ssize_t ret; ssize_t ret;
#ifdef CONFIG_SYSTEM_TIME64 #ifdef CONFIG_SYSTEM_TIME64
/* 32-bit timer */ uint64_t ticktime;
#if !defined(CONFIG_HAVE_DOUBLE) || !defined(CONFIG_LIBC_FLOATINGPOINT)
uint64_t sec;
#endif
uint64_t upticks = clock_systimer64(); #else
uint32_t ticktime;
#if !defined(CONFIG_HAVE_DOUBLE) || !defined(CONFIG_LIBC_FLOATINGPOINT)
uint32_t sec;
#endif
#endif
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT) #if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
double now = (double)upticks / (double)CLOCKS_PER_SEC; double now;
#else #else
uint64_t sec = upticks / CLOCKS_PER_SEC; unsigned int remainder;
unsigned int remainder = (unsigned int)(upticks % CLOCKS_PER_SEC); unsigned int csec;
unsigned int csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;
#endif
#else
/* 32-bit timer */
uint32_t upticks = clock_systimer();
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
double now = (double)upticks / (double)CLOCKS_PER_SEC;
#else
uint32_t sec = upticks / CLOCKS_PER_SEC;
unsigned int remainder = (unsigned int)(upticks % CLOCKS_PER_SEC);
unsigned int csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;
#endif
#endif #endif
fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen); fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);
@ -249,12 +244,41 @@ static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
attr = (FAR struct uptime_file_s *)filep->f_priv; attr = (FAR struct uptime_file_s *)filep->f_priv;
DEBUGASSERT(attr); DEBUGASSERT(attr);
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT) /* If f_pos is zero, then sample the system time. Otherwise, use
/* Convert the system up time to seconds + hundredths of seconds */ * the cached system time from the previous read(). It is necessary
* save the cached value in case, for example, the user is reading
* the time one byte at a time. In that case, the time must remain
* stable throughout the reads.
*/
linesize = snprintf(attr->line, UPTIME_LINELEN, "%10.2f\n", now); if (filep->f_pos == 0)
{
#ifdef CONFIG_SYSTEM_TIME64
/* 64-bit timer */
attr->ticktime = clock_systimer64();
#else
/* 32-bit timer */
attr->ticktime = clock_systimer();
#endif
}
ticktime = attr->ticktime;
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
/* Convert the system up time to a seconds + hundredths of seconds string */
now = (double)ticktime / (double)CLOCKS_PER_SEC;
linesize = snprintf(attr->line, UPTIME_LINELEN, "%10.2f\n", now);
#else #else
/* Convert the system up time to seconds + hundredths of seconds */
sec = ticktime / CLOCKS_PER_SEC;
remainder = (unsigned int)(ticktime % CLOCKS_PER_SEC);
csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;
/* Make sure that rounding did not force the hundredths of a second above 99 */ /* Make sure that rounding did not force the hundredths of a second above 99 */
if (csec > 99) if (csec > 99)
@ -263,7 +287,7 @@ static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
csec -= 100; csec -= 100;
} }
/* Convert the system up time to seconds + hundredths of seconds */ /* Convert the seconds + hundredths of seconds to a string */
linesize = snprintf(attr->line, UPTIME_LINELEN, "%7lu.%02u\n", sec, csec); linesize = snprintf(attr->line, UPTIME_LINELEN, "%7lu.%02u\n", sec, csec);
@ -306,16 +330,16 @@ static int uptime_dup(FAR const struct file *oldp, FAR struct file *newp)
/* Allocate a new container to hold the task and attribute selection */ /* Allocate a new container to hold the task and attribute selection */
newattr = (FAR struct uptime_file_s *)kzalloc(sizeof(struct uptime_file_s)); newattr = (FAR struct uptime_file_s *)kmalloc(sizeof(struct uptime_file_s));
if (!newattr) if (!newattr)
{ {
fdbg("ERROR: Failed to allocate file attributes\n"); fdbg("ERROR: Failed to allocate file attributes\n");
return -ENOMEM; return -ENOMEM;
} }
/* The copy the file attribtes from the old attributes to the new */ /* The copy the file attributes from the old attributes to the new */
memcpy(&newattr->base, &oldattr->base, sizeof(struct procfs_file_s)); memcpy(newattr, oldattr, sizeof(struct uptime_file_s));
/* Save the new attributes in the new file structure */ /* Save the new attributes in the new file structure */

View File

@ -39,6 +39,20 @@ config MSEC_PER_TICK
may be defined to inform NuttX that the processor hardware is providing may be defined to inform NuttX that the processor hardware is providing
system timer interrupts at some interrupt interval other than 10 msec. system timer interrupts at some interrupt interval other than 10 msec.
config SYSTEM_TIME64
bool "64-bit system clock"
default n
---help---
The system timer is incremented at the rate determined by
MSEC_PER_TICK, typically at 100Hz. The count at any given time is
then the "uptime" in units of system timer ticks. By default, the
system time is 32-bits wide. Those defaults provide a range of about
13.6 years which is probably a sufficient range for "uptime".
However, if the system timer rate is significantly higher than 100Hz
and/or if a very long "uptime" is required, then this option can be
selected to support a 64-bit wide timer.
config RR_INTERVAL config RR_INTERVAL
int "Round robin timeslice (MSEC)" int "Round robin timeslice (MSEC)"
default 0 default 0