Add memory debug support to THTTPD

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2033 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-09-11 15:15:35 +00:00
parent 27ba470482
commit 3ae6193334
10 changed files with 317 additions and 95 deletions

View File

@ -34,5 +34,5 @@
############################################################################
THTTPD_ASRCS =
THTTPD_CSRCS = thttpd.c libhttpd.c timers.c fdwatch.c tdate_parse.c
THTTPD_CSRCS = thttpd.c libhttpd.c httpd_alloc.c timers.c fdwatch.c tdate_parse.c

View File

@ -499,7 +499,6 @@ static void do_echo(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
char *cp;
time_t t;
/* Prints the value of one of the include variables. Any dates are
* printed subject to the currently configured g_timeformat. The only valid
@ -550,7 +549,7 @@ static void do_echo(FILE *instream, char *vfilename, char *filename,
/* Same as DATE_LOCAL but in Greenwich mean time. */
gettimeofday(&tm, NULL);
show_time(t, 1);
show_time(tm.tv_sec, 1);
}
else if (strcmp(val, "LAST_MODIFIED") == 0)
{

View File

@ -200,6 +200,12 @@
# define CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC 300
# endif
/* Memory debug instrumentation depends on other debug options */
#if (!defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET)) && defined(CONFIG_THTTPD_MEMDEBUG)
# undef CONFIG_THTTPD_MEMDEBUG
#endif
/* Tilde mapping. Many URLs use ~username to indicate a user's home directory. thttpd
* provides two options for mapping this construct to an actual filename.
*

View File

@ -47,6 +47,7 @@
#include <debug.h>
#include "config.h"
#include "httpd_alloc.h"
#include "fdwatch.h"
#ifdef CONFIG_THTTPD
@ -140,19 +141,19 @@ struct fdwatch_s *fdwatch_initialize(int nfds)
fw->nfds = nfds;
fw->client = (void**)malloc(sizeof(void*) * nfds);
fw->client = (void**)httpd_malloc(sizeof(void*) * nfds);
if (!fw->client)
{
goto errout_with_allocations;
}
fw->pollfds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds);
fw->pollfds = (struct pollfd*)httpd_malloc(sizeof(struct pollfd) * nfds);
if (!fw->pollfds)
{
goto errout_with_allocations;
}
fw->ready = (uint8*)malloc(sizeof(uint8) * nfds);
fw->ready = (uint8*)httpd_malloc(sizeof(uint8) * nfds);
if (!fw->ready)
{
goto errout_with_allocations;
@ -175,20 +176,20 @@ void fdwatch_uninitialize(struct fdwatch_s *fw)
fdwatch_dump("Uninitializing:", fw);
if (fw->client)
{
free(fw->client);
httpd_free(fw->client);
}
if (fw->pollfds)
{
free(fw->pollfds);
httpd_free(fw->pollfds);
}
if (fw->ready)
{
free(fw->ready);
httpd_free(fw->ready);
}
free(fw);
httpd_free(fw);
}
}

188
netutils/thttpd/httpd_alloc.c Executable file
View File

@ -0,0 +1,188 @@
/****************************************************************************
* netutils/thttpd/httpd_alloc.c
*
* Copyright (C) 2009 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 <sys/types.h>
#include <stdlib.h>
#include <debug.h>
#include <errno.h>
#include "config.h"
#include "httpd_alloc.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/****************************************************************************
* Private Data
****************************************************************************/
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
static int g_nallocations = 0;
static size_t g_allocated = 0;
#endif
/****************************************************************************
* Global Functions
****************************************************************************/
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
FAR void *httpd_malloc(size_t nbytes)
{
void *ptr = malloc(nbytes);
if (!ptr)
{
ndbg("Allocation of %d bytes failed\n", nbytes);
}
else
{
#ifdef CONFIG_THTTPD_MEMDEBUG
nvdbg("Allocated %d bytes at %p\n", nbytes, ptr);
#endif
g_nallocations++;
g_allocated += nbytes;
}
#ifdef CONFIG_THTTPD_MEMDEBUG
httpd_memstats();
#endif
return ptr;
}
#endif
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize)
{
void *ptr = realloc(oldptr, newsize);
if (!ptr)
{
ndbg("Re-allocation from %d to %d bytes failed\n",
oldsize, newsize);
}
else
{
#ifdef CONFIG_THTTPD_MEMDEBUG
nvdbg("Re-allocated form %d to %d bytes (from %p to %p)\n",
oldsize, newsize, oldptr, ptr);
#endif
g_allocated += (newsize - oldsize);
}
#ifdef CONFIG_THTTPD_MEMDEBUG
httpd_memstats();
#endif
return ptr;
}
#endif
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
void httpd_free(FAR void *ptr)
{
free(ptr);
#ifdef CONFIG_THTTPD_MEMDEBUG
nvdbg("Freed memory at %p\n", ptr);
httpd_memstats();
#endif
}
#endif
/* Helpers to implement dynamically allocated strings */
void httpd_realloc_str(char **pstr, size_t *maxsize, size_t size)
{
size_t oldsize;
if (*maxsize == 0)
{
*maxsize = MAX(CONFIG_THTTPD_IOBUFFERSIZE, size + CONFIG_THTTPD_REALLOCINCR);
*pstr = NEW(char, *maxsize + 1);
}
else if (size > *maxsize)
{
oldsize = *maxsize;
*maxsize = MAX(oldsize * 2, size * 5 / 4);
*pstr = httpd_realloc(*pstr, oldsize + 1, *maxsize + 1);
}
else
{
return;
}
if (!*pstr)
{
ndbg("out of memory reallocating a string to %d bytes\n", *maxsize);
exit(1);
}
}
/* Generate debugging statistics */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
void httpd_memstats(void)
{
#ifdef CONFIG_THTTPD_MEMDEBUG
static struct mallinfo mm;
#endif
ndbg("%d allocations (%lu bytes)\n", g_nallocations, (unsigned long)g_allocated);
/* Get the current memory usage */
#ifdef CONFIG_THTTPD_MEMDEBUG
#ifdef CONFIG_CAN_PASS_STRUCTS
mm = mallinfo();
#else
(void)mallinfo(&mm);
#endif
ndbg("arena: %08x ordblks: %08x mxordblk: %08x uordblks: %08x fordblks: %08x\n",
mm.arena, mm.ordblks, mm.mxordblk, mm.uordblks, mm.fordblks);
#endif
}
#endif
#endif /* CONFIG_THTTPD */

