From 7905ee17d47789d188fae7c7b00f2f87f2d09831 Mon Sep 17 00:00:00 2001 From: "Nakamura, Yuuichi" Date: Wed, 28 Oct 2020 10:45:30 +0900 Subject: [PATCH] Add task name recording for note RAM driver --- drivers/note/Kconfig | 13 ++ drivers/note/noteram_driver.c | 252 ++++++++++++++++++++++++++++ include/nuttx/note/noteram_driver.h | 24 +++ 3 files changed, 289 insertions(+) diff --git a/drivers/note/Kconfig b/drivers/note/Kconfig index 0424e6d43d..61a22740e0 100644 --- a/drivers/note/Kconfig +++ b/drivers/note/Kconfig @@ -55,6 +55,19 @@ config DRIVER_NOTERAM_BUFSIZE ---help--- The size of the in-memory, circular instrumentation buffer (in bytes). +config DRIVER_NOTERAM_TASKNAME_BUFSIZE + int "Note RAM task name buffer size" + depends on DRIVER_NOTERAM + default 256 if TASK_NAME_SIZE > 0 + default 0 if TASK_NAME_SIZE = 0 + ---help--- + The size of the in-memory task name buffer (in bytes). + The buffer is used to hold the name of the task during instrumentation. + Trace dump can find and show a task name corresponding to given pid in + the instrumentation data by using this buffer. + If 0 is specified, this feature is disabled and trace dump shows only + the name of the newly created task. + config DRIVER_NOTERAM_DEFAULT_NOOVERWRITE bool "Disable overwrite by default" depends on DRIVER_NOTERAM diff --git a/drivers/note/noteram_driver.c b/drivers/note/noteram_driver.c index 9f6cb05063..03dc1c5a82 100644 --- a/drivers/note/noteram_driver.c +++ b/drivers/note/noteram_driver.c @@ -44,8 +44,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -63,6 +65,21 @@ struct noteram_info_s uint8_t ni_buffer[CONFIG_DRIVER_NOTERAM_BUFSIZE]; }; +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +struct noteram_taskname_info_s +{ + uint8_t size; + uint8_t pid[2]; + char name[1]; +}; + +struct noteram_taskname_s +{ + int buffer_used; + char buffer[CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE]; +}; +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -99,6 +116,10 @@ static struct noteram_info_s g_noteram_info = #endif }; +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +static struct noteram_taskname_s g_noteram_taskname; +#endif + #ifdef CONFIG_SMP static volatile spinlock_t g_noteram_lock; #endif @@ -107,6 +128,170 @@ static volatile spinlock_t g_noteram_lock; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: noteram_find_taskname + * + * Description: + * Find task name info corresponding to the specified PID + * + * Input Parameters: + * PID - Task ID + * + * Returned Value: + * Pointer to the task name info + * If the corresponding info doesn't exist in the buffer, NULL is returned. + * + ****************************************************************************/ + +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +static FAR struct noteram_taskname_info_s *noteram_find_taskname(pid_t pid) +{ + int n; + FAR struct noteram_taskname_info_s *ti; + + for (n = 0; n < g_noteram_taskname.buffer_used; ) + { + ti = (FAR struct noteram_taskname_info_s *) + &g_noteram_taskname.buffer[n]; + if (ti->pid[0] + (ti->pid[1] << 8) == pid) + { + return ti; + } + + n += ti->size; + } + + return NULL; +} +#endif + +/**************************************************************************** + * Name: noteram_record_taskname + * + * Description: + * Record the task name info of the specified task + * + * Input Parameters: + * PID - Task ID + * name - task name + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +static void noteram_record_taskname(pid_t pid, const char *name) +{ + FAR struct noteram_taskname_info_s *ti; + size_t tilen; + size_t namelen; + + namelen = strlen(name); + DEBUGASSERT(namelen <= CONFIG_TASK_NAME_SIZE); + tilen = sizeof(struct noteram_taskname_info_s) + namelen; + DEBUGASSERT(tilen <= UCHAR_MAX); + + if (g_noteram_taskname.buffer_used + tilen > + CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE) + { + /* No space in the buffer - ignored */ + + return; + } + + ti = (FAR struct noteram_taskname_info_s *) + &g_noteram_taskname.buffer[g_noteram_taskname.buffer_used]; + ti->size = tilen; + ti->pid[0] = pid & 0xff; + ti->pid[1] = (pid >> 8) & 0xff; + strncpy(ti->name, name, namelen + 1); + g_noteram_taskname.buffer_used += tilen; +} +#endif + +/**************************************************************************** + * Name: noteram_remove_taskname + * + * Description: + * Remove the task name info corresponding to the specified PID + * + * Input Parameters: + * PID - Task ID + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +static void noteram_remove_taskname(pid_t pid) +{ + FAR struct noteram_taskname_info_s *ti; + size_t tilen; + char *src; + int sindex; + + ti = noteram_find_taskname(pid); + if (ti == NULL) + { + return; + } + + tilen = ti->size; + src = (char *)ti + tilen; + sindex = src - g_noteram_taskname.buffer; + + memcpy(ti, src, g_noteram_taskname.buffer_used - sindex); + g_noteram_taskname.buffer_used -= tilen; +} +#endif + +/**************************************************************************** + * Name: noteram_get_taskname + * + * Description: + * Get the task name string of the specified PID + * + * Input Parameters: + * PID - Task ID + * + * Returned Value: + * Pointer to the task name string + * If the corresponding name doesn't exist in the buffer, NULL is returned. + * + ****************************************************************************/ + +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +static const char *noteram_get_taskname(pid_t pid) +{ + irqstate_t irq_mask; + const char *ret = NULL; + FAR struct noteram_taskname_info_s *ti; + FAR struct tcb_s *tcb; + + irq_mask = enter_critical_section(); + + ti = noteram_find_taskname(pid); + if (ti != NULL) + { + ret = ti->name; + } + else + { + tcb = nxsched_get_tcb(pid); + if (tcb != NULL) + { + noteram_record_taskname(pid, tcb->name); + ret = tcb->name; + } + } + + leave_critical_section(irq_mask); + return ret; +} +#endif + /**************************************************************************** * Name: noteram_buffer_clear * @@ -135,6 +320,10 @@ static void noteram_buffer_clear(void) g_noteram_info.ni_overwrite = NOTERAM_MODE_OVERWRITE_DISABLE; } +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 + g_noteram_taskname.buffer_used = 0; +#endif + leave_critical_section(flags); } @@ -255,6 +444,17 @@ static void noteram_remove(void) length = note->nc_length; DEBUGASSERT(length <= noteram_length()); +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 + if (note->nc_type == NOTE_STOP) + { + /* The name of the task is no longer needed because the task is deleted + * and the corresponding notes are lost. + */ + + noteram_remove_taskname(note->nc_pid[0] + (note->nc_pid[1] << 8)); + } +#endif + /* Increment the tail index to remove the entire note from the circular * buffer. */ @@ -534,6 +734,42 @@ static int noteram_ioctl(struct file *filep, int cmd, unsigned long arg) } break; +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 + /* NOTERAM_GETTASKNAME + * - Get task name string + * Argument: A writable pointer to struct note_get_taskname_s + * Result: If -ESRCH, the corresponding task name doesn't + * exist. + */ + + case NOTERAM_GETTASKNAME: + { + struct noteram_get_taskname_s *param; + const char *taskname; + + if (arg == 0) + { + ret = -EINVAL; + break; + } + + param = (struct noteram_get_taskname_s *)arg; + taskname = noteram_get_taskname(param->pid); + if (taskname != NULL) + { + strncpy(param->taskname, taskname, CONFIG_TASK_NAME_SIZE + 1); + param->taskname[CONFIG_TASK_NAME_SIZE] = '\0'; + ret = 0; + } + else + { + param->taskname[0] = '\0'; + ret = -ESRCH; + } + } + break; +#endif + default: break; } @@ -584,6 +820,22 @@ void sched_note_add(FAR const void *note, size_t notelen) return; } +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 + /* Record the name if the new task was created */ + + { + FAR struct note_start_s *note_st; + + note_st = (FAR struct note_start_s *)note; + if (note_st->nst_cmn.nc_type == NOTE_START) + { + noteram_record_taskname(note_st->nst_cmn.nc_pid[0] + + (note_st->nst_cmn.nc_pid[1] << 8), + note_st->nst_name); + } + } +#endif + /* Get the index to the head of the circular buffer */ DEBUGASSERT(note != NULL && notelen < CONFIG_DRIVER_NOTERAM_BUFSIZE); diff --git a/include/nuttx/note/noteram_driver.h b/include/nuttx/note/noteram_driver.h index b845149c28..2b4bcacecf 100644 --- a/include/nuttx/note/noteram_driver.h +++ b/include/nuttx/note/noteram_driver.h @@ -27,6 +27,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -43,12 +44,21 @@ * NOTERAM_SETMODE * - Set overwrite mode * Argument: A read-only pointer to unsigned int + * NOTERAM_GETTASKNAME + * - Get task name string + * Argument: A writable pointer to struct + * noteram_get_taskname_s + * Result: If -ESRCH, the corresponding task name doesn't + * exist. */ #ifdef CONFIG_DRIVER_NOTERAM #define NOTERAM_CLEAR _NOTERAMIOC(0x01) #define NOTERAM_GETMODE _NOTERAMIOC(0x02) #define NOTERAM_SETMODE _NOTERAMIOC(0x03) +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +#define NOTERAM_GETTASKNAME _NOTERAMIOC(0x04) +#endif #endif /* Overwrite mode definitions */ @@ -59,6 +69,20 @@ #define NOTERAM_MODE_OVERWRITE_OVERFLOW 2 #endif +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This is the type of the argument passed to the NOTERAM_GETTASKNAME ioctl */ + +#if CONFIG_DRIVER_NOTERAM_TASKNAME_BUFSIZE > 0 +struct noteram_get_taskname_s +{ + pid_t pid; + char taskname[CONFIG_TASK_NAME_SIZE + 1]; +}; +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/