diff --git a/arch/sim/src/sim/up_heap.c b/arch/sim/src/sim/up_heap.c index 196c6aa9d4..d05c746fe5 100644 --- a/arch/sim/src/sim/up_heap.c +++ b/arch/sim/src/sim/up_heap.c @@ -389,6 +389,18 @@ int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info) return 0; } +/**************************************************************************** + * Name: mm_memdump + * + * Description: + * mm_memdump returns a memory info about specified pid of task/thread. + * + ****************************************************************************/ + +void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid) +{ +} + #ifdef CONFIG_DEBUG_MM /**************************************************************************** diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig index 6d28080119..f5c275f5ad 100644 --- a/fs/procfs/Kconfig +++ b/fs/procfs/Kconfig @@ -96,6 +96,10 @@ config FS_PROCFS_EXCLUDE_MEMINFO bool "Exclude meminfo" default n +config FS_PROCFS_EXCLUDE_MEMDUMP + bool "Exclude memdump" + default n + config FS_PROCFS_INCLUDE_PROGMEM bool "Include prog mem" default n diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 6d04af62bc..0c69f8addb 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -66,6 +66,7 @@ extern const struct procfs_operations irq_operations; extern const struct procfs_operations cpuload_operations; extern const struct procfs_operations critmon_operations; extern const struct procfs_operations meminfo_operations; +extern const struct procfs_operations memdump_operations; extern const struct procfs_operations iobinfo_operations; extern const struct procfs_operations module_operations; extern const struct procfs_operations uptime_operations; @@ -115,6 +116,9 @@ static const struct procfs_entry_s g_procfs_entries[] = #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE }, +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP + { "memdump", &memdump_operations, PROCFS_FILE_TYPE }, +#endif #endif #if defined(CONFIG_MM_IOB) && !defined(CONFIG_FS_PROCFS_EXCLUDE_IOBINFO) diff --git a/fs/procfs/fs_procfsmeminfo.c b/fs/procfs/fs_procfsmeminfo.c index 0156347ea7..13d86da294 100644 --- a/fs/procfs/fs_procfsmeminfo.c +++ b/fs/procfs/fs_procfsmeminfo.c @@ -94,6 +94,12 @@ static void meminfo_progmem(FAR struct progmem_info_s *progmem); static int meminfo_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode); static int meminfo_close(FAR struct file *filep); +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP +static ssize_t memdump_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +#endif static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static int meminfo_dup(FAR const struct file *oldp, @@ -123,6 +129,22 @@ const struct procfs_operations meminfo_operations = meminfo_stat /* stat */ }; +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP +const struct procfs_operations memdump_operations = +{ + meminfo_open, /* open */ + meminfo_close, /* close */ + memdump_read, /* read */ + memdump_write, /* write */ + meminfo_dup, /* dup */ + NULL, /* opendir */ + NULL, /* closedir */ + NULL, /* readdir */ + NULL, /* rewinddir */ + meminfo_stat /* stat */ +}; +#endif + FAR struct procfs_meminfo_entry_s *g_procfs_meminfo = NULL; /**************************************************************************** @@ -206,22 +228,9 @@ static int meminfo_open(FAR struct file *filep, FAR const char *relpath, finfo("Open '%s'\n", relpath); - /* PROCFS is read-only. Any attempt to open with any kind of write - * access is not permitted. - * - * REVISIT: Write-able proc files could be quite useful. - */ - - if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) - { - ferr("ERROR: Only O_RDONLY supported\n"); - return -EACCES; - } - /* Allocate a container to hold the file attributes */ - procfile = (FAR struct meminfo_file_s *) - kmm_zalloc(sizeof(struct meminfo_file_s)); + procfile = kmm_zalloc(sizeof(struct meminfo_file_s)); if (!procfile) { ferr("ERROR: Failed to allocate file attributes\n"); @@ -230,7 +239,7 @@ static int meminfo_open(FAR struct file *filep, FAR const char *relpath, /* Save the attributes as the open-specific state in filep->f_priv */ - filep->f_priv = (FAR void *)procfile; + filep->f_priv = procfile; return OK; } @@ -382,6 +391,88 @@ static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer, return totalsize; } +/**************************************************************************** + * Name: memdump_read + ****************************************************************************/ + +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP +static ssize_t memdump_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct meminfo_file_s *procfile; + size_t linesize; + size_t copysize; + size_t totalsize; + off_t offset; + + finfo("buffer=%p buflen=%d\n", buffer, (int)buflen); + + DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0); + offset = filep->f_pos; + + /* Recover our private data from the struct file instance */ + + procfile = (FAR struct meminfo_file_s *)filep->f_priv; + DEBUGASSERT(procfile); + + linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, + "usage: \n"); + + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, + &offset); + totalsize = copysize; + buffer += copysize; + buflen -= copysize; + linesize = procfs_snprintf(procfile->line, MEMINFO_LINELEN, "%s", + "used: dump all allocated node\n" + "free: dump all free node\n"); + + totalsize += procfs_memcpy(procfile->line, linesize, buffer, buflen, + &offset); + filep->f_pos += totalsize; + return totalsize; +} +#endif + +/**************************************************************************** + * Name: memdump_write + ****************************************************************************/ + +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP +static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR const struct procfs_meminfo_entry_s *entry; + FAR struct meminfo_file_s *procfile; + pid_t pid = -1; + + DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0); + + /* Recover our private data from the struct file instance */ + + procfile = filep->f_priv; + DEBUGASSERT(procfile); + + switch (buffer[0]) + { + case 'u': + pid = -1; + break; + + case 'f': + pid = -2; + break; + } + + for (entry = g_procfs_meminfo; entry != NULL; entry = entry->next) + { + mm_memdump(entry->user_data, pid); + } + + return buflen; +} +#endif + /**************************************************************************** * Name: meminfo_dup * diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h index fa9e3a19e9..246a1b6186 100644 --- a/include/nuttx/mm/mm.h +++ b/include/nuttx/mm/mm.h @@ -296,6 +296,7 @@ void kmm_extend(FAR void *mem, size_t size, int region); struct mallinfo; /* Forward reference */ int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info); +void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid); /* Functions contained in kmm_mallinfo.c ************************************/ diff --git a/mm/mm_heap/Make.defs b/mm/mm_heap/Make.defs index c9c0c1c226..fdeb15dbae 100644 --- a/mm/mm_heap/Make.defs +++ b/mm/mm_heap/Make.defs @@ -25,7 +25,7 @@ ifeq ($(CONFIG_MM_DEFAULT_MANAGER),y) CSRCS += mm_initialize.c mm_sem.c mm_addfreechunk.c mm_size2ndx.c CSRCS += mm_malloc_size.c mm_shrinkchunk.c mm_brkaddr.c mm_calloc.c CSRCS += mm_extend.c mm_free.c mm_mallinfo.c mm_malloc.c mm_foreach.c -CSRCS += mm_memalign.c mm_realloc.c mm_zalloc.c mm_heapmember.c +CSRCS += mm_memalign.c mm_realloc.c mm_zalloc.c mm_heapmember.c mm_memdump.c ifeq ($(CONFIG_DEBUG_MM),y) CSRCS += mm_checkcorruption.c diff --git a/mm/mm_heap/mm_memdump.c b/mm/mm_heap/mm_memdump.c new file mode 100644 index 0000000000..b3b5a5af05 --- /dev/null +++ b/mm/mm_heap/mm_memdump.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * mm/mm_heap/mm_memdump.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "mm_heap/mm.h" + +struct memdump_info_s +{ + pid_t pid; + int blks; + int size; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void memdump_handler(FAR struct mm_allocnode_s *node, FAR void *arg) +{ + FAR struct memdump_info_s *info = arg; + + if ((node->preceding & MM_ALLOC_BIT) != 0) + { + DEBUGASSERT(node->size >= SIZEOF_MM_ALLOCNODE); + if (info->pid == -1) + { + info->blks++; + info->size += node->size; + syslog(LOG_INFO, "%12p%12" PRIu32 "\n", + ((FAR char *)node + SIZEOF_MM_ALLOCNODE), + node->size); + } + } + else + { + FAR struct mm_freenode_s *fnode = (FAR void *)node; + + DEBUGASSERT(node->size >= SIZEOF_MM_FREENODE); + DEBUGASSERT(fnode->blink->flink == fnode); + DEBUGASSERT(fnode->blink->size <= fnode->size); + DEBUGASSERT(fnode->flink == NULL || + fnode->flink->blink == fnode); + DEBUGASSERT(fnode->flink == NULL || + fnode->flink->size == 0 || + fnode->flink->size >= fnode->size); + + if (info->pid == -2) + { + info->blks++; + info->size += node->size; + syslog(LOG_INFO, "%12p%12" PRIu32 "\n", + ((FAR char *)node + SIZEOF_MM_ALLOCNODE), + node->size); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mm_memdump + * + * Description: + * mm_memdump returns a memory info about specified pid of task/thread. + * + ****************************************************************************/ + +void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid) +{ + struct memdump_info_s info; + + if (pid == -1) + { + syslog(LOG_INFO, "Dump all used memory node info:\n"); + } + else if (pid == -2) + { + syslog(LOG_INFO, "Dump all free memory node info:\n"); + } + + syslog(LOG_INFO, "%12s%12s\n", "Address", "Size"); + + info.blks = 0; + info.size = 0; + info.pid = pid; + mm_foreach(heap, memdump_handler, &info); + + syslog(LOG_INFO, "%12s%12s\n", "Total Blks", "Total Size"); + syslog(LOG_INFO, "%12d%12d\n", info.blks, info.size); +}