82
netutils/thttpd/httpd_alloc.h Executable file
View File

@ -0,0 +1,82 @@
/****************************************************************************
* netutils/thttpd/httpd_alloc.h
*
* Copyright (C) 2009 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.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_HTTDP_ALLOC_H
#define __NETUTILS_THTTPD_HTTDP_ALLOC_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "config.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Global Functions
****************************************************************************/
/* Allows all memory management calls to be intercepted */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
extern FAR void *httpd_malloc(size_t nbytes);
extern FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize);
extern void httpd_free(FAR void *ptr);
#else
# define httpd_malloc(n) malloc(n)
# define httpd_realloc(p,o,n) realloc(p,n)
# define httpd_free(p) free(p)
#endif
/* Helpers to support allocations in multiples of a type size */
#define NEW(t,n) ((t*)httpd_malloc(sizeof(t)*(n)))
#define RENEW(p,t,o,n) ((t*)httpd_realloc((void*)p, sizeof(t)*(o), sizeof(t)*(n)))
/* Helpers to implement dynamically allocated strings */
extern void httpd_realloc_str(char **pstr, size_t *maxsizeP, size_t size);
/* Generate debugging statistics */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
extern void httpd_memstats(void);
#else
# define httpd_memstats()
#endif
#endif /* CONFIG_THTTPD */
#endif /* __NETUTILS_THTTPD_HTTDP_ALLOC_H */

View File

