From 1e8eaa90c1ea7c1d5a208c804f7c2f4ec2bdc4a9 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 23 Mar 2007 16:06:22 +0000 Subject: [PATCH] Fix memory leaks git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@133 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 4 ++ Documentation/NuttX.html | 4 ++ examples/ostest/cancel.c | 30 +++++++++- examples/ostest/main.c | 121 ++++++++++++++++++++++++++++++++++++++- examples/ostest/mqueue.c | 5 +- sched/pthread_join.c | 7 +++ 6 files changed, 166 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6bacc8f7ab..b4594a56bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -72,6 +72,10 @@ 0.2.2 2007-xx-xx Gregory Nutt * Created the configs/ directory; separated board configuration from processor architecture logic + * Add memory leak detection test to examples/ostest + * Corrected memory leak in OS pthread join logic + * Corrected memory leaks in examples/ostest due to failures + to join or detach from pthreads. * Started m68322 diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 01bfbbc02c..c0b4a15067 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -433,6 +433,10 @@ Other memory: 0.2.2 2007-xx-xx Gregory Nutt * Created the configs/ directory; separated board configuration from processor architecture logic + * Add memory leak detection test to examples/ostest + * Corrected memory leak in OS pthread join logic + * Corrected memory leaks in examples/ostest due to failures + to join or detach from pthreads. * Started m68322 diff --git a/examples/ostest/cancel.c b/examples/ostest/cancel.c index 2bd08da24b..4af1b86fbe 100644 --- a/examples/ostest/cancel.c +++ b/examples/ostest/cancel.c @@ -202,7 +202,9 @@ void cancel_test(void) printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status); } - /* Then join to the thread to pick up the result */ + /* Then join to the thread to pick up the result (if we don't do + * we will have a memory leak!) + */ printf("cancel_test: Joining\n"); status = pthread_join(waiter, &result); @@ -283,7 +285,7 @@ void cancel_test(void) printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status); } - /* Signal the thread. It should wake up an restore the cancelable state. + /* Signal the thread. It should wake up and restore the cancelable state. * When the cancelable state is re-enabled, the thread should be canceled. */ @@ -304,4 +306,28 @@ void cancel_test(void) { printf("cancel_test: ERROR pthread_mutex_unlock failed, status=%d\n", status); } + + /* Then join to the thread to pick up the result (if we don't do + * we will have a memory leak!) + */ + + printf("cancel_test: Joining\n"); + status = pthread_join(waiter, &result); + if (status != 0) + { + printf("cancel_test: ERROR pthread_join failed, status=%d\n", status); + } + else + { + printf("cancel_test: waiter exited with result=%p\n", result); + if (result != PTHREAD_CANCELED) + { + printf("cancel_test: ERROR expected result=%p\n", PTHREAD_CANCELED); + } + else + { + printf("cancel_test: PASS thread terminated with PTHREAD_CANCELED\n"); + } + } + } diff --git a/examples/ostest/main.c b/examples/ostest/main.c index b4aa5deeda..c78fc0cde6 100644 --- a/examples/ostest/main.c +++ b/examples/ostest/main.c @@ -41,11 +41,13 @@ * Included Files ************************************************************/ -#include +#include #include +#include #include #include #include +#include #include "ostest.h" /************************************************************ @@ -81,10 +83,72 @@ static const char *g_argv[NARGS+1]; static const char *g_argv[NARGS+1] = { arg1, arg2, arg3, arg4, NULL }; #endif +#ifndef CONFIG_DISABLE_SIGNALS +static struct mallinfo g_mmbefore; +static struct mallinfo g_mmprevious; +static struct mallinfo g_mmafter; +#endif + /************************************************************ * Private Functions ************************************************************/ +/************************************************************ + * Name: show_memory_usage + ************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +static void show_memory_usage(struct mallinfo *mmbefore, + struct mallinfo *mmafter) +{ + printf("VARIABLE BEFORE AFTER\n"); + printf("======== ======== ========\n"); + printf("arena %8x %8x\n", mmbefore->arena, mmafter->arena); + printf("ordblks %8d %8d\n", mmbefore->ordblks, mmafter->ordblks); + printf("mxordblk %8x %8x\n", mmbefore->mxordblk, mmafter->mxordblk); + printf("uordblks %8x %8x\n", mmbefore->uordblks, mmafter->uordblks); + printf("fordblks %8x %8x\n", mmbefore->fordblks, mmafter->fordblks); +} +#else +# define show_memory_usage(mm1, mm2) +#endif + +/************************************************************ + * Name: check_test_memory_usage + ************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +static void check_test_memory_usage(void) +{ + /* Wait a little bit to let any threads terminate */ + + usleep(500*1000); + + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + + /* Show the change from the previous time */ + + printf("\nEnd of test memory usage:\n"); + show_memory_usage(&g_mmprevious, &g_mmafter); + + /* Set up for the next test */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmprevious = g_mmafter; +#else + memcpy(&g_mmprevious, &g_mmafter, sizeof(struct mallinfo)); +#endif +} +#else +# define check_test_memory_usage() +#endif + /************************************************************ * Name: user_main ************************************************************/ @@ -93,6 +157,21 @@ static int user_main(int argc, char *argv[]) { int i; + /* Sample the memory usage now */ + +#ifndef CONFIG_DISABLE_SIGNALS + usleep(500*1000); + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmbefore = mallinfo(); + g_mmprevious = g_mmbefore; +#else + (void)mallinfo(&g_mmbefore); + memcpy(g_mmprevious, g_mmbefore, sizeof(struct mallinfo)); +#endif +#endif + + printf("\nuser_main: Begin argument test\n"); printf("user_main: Started with argc=%d\n", argc); /* Verify passed arguments */ @@ -116,65 +195,105 @@ static int user_main(int argc, char *argv[]) i, g_argv[i-1], argv[i]); } } + check_test_memory_usage(); #if CONFIG_NFILE_DESCRIPTORS > 0 /* Checkout /dev/null */ + printf("\nuser_main: /dev/null test\n"); dev_null(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_PTHREAD /* Verify pthreads and pthread mutex */ + printf("\nuser_main: mutex test\n"); mutex_test(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_PTHREAD /* Verify pthread cancellation */ + printf("\nuser_main: cancel test\n"); cancel_test(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_PTHREAD /* Verify pthreads and semaphores */ + printf("\nuser_main: semaphore test\n"); sem_test(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_PTHREAD /* Verify pthreads and condition variables */ + printf("\nuser_main: condition variable test\n"); cond_test(); + check_test_memory_usage(); #endif #if !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) /* Verify pthreads and condition variable timed waits */ + printf("\nuser_main: timed wait test\n"); timedwait_test(); + check_test_memory_usage(); #endif #if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD) /* Verify pthreads and message queues */ + printf("\nuser_main: message queue test\n"); mqueue_test(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_SIGNALS /* Verify signal handlers */ + printf("\nuser_main: signal handler test\n"); sighand_test(); + check_test_memory_usage(); #endif #if !defined(CONFIG_DISABLE_POSIX_TIMERS) && !defined(CONFIG_DISABLE_SIGNALS) /* Verify posix timers */ + printf("\nuser_main: POSIX timer test\n"); timer_test(); + check_test_memory_usage(); #endif #if !defined(CONFIG_DISABLE_PTHREAD) && CONFIG_RR_INTERVAL > 0 /* Verify round robin scheduling */ + printf("\nuser_main: round-robin scheduler test\n"); rr_test(); + check_test_memory_usage(); +#endif + + /* Compare memory usage at time user_start started until + * user_main exits. These should not be identical, but should + * be similar enough that we can detect any serious OS memory + * leaks. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + usleep(500*1000); + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + + printf("\nFinal memory usage:\n"); + show_memory_usage(&g_mmbefore, &g_mmafter); #endif printf("user_main: Exitting\n"); diff --git a/examples/ostest/mqueue.c b/examples/ostest/mqueue.c index 3ad68459cc..00b17e124e 100644 --- a/examples/ostest/mqueue.c +++ b/examples/ostest/mqueue.c @@ -236,8 +236,6 @@ static void *receiver_thread(void *arg) nerrors++; } - pthread_exit((pthread_addr_t)nerrors); - /* Destroy the queue */ if (mq_unlink("testmq") < 0) @@ -247,6 +245,7 @@ static void *receiver_thread(void *arg) } printf("receiver_thread: returning nerrors=%d\n", nerrors); + pthread_exit((pthread_addr_t)nerrors); return (pthread_addr_t)nerrors; } @@ -330,12 +329,14 @@ void mqueue_test(void) printf("mqueue_test: pthread_create failed, status=%d\n", status); } + printf("mqueue_test: Waiting for sender to complete\n"); pthread_join(sender, &result); if (result != (void*)0) { printf("mqueue_test: ERROR sender thread exited with %d errors\n", (int)result); } + printf("mqueue_test: Canceling receiver\n"); pthread_cancel(receiver); pthread_join(receiver, &result); if (result != (void*)0) diff --git a/sched/pthread_join.c b/sched/pthread_join.c index 2754a35fe6..3819c1fa37 100644 --- a/sched/pthread_join.c +++ b/sched/pthread_join.c @@ -195,6 +195,10 @@ int pthread_join(pthread_t thread, pthread_addr_t *pexit_value) dbg("exit_value=0x%p\n", pjoin->exit_value); } + /* Then remove the thread entry. */ + + (void)pthread_removejoininfo((pid_t)thread); + /* Post the thread's join semaphore so that exitting thread * will know that we have received the data. */ @@ -205,6 +209,9 @@ int pthread_join(pthread_t thread, pthread_addr_t *pexit_value) sched_unlock(); + /* Deallocate the thread entry */ + + sched_free(pjoin); ret = OK; }