mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:22:18 +08:00
Squashed commit of the following:
fs/procfs/fs_procfsproc: Extended the process ID ProcFS output to show per-thread maximum time for pre-emption disabled and maximum time within a critical section.
sched/sched/sched_critmonitor.c: Adds data collection logic in support of monitoring critical sections and pre-emption state.
This commit is contained in:
+124
-1
@@ -53,6 +53,10 @@
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
@@ -62,7 +66,7 @@
|
||||
#include <nuttx/fs/procfs.h>
|
||||
#include <nuttx/fs/dirent.h>
|
||||
|
||||
#ifdef CONFIG_SCHED_CPULOAD
|
||||
#if defined(CONFIG_SCHED_CPULOAD) || defined(CONFIG_SCHED_CRITMONITOR)
|
||||
# include <nuttx/clock.h>
|
||||
#endif
|
||||
|
||||
@@ -105,6 +109,9 @@ enum proc_node_e
|
||||
PROC_CMDLINE, /* Task command line */
|
||||
#ifdef CONFIG_SCHED_CPULOAD
|
||||
PROC_LOADAVG, /* Average CPU utilization */
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
PROC_CRITMON, /* Critical section monitor */
|
||||
#endif
|
||||
PROC_STACK, /* Task stack info */
|
||||
PROC_GROUP, /* Group directory */
|
||||
@@ -167,9 +174,24 @@ static FAR const char *g_policy[4] =
|
||||
"SCHED_FIFO", "SCHED_RR", "SCHED_SPORADIC", "SCHED_OTHER"
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* External Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
/* If CONFIG_SCHED_CRITMONITOR is selected, then platform-specific logic
|
||||
* must provide the following interface. This interface simply converts an
|
||||
* elapsed time into well known units for presentation by the ProcFS file
|
||||
* system..
|
||||
*/
|
||||
|
||||
void up_critmon_convert(uint32_t starttime, FAR struct timespec *ts);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Helpers */
|
||||
|
||||
static FAR const struct proc_node_s *
|
||||
@@ -185,6 +207,11 @@ static ssize_t proc_loadavg(FAR struct proc_file_s *procfile,
|
||||
FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen,
|
||||
off_t offset);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
static ssize_t proc_critmon(FAR struct proc_file_s *procfile,
|
||||
FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen,
|
||||
off_t offset);
|
||||
#endif
|
||||
static ssize_t proc_stack(FAR struct proc_file_s *procfile,
|
||||
FAR struct tcb_s *tcb, FAR char *buffer, size_t buflen,
|
||||
off_t offset);
|
||||
@@ -273,6 +300,13 @@ static const struct proc_node_s g_loadavg =
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
static const struct proc_node_s g_critmon =
|
||||
{
|
||||
"critmon", "critmon", (uint8_t)PROC_CRITMON, DTYPE_FILE /* Critical Section Monitor */
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct proc_node_s g_stack =
|
||||
{
|
||||
"stack", "stack", (uint8_t)PROC_STACK, DTYPE_FILE /* Task stack info */
|
||||
@@ -309,6 +343,9 @@ static FAR const struct proc_node_s * const g_nodeinfo[] =
|
||||
&g_cmdline, /* Task command line */
|
||||
#ifdef CONFIG_SCHED_CPULOAD
|
||||
&g_loadavg, /* Average CPU utilization */
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
&g_critmon, /* Critical section Monitor */
|
||||
#endif
|
||||
&g_stack, /* Task stack info */
|
||||
&g_group, /* Group directory */
|
||||
@@ -329,6 +366,9 @@ static const struct proc_node_s * const g_level0info[] =
|
||||
&g_cmdline, /* Task command line */
|
||||
#ifdef CONFIG_SCHED_CPULOAD
|
||||
&g_loadavg, /* Average CPU utilization */
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
&g_critmon, /* Critical section monitor */
|
||||
#endif
|
||||
&g_stack, /* Task stack info */
|
||||
&g_group, /* Group directory */
|
||||
@@ -743,6 +783,84 @@ static ssize_t proc_loadavg(FAR struct proc_file_s *procfile,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: proc_critmon
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
static ssize_t proc_critmon(FAR struct proc_file_s *procfile,
|
||||
FAR struct tcb_s *tcb, FAR char *buffer,
|
||||
size_t buflen, off_t offset)
|
||||
{
|
||||
struct timespec maxtime;
|
||||
size_t remaining;
|
||||
size_t linesize;
|
||||
size_t copysize;
|
||||
size_t totalsize;
|
||||
|
||||
remaining = buflen;
|
||||
totalsize = 0;
|
||||
|
||||
/* Convert the for maximum time pre-emption disabled */
|
||||
|
||||
if (tcb->premp_max > 0)
|
||||
{
|
||||
up_critmon_convert(tcb->premp_max, &maxtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxtime.tv_sec = 0;
|
||||
maxtime.tv_nsec = 0;
|
||||
}
|
||||
|
||||
/* Reset the maximum */
|
||||
|
||||
tcb->premp_max = 0;
|
||||
|
||||
/* Generate output for maximum time pre-emption disabled */
|
||||
|
||||
linesize = snprintf(procfile->line, STATUS_LINELEN, "%lu.%09lu,",
|
||||
(unsigned long)maxtime.tv_sec,
|
||||
(unsigned long)maxtime.tv_nsec);
|
||||
copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, &offset);
|
||||
|
||||
totalsize += copysize;
|
||||
buffer += copysize;
|
||||
remaining -= copysize;
|
||||
|
||||
if (totalsize >= buflen)
|
||||
{
|
||||
return totalsize;
|
||||
}
|
||||
|
||||
/* Convert and generate output for maximum time in a critical section */
|
||||
|
||||
if (tcb->crit_max > 0)
|
||||
{
|
||||
up_critmon_convert(tcb->crit_max, &maxtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxtime.tv_sec = 0;
|
||||
maxtime.tv_nsec = 0;
|
||||
}
|
||||
|
||||
/* Reset the maximum */
|
||||
|
||||
tcb->crit_max = 0;
|
||||
|
||||
/* Generate output for maximum time in a critical section */
|
||||
|
||||
linesize = snprintf(procfile->line, STATUS_LINELEN, "%lu.%09lu\n",
|
||||
(unsigned long)maxtime.tv_sec,
|
||||
(unsigned long)maxtime.tv_nsec);
|
||||
copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, &offset);
|
||||
|
||||
totalsize += copysize;
|
||||
return totalsize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: proc_stack
|
||||
****************************************************************************/
|
||||
@@ -1324,6 +1442,11 @@ static ssize_t proc_read(FAR struct file *filep, FAR char *buffer,
|
||||
case PROC_LOADAVG: /* Average CPU utilization */
|
||||
ret = proc_loadavg(procfile, tcb, buffer, buflen, filep->f_pos);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
case PROC_CRITMON: /* Critical section monitor */
|
||||
ret = proc_critmon(procfile, tcb, buffer, buflen, filep->f_pos);
|
||||
break;
|
||||
#endif
|
||||
case PROC_STACK: /* Task stack info */
|
||||
ret = proc_stack(procfile, tcb, buffer, buflen, filep->f_pos);
|
||||
|
||||
+6
-3
@@ -1,7 +1,8 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/irq.h
|
||||
*
|
||||
* Copyright (C) 2007-2011, 2013, 2016-2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2011, 2013, 2016-2017 Gregory Nutt. All rights
|
||||
* reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -196,7 +197,8 @@ int irqchain_detach(int irq, xcpt_t isr, FAR void *arg);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
irqstate_t enter_critical_section(void);
|
||||
#else
|
||||
# define enter_critical_section(f) up_irq_save(f)
|
||||
@@ -223,7 +225,8 @@ irqstate_t enter_critical_section(void);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
void leave_critical_section(irqstate_t flags);
|
||||
#else
|
||||
# define leave_critical_section(f) up_irq_restore(f)
|
||||
|
||||
+14
-2
@@ -696,6 +696,16 @@ struct tcb_s
|
||||
FAR void *pthread_data[CONFIG_NPTHREAD_KEYS];
|
||||
#endif
|
||||
|
||||
/* Pre-emption monitor support ************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
uint32_t crit_flags; /* Flag values used by the monitor */
|
||||
uint32_t premp_start; /* Time when preemption disabled */
|
||||
uint32_t premp_max; /* Max time preemption disabled */
|
||||
uint32_t crit_start; /* Time critical section entered */
|
||||
uint32_t crit_max; /* Max time in critical section */
|
||||
#endif
|
||||
|
||||
/* Library related fields *****************************************************/
|
||||
|
||||
int pterrno; /* Current per-thread errno */
|
||||
@@ -931,7 +941,8 @@ int group_exitinfo(pid_t pid, FAR struct binary_s *bininfo);
|
||||
********************************************************************************/
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) || \
|
||||
defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SMP)
|
||||
defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SCHED_CRITMONITOR) || \
|
||||
defined(CONFIG_SMP)
|
||||
void sched_resume_scheduler(FAR struct tcb_s *tcb);
|
||||
#else
|
||||
# define sched_resume_scheduler(tcb)
|
||||
@@ -953,7 +964,8 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb);
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION)
|
||||
#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
void sched_suspend_scheduler(FAR struct tcb_s *tcb);
|
||||
#else
|
||||
# define sched_suspend_scheduler(tcb)
|
||||
|
||||
@@ -700,6 +700,39 @@ config SCHED_IRQMONITOR
|
||||
counts will be available in the mounted procfs file systems at the
|
||||
top-level file, "irqs".
|
||||
|
||||
config SCHED_CRITMONITOR
|
||||
bool "Enable Critical Section monitoring"
|
||||
default n
|
||||
depends on FS_PROCFS
|
||||
---help---
|
||||
Enables logic that monitors the duration of time that a thread keeps
|
||||
interrupts or pre-emption disabled. These global locks can have
|
||||
negative consequences to real timer performance: Disabling interrupts
|
||||
adds jitter in the time when a interrupt request is asserted until
|
||||
the hardware can responds with the interrupt. Disabling pre-emption
|
||||
adds jitter in the timer from when the event is posted in the
|
||||
interrupt handler until the task that responds to the event can run.
|
||||
|
||||
If this option is selected, then the following interfaces must be
|
||||
provided by platform-specific logic:
|
||||
|
||||
uint32_t up_critmon_gettime(void);
|
||||
void up_critmon_convert(uint32_t starttime, FAR struct timespec *ts);
|
||||
|
||||
The first interface simply provides the current time value in unknown
|
||||
units. NOTE: This function may be called early before the timer has
|
||||
been initialized. In that event, the function should just return a
|
||||
start time of zero.
|
||||
|
||||
Nothing is assumed about the units of this time value. The following
|
||||
are assumed, however: (1) The time is an unsigned is an unsigned integer
|
||||
value, (2) is is monotonically increasing, and (3) the elapsed time
|
||||
(also in unknown units) can be obtained by subtracting a start time
|
||||
from the current time.
|
||||
|
||||
The second interface simple converts an elapsed time into well known
|
||||
units for presentation by the ProcFS file system..
|
||||
|
||||
config SCHED_CPULOAD
|
||||
bool "Enable CPU load monitoring"
|
||||
default n
|
||||
|
||||
@@ -44,6 +44,8 @@ endif
|
||||
endif
|
||||
else ifeq ($(CONFIG_SCHED_INSTRUMENTATION_CSECTION),y)
|
||||
CSRCS += irq_csection.c
|
||||
else ifeq ($(CONFIG_SCHED_CRITMONITOR),y)
|
||||
CSRCS += irq_csection.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_IRQMONITOR),y)
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
#include "sched/sched.h"
|
||||
#include "irq/irq.h"
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION)
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
@@ -375,9 +376,12 @@ try_again:
|
||||
&g_cpu_irqlock);
|
||||
rtcb->irqcount = 1;
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
/* Note that we have entered the critical section */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_csection(rtcb, true);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
sched_note_csection(rtcb, true);
|
||||
#endif
|
||||
}
|
||||
@@ -388,7 +392,8 @@ try_again:
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */
|
||||
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) || \
|
||||
* defined(CONFIG_SCHED_CRITMONITOR) */
|
||||
irqstate_t enter_critical_section(void)
|
||||
{
|
||||
irqstate_t ret;
|
||||
@@ -408,7 +413,12 @@ irqstate_t enter_critical_section(void)
|
||||
|
||||
/* Yes.. Note that we have entered the critical section */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_csection(rtcb, true);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
sched_note_csection(rtcb, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return interrupt status */
|
||||
@@ -507,9 +517,12 @@ void leave_critical_section(irqstate_t flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
/* No.. Note that we have left the critical section */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_csection(rtcb, false);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
sched_note_csection(rtcb, false);
|
||||
#endif
|
||||
/* Decrement our count on the lock. If all CPUs have
|
||||
@@ -563,7 +576,10 @@ void leave_critical_section(irqstate_t flags)
|
||||
|
||||
up_irq_restore(flags);
|
||||
}
|
||||
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) */
|
||||
|
||||
#else /* defined(CONFIG_SCHED_INSTRUMENTATION_CSECTION) ||
|
||||
* defined(CONFIG_SCHED_CRITMONITOR) */
|
||||
|
||||
void leave_critical_section(irqstate_t flags)
|
||||
{
|
||||
/* Check if we were called from an interrupt handler and that the tasks
|
||||
@@ -577,7 +593,12 @@ void leave_critical_section(irqstate_t flags)
|
||||
|
||||
/* Yes.. Note that we have left the critical section */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_csection(rtcb, false);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_CSECTION
|
||||
sched_note_csection(rtcb, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Restore the previous interrupt state. */
|
||||
@@ -669,4 +690,5 @@ bool irq_cpu_locked(int cpu)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SMP || CONFIG_SCHED_INSTRUMENTATION_CSECTION */
|
||||
#endif /* CONFIG_SMP || CONFIG_SCHED_INSTRUMENTATION_CSECTION ||
|
||||
* CONFIG_SCHED_CRITMONITOR */
|
||||
|
||||
+12
-4
@@ -73,6 +73,8 @@ ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_sporadic.c sched_suspendscheduler.c
|
||||
else ifeq ($(CONFIG_SCHED_INSTRUMENTATION),y)
|
||||
CSRCS += sched_suspendscheduler.c
|
||||
else ifeq ($(CONFIG_SCHED_CRITMONITOR),y)
|
||||
CSRCS += sched_suspendscheduler.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_RR_INTERVAL),0)
|
||||
@@ -81,6 +83,8 @@ else ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_resumescheduler.c
|
||||
else ifeq ($(CONFIG_SCHED_INSTRUMENTATION),y)
|
||||
CSRCS += sched_resumescheduler.c
|
||||
else ifeq ($(CONFIG_SCHED_CRITMONITOR),y)
|
||||
CSRCS += sched_resumescheduler.c
|
||||
else ifeq ($(CONFIG_SMP),y)
|
||||
CSRCS += sched_resumescheduler.c
|
||||
endif
|
||||
@@ -101,10 +105,6 @@ else
|
||||
CSRCS += sched_processtimer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y)
|
||||
CSRCS += sched_note.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
CSRCS += sched_tasklistlock.c
|
||||
ifeq ($(CONFIG_ARCH_GLOBAL_IRQDISABLE),y)
|
||||
@@ -114,6 +114,14 @@ CSRCS += sched_thistask.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_INSTRUMENTATION_BUFFER),y)
|
||||
CSRCS += sched_note.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_CRITMONITOR),y)
|
||||
CSRCS += sched_critmonitor.c
|
||||
endif
|
||||
|
||||
# Include sched build support
|
||||
|
||||
DEPPATH += --dep-path sched
|
||||
|
||||
@@ -496,6 +496,15 @@ void sched_tasklist_unlock(irqstate_t lock);
|
||||
void weak_function sched_process_cpuload(void);
|
||||
#endif
|
||||
|
||||
/* Critical section monitor */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
void sched_critmon_preemption(FAR struct tcb_s *tcb, bool state);
|
||||
void sched_critmon_csection(FAR struct tcb_s *tcb, bool state);
|
||||
void sched_critmon_resume(FAR struct tcb_s *tcb);
|
||||
void sched_critmon_suspend(FAR struct tcb_s *tcb);
|
||||
#endif
|
||||
|
||||
/* TCB operations */
|
||||
|
||||
bool sched_verifytcb(FAR struct tcb_s *tcb);
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_critmonitor.c
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sched.h>
|
||||
#include "sched/sched.h"
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Flags used by the critical section monitor */
|
||||
|
||||
#define CRITMON_PREEMPT (1 << 0) /* Bit 0: Pre-emption is disabled */
|
||||
#define CRITMON_CSECTION (1 << 1) /* Bit 1: In a critical section */
|
||||
|
||||
#define DISABLE_PREEMPT(t) do { (t)->flags |= CRITMON_PREEMPT; } while (0)
|
||||
#define ENTER_CSECTION(t) do { (t)->flags |= CRITMON_PREEMPT; } while (0)
|
||||
|
||||
#define ENABLE_PREEMPT(t) do { (t)->flags &= ~CRITMON_PREEMPT; } while (0)
|
||||
#define LEAVE_CSECTION(t) do { (t)->flags &= ~CRITMON_PREEMPT; } while (0)
|
||||
|
||||
#define PREEMPT_DISABLED(t) (((t)->crit_flags & CRITMON_PREEMPT) != 0)
|
||||
#define IN_CSECTION(t) (((t)->crit_flags & CRITMON_CSECTION) != 0)
|
||||
|
||||
/****************************************************************************
|
||||
* External Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* If CONFIG_SCHED_CRITMONITOR is selected, then platform-specific logic
|
||||
* must provide the following interface. This interface simply provides the
|
||||
* current time value in unknown units. NOTE: This function may be called
|
||||
* early before the timer has been initialized. In that event, the function
|
||||
* should just return a start time of zero.
|
||||
*
|
||||
* Nothing is assumed about the units of this time value. The following
|
||||
* are assumed, however: (1) The time is an unsigned is an unsigned integer
|
||||
* value, (2) is is monotonically increasing, and (3) the elapsed time
|
||||
* (also in unknown units) can be obtained by subtracting a start time
|
||||
* from the current time.
|
||||
*/
|
||||
|
||||
uint32_t up_critmon_gettime(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_critmon_preemption
|
||||
*
|
||||
* Description:
|
||||
* Called when there is any change in pre-emptible state of a thread.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called within a critical section.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_critmon_preemption(FAR struct tcb_s *tcb, bool state)
|
||||
{
|
||||
/* Are we enabling or disabling pre-emption */
|
||||
|
||||
if (state)
|
||||
{
|
||||
DEBUGASSERT(tcb->premp_start == 0 && !PREEMPT_DISABLED(tcb));
|
||||
|
||||
/* Disabling.. Save the start time */
|
||||
|
||||
tcb->premp_start = up_critmon_gettime();
|
||||
DISABLE_PREEMPT(tcb);
|
||||
}
|
||||
else if (tcb->premp_start != 0)
|
||||
{
|
||||
DEBUGASSERT(PREEMPT_DISABLED(tcb));
|
||||
|
||||
/* Re-enabling.. Check for the max elapsed time */
|
||||
|
||||
uint32_t elapsed = tcb->premp_start - up_critmon_gettime();
|
||||
|
||||
tcb->premp_start = 0;
|
||||
if (elapsed > tcb->premp_max)
|
||||
{
|
||||
tcb->premp_max = elapsed;
|
||||
}
|
||||
|
||||
ENABLE_PREEMPT(tcb);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_critmon_csection
|
||||
*
|
||||
* Description:
|
||||
* Called when a thread enters or leaves a critical section.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called within a critical section.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_critmon_csection(FAR struct tcb_s *tcb, bool state)
|
||||
{
|
||||
/* Are we entering or leaving the critical section? */
|
||||
|
||||
if (state)
|
||||
{
|
||||
/* Entering... Save the start time. */
|
||||
|
||||
DEBUGASSERT(tcb->crit_start == 0 && !IN_CSECTION(tcb));
|
||||
tcb->crit_start = up_critmon_gettime();
|
||||
}
|
||||
else if (tcb->crit_start != 0)
|
||||
{
|
||||
DEBUGASSERT(IN_CSECTION(tcb));
|
||||
|
||||
/* Leaving .. Check for the max elapsed time */
|
||||
|
||||
uint32_t elapsed = tcb->crit_start - up_critmon_gettime();
|
||||
|
||||
tcb->crit_start = 0;
|
||||
if (elapsed > tcb->crit_max)
|
||||
{
|
||||
tcb->crit_max = elapsed;
|
||||
}
|
||||
|
||||
ENTER_CSECTION(tcb);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_critmon_resume
|
||||
*
|
||||
* Description:
|
||||
* Called when a thread resumes execution, perhaps re-establishing a
|
||||
* critical section or a non-pre-emptible state.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called within a critical section.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_critmon_resume(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb->premp_start == 0 && tcb->crit_start == 0);
|
||||
|
||||
/* Did this task disable pre-emption? */
|
||||
|
||||
if (PREEMPT_DISABLED(tcb))
|
||||
{
|
||||
/* Yes.. Save the start time */
|
||||
|
||||
tcb->premp_start = up_critmon_gettime();
|
||||
}
|
||||
|
||||
/* Was this task in a critical section? */
|
||||
|
||||
if (IN_CSECTION(tcb))
|
||||
{
|
||||
/* Yes.. Save the start time */
|
||||
|
||||
tcb->crit_start = up_critmon_gettime();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_critmon_suspend
|
||||
*
|
||||
* Description:
|
||||
* Called when a thread suspends execution, perhaps terminating a
|
||||
* critical section or a non-pre-emptible state.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called within a critical section.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_critmon_suspend(FAR struct tcb_s *tcb)
|
||||
{
|
||||
/* Did this task disable pre-emption? */
|
||||
|
||||
if (PREEMPT_DISABLED(tcb))
|
||||
{
|
||||
/* Re-enabling.. Check for the max elapsed time */
|
||||
|
||||
uint32_t elapsed = tcb->premp_start - up_critmon_gettime();
|
||||
|
||||
tcb->premp_start = 0;
|
||||
if (elapsed > tcb->premp_max)
|
||||
{
|
||||
tcb->premp_max = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is this task in a critical section? */
|
||||
|
||||
if (IN_CSECTION(tcb))
|
||||
{
|
||||
/* Leaving .. Check for the max elapsed time */
|
||||
|
||||
uint32_t elapsed = tcb->crit_start - up_critmon_gettime();
|
||||
|
||||
tcb->crit_start = 0;
|
||||
if (elapsed > tcb->crit_max)
|
||||
{
|
||||
tcb->crit_max = elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -250,14 +250,20 @@ int sched_lock(void)
|
||||
(void)up_fetchsub16(&g_global_lockcount, 1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
#if defined(CONFIG_SCHED_INSTRUMENTATION_PREEMPTION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
/* Check if we just acquired the lock */
|
||||
|
||||
if (rtcb->lockcount == 1)
|
||||
{
|
||||
/* Note that we have pre-emption locked */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_premption(rtcb, true);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
sched_note_premption(rtcb, true);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -299,14 +305,20 @@ int sched_lock(void)
|
||||
|
||||
rtcb->lockcount++;
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
#if defined(CONFIG_SCHED_INSTRUMENTATION_PREEMPTION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
/* Check if we just acquired the lock */
|
||||
|
||||
if (rtcb->lockcount == 1)
|
||||
{
|
||||
/* Note that we have pre-emption locked */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_premption(rtcb, true);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
sched_note_premption(rtcb, true);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_resumescheduler.c
|
||||
*
|
||||
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,7 +49,8 @@
|
||||
#include "sched/sched.h"
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) || \
|
||||
defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SMP)
|
||||
defined(CONFIG_SCHED_INSTRUMENTATION) || defined(CONFIG_SCHED_CRITMONITOR) || \
|
||||
defined(CONFIG_SMP)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -96,9 +97,12 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Inidicate the task has been resumed */
|
||||
/* Indicate the task has been resumed */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_resume(tcb);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
sched_note_resume(tcb);
|
||||
#endif
|
||||
|
||||
@@ -142,4 +146,5 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RR_INTERVAL > 0 || CONFIG_SCHED_SPORADIC || \
|
||||
* CONFIG_SCHED_INSTRUMENTATION || CONFIG_SMP */
|
||||
* CONFIG_SCHED_INSTRUMENTATION || CONFIG_SCHED_CRITMONITOR ||
|
||||
* CONFIG_SMP */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_suspendscheduler.c
|
||||
*
|
||||
* Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2015-2016, 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -50,7 +50,8 @@
|
||||
#include "clock/clock.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION)
|
||||
#if defined(CONFIG_SCHED_SPORADIC) || defined(CONFIG_SCHED_INSTRUMENTATION) || \
|
||||
defined(CONFIG_SCHED_CRITMONITOR)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -83,11 +84,15 @@ void sched_suspend_scheduler(FAR struct tcb_s *tcb)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Inidicate the task has been suspended */
|
||||
/* Indicate that the task has been suspended */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_suspend(tcb);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
sched_note_suspend(tcb);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_SPORADIC || CONFIG_SCHED_INSTRUMENTATION */
|
||||
#endif /* CONFIG_SCHED_SPORADIC || CONFIG_SCHED_INSTRUMENTATION ||
|
||||
* CONFIG_SCHED_CRITMONITOR */
|
||||
|
||||
@@ -103,11 +103,15 @@ int sched_unlock(void)
|
||||
|
||||
if (rtcb->lockcount <= 0)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
/* Note that we no longer have pre-emption disabled. */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_premption(rtcb, false);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
sched_note_premption(rtcb, false);
|
||||
#endif
|
||||
|
||||
/* Set the lock count to zero */
|
||||
|
||||
rtcb->lockcount = 0;
|
||||
@@ -254,11 +258,15 @@ int sched_unlock(void)
|
||||
|
||||
if (rtcb->lockcount <= 0)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
/* Note that we no longer have pre-emption disabled. */
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
sched_critmon_premption(rtcb, false);
|
||||
#endif
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
|
||||
sched_note_premption(rtcb, false);
|
||||
#endif
|
||||
|
||||
/* Set the lock count to zero */
|
||||
|
||||
rtcb->lockcount = 0;
|
||||
|
||||
Reference in New Issue
Block a user