diff --git a/ChangeLog b/ChangeLog index 76f4f2c97881622793088168f1635182ca1d9721..e4f09183b1eb35ca7e02cac668a08a43b0c81b2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1548,7 +1548,7 @@ * sched/atexit.c and sched/exit.c: The atexit function is not frequently used. In order to save a few bytes, it is now conditioned on CONFIG_SCHED_ATEXIT. It your application is currently using atexit(), - you will need to add CONFIG_SCHED_ATEXT to your configuration file. + you will need to add CONFIG_SCHED_ATEXIT to your configuration file. * drivers/net/slip.c: Add a SLIP driver (untested on initial check-in). * configs/olimex-lpc1766stk/slip-httpd: An example that uses SLIP to provide a serial-port based THTTPD web server. @@ -1770,7 +1770,22 @@ the MPLAB debugger on PIC32; I will need to get a PICkit 3). * drivers/net/e1000.c/h: A PCI-based E1000 ethernet driver submitted by Yu Qiang. - * lib/net/lib_inetaddr.c: An implementatino of the inet_addr() function - submitted y Yu Qiang. + * lib/net/lib_inetaddr.c: An implementation of the inet_addr() function + submitted by Yu Qiang. * arch/arm/src/lpc31xx and arch/arm/include/lpc31xx: Renamed from lpc313x to make name space for other famiy members. + * arch/arm/*/lpc31xx: Added support for the LPC315x family (untested). + * sched/task_exithook.c: Functionality performed when a task exits or is + deleted has been moved to a common file task_exithook.c. Now exit() + functionality (like flushing I/O and calling registered atexit() + functions, etc.) will be performed when a task is deleted as well. + * mm/: Added support for CONFIG_MM_SMALL. Each memory allocation has a + small allocation overhead. The size of that overhead is normally + determined by the "width" of the address support by the MCU. MCUs + that support 16-bit addressability have smaller overhead than devices + that support 32-bit addressability. However, there are many MCUs + that support 32-bit addressability *but* have internal SRAM of size + less than or equal to 64Kb. In this case, CONFIG_MM_SMALL can be + defined so that those MCUs will also benefit from the smaller, 16- + bit-based allocation overhead. + diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index b29bf7ab0ac7f86dbf118babacc47a7af8515758..84548e10dbcdc1437d4d491ee6f8ca77ee4b5cd2 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@ <tr align="center" bgcolor="#e4e4e4"> <td> <h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1> - <p>Last Updated: May 25, 2011</p> + <p>Last Updated: May 28, 2011</p> </td> </tr> </table> @@ -2313,8 +2313,24 @@ nuttx-6.4 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> the MPLAB debugger on PIC32; I will need to get a PICkit 3). * drivers/net/e1000.c/h: A PCI-based E1000 ethernet driver submitted by Yu Qiang. - * lib/net/lib_inetaddr.c: An implementatino of the inet_addr() function - submitted y Yu Qiang. + * lib/net/lib_inetaddr.c: An implementation of the inet_addr() function + submitted by Yu Qiang. + * arch/arm/src/lpc31xx and arch/arm/include/lpc31xx: Renamed from lpc313x + to make name space for other famiy members. + * arch/arm/*/lpc31xx: Added support for the LPC315x family (untested). + * sched/task_exithook.c: Functionality performed when a task exits or is + deleted has been moved to a common file task_exithook.c. Now exit() + functionality (like flushing I/O and calling registered atexit() + functions, etc.) will be performed when a task is deleted as well. + * mm/: Added support for CONFIG_MM_SMALL. Each memory allocation has a + small allocation overhead. The size of that overhead is normally + determined by the "width" of the address support by the MCU. MCUs + that support 16-bit addressability have smaller overhead than devices + that support 32-bit addressability. However, there are many MCUs + that support 32-bit addressability *but* have internal SRAM of size + less than or equal to 64Kb. In this case, CONFIG_MM_SMALL can be + defined so that those MCUs will also benefit from the smaller, 16- + bit-based allocation overhead. apps-6.4 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html index fb06f794ee538b2356819622e72c6fd786884ab7..faa9f32cf406dae3f25601f6c6dde3fdeb7c1f0a 100644 --- a/Documentation/NuttxPortingGuide.html +++ b/Documentation/NuttxPortingGuide.html @@ -12,7 +12,7 @@ <h1><big><font color="#3c34ec"> <i>NuttX RTOS Porting Guide</i> </font></big></h1> - <p>Last Updated: May 25, 2011</p> + <p>Last Updated: May 28, 2011</p> </td> </tr> </table> @@ -3262,6 +3262,17 @@ build number of memory regions that the memory manager must handle and enables the API mm_addregion(start, end); </li> + <li> + <code>CONFIG_MM_SMALL</code>: Each memory allocation has a small allocation + overhead. The size of that overhead is normally determined by + the "width" of the address support by the MCU. MCUs that support + 16-bit addressability have smaller overhead than devices that + support 32-bit addressability. However, there are many MCUs + that support 32-bit addressability <i>but</i> have internal SRAM + of size less than or equal to 64Kb. In this case, CONFIG_MM_SMALL + can be defined so that those MCUs will also benefit from the + smaller, 16-bit-based allocation overhead. + </li> <li> <code>CONFIG_MSEC_PER_TICK</code>: The default system timer is 100Hz or <code>MSEC_PER_TICK</code>=10. This setting may be defined to inform NuttX diff --git a/TODO b/TODO index 25722f3f07c007c042f1285364d27d45a9a614aa..553c79ec252fe0033feaaa4b9b03b6b5f8e12aed 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,11 @@ -NuttX TODO List (Last updated May 14, 2011) +NuttX TODO List (Last updated May 28, 2011) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ nuttx/ (5) Task/Scheduler (sched/) (1) On-demand paging (sched/) - (2) Memory Managment (mm/) + (1) Memory Managment (mm/) (1) Signals (sched/, arch/) (1) pthreads (sched/) (1) C++ Support @@ -40,7 +40,7 @@ nuttx/ apps/ (5) Network Utilities (apps/netutils/) - (4) NuttShell (NSH) (apps/nshlib) + (5) NuttShell (NSH) (apps/nshlib) (3) Other Applications & Tests (apps/examples/) o Task/Scheduler (sched/) @@ -51,13 +51,12 @@ o Task/Scheduler (sched/) Status: Open Priority: Medium, required for good emulation of process/pthread model. - Description: atexit() supports registration of one function called on exit(). - Should task_delete() also cause atexit() function to be called? - Update: atexit() is only built into the system if CONFIG_SCHED_ATEXT - is defined in the configuration. + Description: atexit() supports registration of only single function called on + exit(). It should support multiple functions registered by atexit() + or onexit() and these should be called in reverse order of + registration when the task exits. Status: Open - Priority: Low, task_delete() is non-standard and its behavior is - unspecified. + Priority: Low Description: Implement sys/mman.h and functions Status: Open @@ -121,13 +120,6 @@ o Memory Managment (mm/) Priority: Medium/Low, a good feature to prevent memory leaks but would have negative impact on memory usage and code size. - Description: Current logic adapts size_t for 16-bit address machines vs. - 32-bit address machines. But a small memory option should also - be provided so that the small offset option can be used with - 32-bit machines that have small RAM memories (like the lpc2148) - Status: Open - Priority: High, a good feature enhancement. - o Signals (sched/, arch/) ^^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +321,7 @@ o Network (net/, drivers/net) Description: The interfaces used to leave/join IGMP multicast groups is non-standard. RFC3678 (IGMPv3) suggests ioctl() commands to do this (SIOCSIPMSFILTER) but also status that those APIs are historic. NuttX implements these ioctl - commnands, but is non-standard because: (1) It does not support IGMPv3, and + commands, but is non-standard because: (1) It does not support IGMPv3, and (2) it looks up drivers by their device name (eg., "eth0") vs IP address. Linux uses setsockopt() to control multicast group membership using the @@ -1196,6 +1188,13 @@ o NuttShell (NSH) (apps/nshlib) Status: Open Priority: Med-High + Descripton: The ifconfig command will not behave correctly is an interface + is provided and there are multiple interfaces. It should only + show status for the single interface on the command line; it will + still show status for all interfaces. + Status: Open + Priority: Low (multiple network interfaces not fully supported yet anyway). + Description: Add support to NSH to run NXFLAT programs from a ROMFS file system Status: Open Priority: Low (enhancement) diff --git a/arch/sim/src/up_allocateheap.c b/arch/sim/src/up_allocateheap.c index 9278faf2725e5b4330987a0f22eb2b1f702c9d88..f02f8cbfa0afa2d0675e16ff436efeb5a21a8ad0 100644 --- a/arch/sim/src/up_allocateheap.c +++ b/arch/sim/src/up_allocateheap.c @@ -81,5 +81,5 @@ static uint8_t sim_heap[SIM_HEAP_SIZE]; void up_allocate_heap(void **heap_start, size_t *heap_size) { *heap_start = sim_heap; - *heap_size = SIM_HEAP_SIZE; + *heap_size = SIM_HEAP_SIZE; } diff --git a/arch/sim/src/up_internal.h b/arch/sim/src/up_internal.h index 7f241e48e3c94ecfe6617f88b41b6139946f12e0..094776390fad89baeea508f55b1927b566780965 100644 --- a/arch/sim/src/up_internal.h +++ b/arch/sim/src/up_internal.h @@ -40,6 +40,7 @@ * Included Files **************************************************************************/ +#include <nuttx/config.h> #include <sys/types.h> #include <nuttx/irq.h> @@ -64,7 +65,13 @@ # define JB_PC (5) #endif /* __ASSEMBLY__ */ -#define SIM_HEAP_SIZE (4*1024*1024) +/* Size of the simulated heap */ + +#if CONFIG_MM_SMALL +# define SIM_HEAP_SIZE (64*1024) +#else +# define SIM_HEAP_SIZE (4*1024*1024) +#endif /* These definitions characterize the compressed filesystem image */ diff --git a/configs/README.txt b/configs/README.txt index d00fe1e2020a73efed13288ed443d14aa931d3a0..509e57281ab196fff82c95cd1416929a4b8c21b9 100644 --- a/configs/README.txt +++ b/configs/README.txt @@ -261,6 +261,15 @@ defconfig -- This is a configuration file similar to the Linux regions of memory to allocate from, this specifies the number of memory regions that the memory manager must handle and enables the API mm_addregion(start, end); + CONFIG_MM_SMALL - Each memory allocation has a small allocation + overhead. The size of that overhead is normally determined by + the "width" of the address support by the MCU. MCUs that support + 16-bit addressability have smaller overhead than devices that + support 32-bit addressability. However, there are many MCUs + that support 32-bit addressability *but* have internal SRAM + of size less than or equal to 64Kb. In this case, CONFIG_MM_SMALL + can be defined so that those MCUs will also benefit from the + smaller, 16-bit-based allocation overhead. CONFIG_MSEC_PER_TICK - The default system timer is 100Hz or MSEC_PER_TICK=10. This setting may be defined to inform NuttX that the processor hardware is providing diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 78e6f6b378af296ebbf98c076111e981ce9a4cb8..8256c2d8c878a777cbec1e9bd09903c86c43ca37 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -137,7 +137,7 @@ typedef union entry_u entry_t; * (if registered via atexit()). */ -#ifdef CONFIG_SCHED_ATEXT +#ifdef CONFIG_SCHED_ATEXIT typedef void (*exitfunc_t)(void); #endif @@ -184,7 +184,7 @@ struct _TCB pid_t pid; /* This is the ID of the thread */ start_t start; /* Thread start function */ entry_t entry; /* Entry Point into the thread */ -#ifdef CONFIG_SCHED_ATEXT +#ifdef CONFIG_SCHED_ATEXIT exitfunc_t exitfunc; /* Called if exit is called. */ #endif #ifdef CONFIG_SCHED_WAITPID /* Experimental */ diff --git a/mm/mm_environment.h b/mm/mm_environment.h index 3525eccc06797c1aaa37e2eb5b61e05b17bcb869..ef4f14f7a4e627229c37bbd72ee07b4593eff8b8 100644 --- a/mm/mm_environment.h +++ b/mm/mm_environment.h @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_environment.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> * * Redistribution and use in source and binary forms, with or without @@ -76,6 +76,7 @@ # define FAR /* Normally in compiler.h */ # define CONFIG_CPP_HAVE_VARARGS 1 /* Normally in compiler.h */ # define CONFIG_MM_REGIONS 2 /* Normally in config.h */ +# undef CONFIG_MM_SMALL /* Normally in config.h */ # define CONFIG_CAN_PASS_STRUCTS 1 /* Normally in config.h */ # undef CONFIG_SMALL_MEMORY /* Normally in config.h */ diff --git a/mm/mm_initialize.c b/mm/mm_initialize.c index 9a580cd894c3fc580ce0c444b4f950cd631b73bb..351948c2fad7227c6379ffd38d5e15cfdd6c71a1 100644 --- a/mm/mm_initialize.c +++ b/mm/mm_initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_initialize.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> * * Redistribution and use in source and binary forms, with or without @@ -124,7 +124,7 @@ void mm_initialize(FAR void *heapstart, size_t heapsize) } /* Initialize the malloc semaphore to one (to support one-at- - * a-time access to private data sets. + * a-time access to private data sets). */ mm_seminitialize(); @@ -155,20 +155,29 @@ void mm_initialize(FAR void *heapstart, size_t heapsize) void mm_addregion(FAR void *heapstart, size_t heapsize) { FAR struct mm_freenode_s *node; - size_t heapbase; - size_t heapend; + uintptr_t heapbase; + uintptr_t heapend; #if CONFIG_MM_REGIONS > 1 int IDX = g_nregions; #else # define IDX 0 #endif + /* If the MCU handles wide addresses but the memory manager + * is configured for a small heap, then verify that the caller + * not doing something crazy. + */ + +#if defined(CONFIG_MM_SMALL) && !defined(CONFIG_SMALL_MEMORY) + DEBUGASSERT(heapsize <= MMSIZE_MAX+1); +#endif + /* Adjust the provide heap start and size so that they are * both aligned with the MM_MIN_CHUNK size. */ - heapbase = MM_ALIGN_UP((size_t)heapstart); - heapend = MM_ALIGN_DOWN((size_t)heapstart + (size_t)heapsize); + heapbase = MM_ALIGN_UP((uintptr_t)heapstart); + heapend = MM_ALIGN_DOWN((uintptr_t)heapstart + (uintptr_t)heapsize); heapsize = heapend - heapbase; mlldbg("Region %d: base=%p size=%u\n", IDX+1, heapstart, heapsize); diff --git a/mm/mm_internal.h b/mm/mm_internal.h index 0649122a2fb2321adf2a9a0871c56b5d47065816..42955932870e9af6b0d1004bedf041435d6fbf1e 100644 --- a/mm/mm_internal.h +++ b/mm/mm_internal.h @@ -1,7 +1,7 @@ /************************************************************************ * mm/mm_internal.h * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,24 @@ /************************************************************************ * Pre-processor Definitions ************************************************************************/ +/* Configuration ********************************************************/ +/* If the MCU has a small (16-bit) address capability, then we will use + * a smaller chunk header that contains 16-bit size/offset information. + * We will also use the smaller header on MCUs with wider addresses if + * CONFIG_MM_SMALL is selected. This configuration is common with MCUs + * that have a large FLASH space, but only a tiny internal SRAM. + */ + +#ifdef CONFIG_SMALL_MEMORY + /* If the MCU has a small addressing capability, then for the smaller + * chunk header. + */ + +# undef CONFIG_MM_SMALL +# define CONFIG_MM_SMALL 1 +#endif +/* Chunk Header Definitions *********************************************/ /* These definitions define the characteristics of allocator * * MM_MIN_SHIFT is used to define MM_MIN_CHUNK. @@ -61,7 +78,7 @@ * losses. */ -#ifdef CONFIG_SMALL_MEMORY +#ifdef CONFIG_MM_SMALL # define MM_MIN_SHIFT 4 /* 16 bytes */ # define MM_MAX_SHIFT 15 /* 32 Kb */ #else @@ -84,7 +101,7 @@ * an allocated chunk. */ -#ifdef CONFIG_SMALL_MEMORY +#ifdef CONFIG_MM_SMALL # define MM_ALLOC_BIT 0x8000 #else # define MM_ALLOC_BIT 0x80000000 @@ -96,18 +113,30 @@ * Public Types ************************************************************************/ +/* Determine the size of the chunk size/offset type */ + +#ifdef CONFIG_MM_SMALL + typedef uint16_t mmsize_t; +# define MMSIZE_MAX 0xffff +#else + typedef size_t mmsize_t; +# define MMSIZE_MAX SIZE_MAX +#endif + /* This describes an allocated chunk. An allocated chunk is - * distinguished from a free chunk by bit 31 of the 'precding' - * chunk size. If set, then this is an allocated chunk. + * distinguished from a free chunk by bit 15/31 of the 'preceding' chunk + * size. If set, then this is an allocated chunk. */ struct mm_allocnode_s { - size_t size; /* Size of this chunk */ - size_t preceding; /* Size of the preceding chunk */ + mmsize_t size; /* Size of this chunk */ + mmsize_t preceding; /* Size of the preceding chunk */ }; -#ifdef CONFIG_SMALL_MEMORY +/* What is the size of the allocnode? */ + +#ifdef CONFIG_MM_SMALL # define SIZEOF_MM_ALLOCNODE 4 #else # define SIZEOF_MM_ALLOCNODE 8 @@ -120,18 +149,25 @@ struct mm_allocnode_s struct mm_freenode_s { - size_t size; /* Size of this chunk */ - size_t preceding; /* Size of the preceding chunk */ + mmsize_t size; /* Size of this chunk */ + mmsize_t preceding; /* Size of the preceding chunk */ FAR struct mm_freenode_s *flink; /* Supports a doubly linked list */ FAR struct mm_freenode_s *blink; }; -#ifdef CONFIG_SMALL_MEMORY -# define SIZEOF_MM_FREENODE 8 +/* Free is the size of the freenode */ + +#ifdef CONFIG_MM_SMALL +# ifdef CONFIG_SMALL_MEMORY +# define SIZEOF_MM_FREENODE 8 +# else +# define SIZEOF_MM_FREENODE 12 +# endif #else -# define SIZEOF_MM_FREENODE 16 +# define SIZEOF_MM_FREENODE 16 #endif -#define CHECK_FREENODE_SIZE \ + +#define CHECK_FREENODE_SIZE \ DEBUGASSERT(sizeof(struct mm_freenode_s) == SIZEOF_MM_FREENODE) /* Normally defined in stdlib.h */ diff --git a/mm/mm_malloc.c b/mm/mm_malloc.c index 5d5257716ae9a52e358a236471cf405d9cf6aceb..dbcba33a836469fc103948f38beef64a3267cc36 100644 --- a/mm/mm_malloc.c +++ b/mm/mm_malloc.c @@ -199,6 +199,6 @@ FAR void *malloc(size_t size) } mm_givesemaphore(); - mvdbg("Allocated %p\n", ret); + mvdbg("Allocated %p, size %d\n", ret, size); return ret; } diff --git a/mm/mm_memalign.c b/mm/mm_memalign.c index a4d9cabd59b94d869c1376a0331ddfe68c0caacc..d40f723488ab33e936bc65c0f524298dc84bc934 100644 --- a/mm/mm_memalign.c +++ b/mm/mm_memalign.c @@ -94,7 +94,7 @@ FAR void *memalign(size_t alignment, size_t size) * The do not include SIZEOF_MM_ALLOCNODE. */ - size = MM_ALIGN_UP(size); /* Make mutliples of our granule size */ + size = MM_ALIGN_UP(size); /* Make multiples of our granule size */ allocsize = size + 2*alignment; /* Add double full alignment size */ /* Then malloc that size */ diff --git a/mm/mm_test.c b/mm/mm_test.c index 48f380221e2f0e30fcd4e9caa0dda233c8b96695..e7a44dec769f981e85c99a647c2f971481b6b809 100644 --- a/mm/mm_test.c +++ b/mm/mm_test.c @@ -41,6 +41,7 @@ #define FAR #define CONFIG_MM_REGIONS 2 +#undef CONFIG_MM_SMALL #define CONFIG_CAN_PASS_STRUCTS 1 #undef CONFIG_SMALL_MEMORY diff --git a/sched/Makefile b/sched/Makefile index 859bd57b4cbfd88bd349980bf55206d36c8a5c88..9ea7ca1bae64e35d094cff38b95d1a501cd7b760 100644 --- a/sched/Makefile +++ b/sched/Makefile @@ -44,11 +44,11 @@ MISC_SRCS = os_start.c os_bringup.c errno_getptr.c errno_get.c errno_set.c \ sched_setuppthreadfiles.c sched_releasefiles.c TSK_SRCS = task_create.c task_init.c task_setup.c task_activate.c \ - task_start.c task_delete.c task_deletecurrent.c task_restart.c \ - exit.c atexit.c getpid.c sched_addreadytorun.c sched_removereadytorun.c \ - sched_addprioritized.c sched_mergepending.c sched_addblocked.c \ - sched_removeblocked.c sched_free.c sched_gettcb.c sched_verifytcb.c \ - sched_releasetcb.c + task_start.c task_delete.c task_deletecurrent.c task_exithook.c \ + task_restart.c exit.c atexit.c getpid.c sched_addreadytorun.c \ + sched_removereadytorun.c sched_addprioritized.c sched_mergepending.c \ + sched_addblocked.c sched_removeblocked.c sched_free.c sched_gettcb.c \ + sched_verifytcb.c sched_releasetcb.c SCHED_SRCS = sched_setparam.c sched_setpriority.c sched_getparam.c \ sched_setscheduler.c sched_getscheduler.c \ diff --git a/sched/exit.c b/sched/exit.c index 6793eae77a166382172bec7f63efda722765f18c..2964b5a01dda49efddcb9b030c17e920212b8a0f 100644 --- a/sched/exit.c +++ b/sched/exit.c @@ -67,7 +67,7 @@ ****************************************************************************/ /**************************************************************************** - * Private Functionss + * Private Functions ****************************************************************************/ /**************************************************************************** @@ -78,68 +78,29 @@ * Function: exit * * Description: - * The exit() function causes normal process termination - * and the value of status & 0377 is returned to the parent. + * The exit() function causes normal process termination and the value of + * status & 0377 to be returned to the parent. * - * All functions registered with atexit() and on_exit() are - * called, in the reverse order of their registration. + * All functions registered with atexit() and on_exit() are called, in the + * reverse order of their registration. * - * All open streams are flushed and closed. Files created - * by tmpfile() are removed. + * All open streams are flushed and closed. * ****************************************************************************/ void exit(int status) { -#if CONFIG_NFILE_STREAMS > 0 || defined(CONFIG_SCHED_WAITPID) || defined(CONFIG_SCHED_ATEXIT) _TCB *tcb = (_TCB*)g_readytorun.head; -#endif - /* Only the lower 8 bits of the exit status are used */ + /* Only the lower 8-bits of status are used */ status &= 0xff; - /* Flush all streams (File descriptors will be closed when - * the TCB is deallocated. - */ + /* Perform common task termination logic */ -#if CONFIG_NFILE_STREAMS > 0 - (void)lib_flushall(tcb->streams); -#endif + task_exithook(tcb, status); - /* Wakeup any tasks waiting for this task to exit */ - -#ifdef CONFIG_SCHED_WAITPID /* Experimental */ - while (tcb->exitsem.semcount < 0) - { - /* "If more than one thread is suspended in waitpid() awaiting - * termination of the same process, exactly one thread will return - * the process status at the time of the target process termination." - * Hmmm.. what do we return to the others? - */ - - if (tcb->stat_loc) - { - *tcb->stat_loc = status << 8; - tcb->stat_loc = NULL; - } - - /* Wake up the thread */ - - sem_post(&tcb->exitsem); - } -#endif - - /* If an exit function was registered, call it now. */ - -#ifdef CONFIG_SCHED_ATEXIT - if (tcb->exitfunc) - { - (*tcb->exitfunc)(); - } -#endif - - /* Then "really" exit */ + /* Then "really" exit. Only the lower 8 bits of the exit status are used. */ _exit(status); } diff --git a/sched/os_internal.h b/sched/os_internal.h index b25ee1c5e59a39c57007ed0cf048800a87565036..3287507a967db3b039852615a53f4a2c458d09b0 100644 --- a/sched/os_internal.h +++ b/sched/os_internal.h @@ -265,6 +265,7 @@ extern void task_start(void); extern int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main); extern int task_argsetup(FAR _TCB *tcb, const char *name, const char *argv[]); +extern void task_exithook(FAR _TCB *tcb, int status); extern int task_deletecurrent(void); #ifndef CONFIG_CUSTOM_STACK extern int kernel_thread(const char *name, int priority, diff --git a/sched/task_delete.c b/sched/task_delete.c index 4fd49a4ea4002afed989d34096e2a7f985bae76c..51b3e30da1c440d3c86613b8c82a6920f3ae7d9b 100644 --- a/sched/task_delete.c +++ b/sched/task_delete.c @@ -140,14 +140,9 @@ int task_delete(pid_t pid) PANIC(OSERR_BADDELETESTATE); } - saved_state = irqsave(); - - /* Inform the instrumentation layer that the task has stopped */ - - sched_note_stop(dtcb); - /* Remove the task from the OS's tasks lists. */ + saved_state = irqsave(); dq_rem((FAR dq_entry_t*)dtcb, (dq_queue_t*)g_tasklisttable[dtcb->task_state].list); dtcb->task_state = TSTATE_TASK_INVALID; irqrestore(saved_state); @@ -156,11 +151,12 @@ int task_delete(pid_t pid) sched_unlock(); - /* Deallocate anything left in the TCB's queues */ + /* Perform common task termination logic (flushing streams, calling + * functions registered by at_exit/on_exit, etc.). I suppose EXIT_SUCCESS + * is an appropriate return value??? + */ -#ifndef CONFIG_DISABLE_SIGNALS - sig_cleanup(dtcb); /* Deallocate Signal lists */ -#endif + task_exithook(dtcb, EXIT_SUCCESS); /* Deallocate its TCB */ diff --git a/sched/task_exithook.c b/sched/task_exithook.c new file mode 100644 index 0000000000000000000000000000000000000000..9567f48a9f7b11d5723be6b4993591a9474a2f25 --- /dev/null +++ b/sched/task_exithook.c @@ -0,0 +1,157 @@ +/**************************************************************************** + * sched/task_exithook.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 <nuttx/config.h> + +#include <stdlib.h> +#include <unistd.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/fs.h> + +#include "os_internal.h" +#include "sig_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: task_hook + * + * Description: + * This function implements some of the internal logic of exit() and + * task_delete(). This function performs some cleanup and other actions + * required when a task exists: + * + * - All open streams are flushed and closed. + * - All functions registered with atexit() and on_exit() are called, in + * the reverse order of their registration. + * + * When called from exit(), the tcb still resides at the head of the ready- + * to-run list. The following logic is safe because we will not be + * returning from the exit() call. + * + * When called from task_delete() we are operating on a different thread; + * on the thread that called task_delete(). In this case, task_delete + * will have already removed the tcb from the ready-to-run list to prevent + * any further action on this task. + * + ****************************************************************************/ + +void task_exithook(FAR _TCB *tcb, int status) +{ + /* Inform the instrumentation layer that the task has stopped */ + + sched_note_stop(tcb); + + /* Flush all streams (File descriptors will be closed when + * the TCB is deallocated). + */ + +#if CONFIG_NFILE_STREAMS > 0 + (void)lib_flushall(tcb->streams); +#endif + + /* Deallocate anything left in the TCB's queues */ + +#ifndef CONFIG_DISABLE_SIGNALS + sig_cleanup(tcb); /* Deallocate Signal lists */ +#endif + + /* Wakeup any tasks waiting for this task to exit */ + +#ifdef CONFIG_SCHED_WAITPID /* Experimental */ + while (tcb->exitsem.semcount < 0) + { + /* "If more than one thread is suspended in waitpid() awaiting + * termination of the same process, exactly one thread will return + * the process status at the time of the target process termination." + * Hmmm.. what do we return to the others? + */ + + if (tcb->stat_loc) + { + *tcb->stat_loc = status << 8; + tcb->stat_loc = NULL; + } + + /* Wake up the thread */ + + sem_post(&tcb->exitsem); + } +#endif + + /* If an exit function was registered, call it now. NOTE: In the case + * of task_delete(), the exit function will *not* be called on the thread + * execution of the task being deleted! + */ + +#ifdef CONFIG_SCHED_ATEXIT + if (tcb->exitfunc) + { + (*tcb->exitfunc)(); + } +#endif +}