@ -63,6 +63,7 @@
#include "config.h"
#include "libhttpd.h"
#include "httpd_alloc.h"
#include "timers.h"
#include "tdate_parse.h"
#include "fdwatch.h"
@ -222,8 +223,6 @@ static size_t sockaddr_len(httpd_sockaddr *saP);
*/
static pid_t main_thread;
static int str_alloc_count = 0;
static size_t str_alloc_size = 0;
/* This is the 'root' of the Filesystem as seen by the HTTP client */
@ -295,10 +294,10 @@ static void free_httpd_server(httpd_server * hs)
{
if (hs->hostname)
{
free(hs->hostname);
httpd_free(hs->hostname);
}
free(hs);
httpd_free(hs);
}
}
@ -1791,13 +1790,14 @@ static void ls_child(int argc, char **argv)
{
maxnames = 100;
names = NEW(char, maxnames * (MAXPATHLEN + 1));
nameptrs = NEW(char *, maxnames);
nameptrs = NEW(char*, maxnames);
}
else
{
oldmax = maxnames;
maxnames *= 2;
names = RENEW(names, char, maxnames * (MAXPATHLEN + 1));
nameptrs = RENEW(nameptrs, char *, maxnames);
names = RENEW(names, char, oldmax*(MAXPATHLEN+1), maxnames*(MAXPATHLEN + 1));
nameptrs = RENEW(nameptrs, char*, oldmax, maxnames);
}
if (!names || !nameptrs)
@ -2756,7 +2756,7 @@ static int cgi_child(int argc, char **argv)
goto errout_with_descriptors;
}
buffer = (char*)malloc(CONFIG_THTTPD_IOBUFFERSIZE);
buffer = (char*)httpd_malloc(CONFIG_THTTPD_IOBUFFERSIZE);
if (!buffer)
{
ndbg("buffer allocation failed\n");
@ -2837,9 +2837,9 @@ errout_with_watch:
/* Free memory */
errout_with_buffer:
free(buffer);
httpd_free(buffer);
errout_with_header:
free(hdr.buffer);
httpd_free(hdr.buffer);
/* Close all descriptors */
@ -3222,34 +3222,6 @@ void httpd_clear_ndelay(int fd)
}
}
void httpd_realloc_str(char **strP, size_t * maxsizeP, size_t size)
{
if (*maxsizeP == 0)
{
*maxsizeP = MAX(CONFIG_THTTPD_IOBUFFERSIZE, size + CONFIG_THTTPD_REALLOCINCR);
*strP = NEW(char, *maxsizeP + 1);
++str_alloc_count;
str_alloc_size += *maxsizeP;
}
else if (size > *maxsizeP)
{
str_alloc_size -= *maxsizeP;
*maxsizeP = MAX(*maxsizeP * 2, size * 5 / 4);
*strP = RENEW(*strP, char, *maxsizeP + 1);
str_alloc_size += *maxsizeP;
}
else
{
return;
}
if (!*strP)
{
ndbg("out of memory reallocating a string to %d bytes\n", *maxsizeP);
exit(1);
}
}
void httpd_send_err(httpd_conn *hc, int status, const char *title, const char *extraheads,
const char *form, const char *arg)
{
@ -4145,21 +4117,21 @@ void httpd_destroy_conn(httpd_conn *hc)
{
if (hc->initialized)
{
free((void *)hc->read_buf);
free((void *)hc->decodedurl);
free((void *)hc->origfilename);
free((void *)hc->expnfilename);
free((void *)hc->encodings);
free((void *)hc->pathinfo);
free((void *)hc->query);
free((void *)hc->accept);
free((void *)hc->accepte);
free((void *)hc->reqhost);
free((void *)hc->hostdir);
free((void *)hc->remoteuser);
free((void *)hc->buffer);
httpd_free((void *)hc->read_buf);
httpd_free((void *)hc->decodedurl);
httpd_free((void *)hc->origfilename);
httpd_free((void *)hc->expnfilename);
httpd_free((void *)hc->encodings);
httpd_free((void *)hc->pathinfo);
httpd_free((void *)hc->query);
httpd_free((void *)hc->accept);
httpd_free((void *)hc->accepte);
httpd_free((void *)hc->reqhost);
httpd_free((void *)hc->hostdir);
httpd_free((void *)hc->remoteuser);
httpd_free((void *)hc->buffer);
#ifdef CONFIG_THTTPD_TILDE_MAP2
free((void *)hc->altdir);
httpd_free((void *)hc->altdir);
#endif /*CONFIG_THTTPD_TILDE_MAP2 */
hc->initialized = 0;
}
@ -4560,18 +4532,5 @@ int httpd_write(int fd, const void *buf, size_t nbytes)
return ntotal;
}
/* Generate debugging statistics */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
void httpd_logstats(long secs)
{
if (str_alloc_count > 0)
{
ndbg(" libhttpd - %d strings allocated, %lu bytes (%g bytes/str)\n",
str_alloc_count, (unsigned long)str_alloc_size,
(float)str_alloc_size / str_alloc_count);
}
}
#endif
#endif /* CONFIG_THTTPD */

View File

@ -65,9 +65,6 @@
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define NEW(t,n) ((t*) malloc( sizeof(t) * (n) ))
#define RENEW(o,t,n) ((t*) realloc( (void*) o, sizeof(t) * (n) ))
/* Enable special instrumentation to track down "400 Bad Request" problems */
#undef CONFIG_THTTPD_BADREQUEST /* Define to enable "Bad Request" instrumentation */
@ -327,10 +324,6 @@ extern const char httpd_err408form[];
extern const char *httpd_method_str(int method);
/* Reallocate a string. */
extern void httpd_realloc_str(char **strP, size_t *maxsizeP, size_t size);
/* Format a network socket to a string representation. */
extern char *httpd_ntoa(httpd_sockaddr * saP);
@ -343,14 +336,6 @@ extern void httpd_set_ndelay(int fd);
extern void httpd_clear_ndelay(int fd);
/* Generate debugging statistics syslog message. */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
extern void httpd_logstats(long secs);
#else
# define httpd_logstats(secs)
#endif
/* Read to requested buffer, accounting for interruptions and EOF */
extern int httpd_read(int fd, const void *buf, size_t nbytes);

View File

@ -59,6 +59,7 @@
#include "config.h"
#include "fdwatch.h"
#include "libhttpd.h"
#include "httpd_alloc.h"
#include "timers.h"
#ifdef CONFIG_THTTPD
@ -163,7 +164,7 @@ static void shut_down(void)
if (connects[cnum].hc != NULL)
{
httpd_destroy_conn(connects[cnum].hc);
free((void *)connects[cnum].hc);
httpd_free((void *)connects[cnum].hc);
connects[cnum].hc = NULL;
}
}
@ -180,7 +181,7 @@ static void shut_down(void)
}
tmr_destroy();
free((void *)connects);
httpd_free((void *)connects);
}
static int handle_newconnect(struct timeval *tv, int listen_fd)
@ -681,7 +682,7 @@ static void logstats(struct timeval *nowP)
ndbg("up %ld seconds, stats for %ld seconds\n", up_secs, stats_secs);
thttpd_logstats(stats_secs);
httpd_logstats(stats_secs);
httpd_memstats();
fdwatch_logstats(fw, stats_secs);
tmr_logstats(stats_secs);
}

View File

@ -45,6 +45,7 @@
#include <stdio.h>
#include <debug.h>
#include "httpd_alloc.h"
#include "timers.h"
/****************************************************************************
@ -202,7 +203,7 @@ Timer *tmr_create(struct timeval *nowP, TimerProc * timer_proc,
}
else
{
t = (Timer*)malloc(sizeof(Timer));
t = (Timer*)httpd_malloc(sizeof(Timer));
if (!t)
{
return NULL;
@ -352,7 +353,7 @@ void tmr_cleanup(void)
t = free_timers;
free_timers = t->next;
free_count--;
free((void*)t);
httpd_free((void*)t);
alloc_count--;
}
}