 |
|
 |
Hello,
If I leave my embedded device webserver working for hours, with 4-10 clients (Internet Explorer) calling periodically a CGI function my heap keeps filling until I get an exception. My opinion is that some sessions are not well closed and generate some memory leak. I can reproduce this behaviour in this way: start.....20%heap open 10 IE clients....30% heap keep working some time.... close 10 clients...HEAP doesnt reduce open 10 new IE clients....40% heap and so on
Any ideas ? Thanks, regards Paolo
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Paolo,
I sure does sound like a memory leak. I'll try to reproduce it over the next few days and see if I can spot it.
In your example above, when you "close 10 clients...", how do you close them? Do you lose the IE application with an exit, kill it from the process controller, or something else?
Please let me know,
-JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi JB,
I made some more investigation and found a memory leak. My webpage sends a GET avery 10 seconds to WebIO. Here some logs with caller routine in evidence:
****WI_MALLOC (0654) = 380031F4...wi_newsess:wi_alloc(sizeof(wi_sess)) = 380031FC ****WI_MALLOC (0024) = 3800D868...wi_buildform:wi_alloc(sizeof(total 24 bytes)) = 3800D870 ****WI_MALLOC (001C) = 3800D894...em_fopen:wi_alloc(sizeof(EOFILE)) = 3800D89C ****WI_MALLOC (0824) = 38003850...wi_newfile:wi_alloc(sizeof(wi_file)) = 38003858 wi_newfile GetUpdate.cgi ****WI_FREE (3800D894)...em_fclose:wi_free(passedfd) = 3800D89C wi_fclose ****WI_FREE (38003850)...wi_delfile:wi_free(delfile) = 38003858 wi_delfile wi_txdone:socket close wi_delsess:oldsess->ws_socket == INVALID_SOCKET ****WI_FREE (3800D868)...****WI_FREE (380031F4)...wi_delsess:wi_free(oldsess) = 380031FC
The form data (24 bytes) malloc never get freed. I think the problem in resourse freeing in wi_delsess:
................. /* Unlink from master session list */ lastsess = NULL; for(tmpsess = wi_sessions; tmpsess; tmpsess = tmpsess->ws_next) { if(tmpsess == oldsess) /* Found session to unlink? */ { if(lastsess) lastsess->ws_next = tmpsess->ws_next; else wi_sessions = tmpsess->ws_next; break; } lastsess= tmpsess; }
/* Make sure there are no dangling resources */ if(oldsess->ws_txbufs) { while(oldsess->ws_txbufs) { wi_txfree(oldsess->ws_txbufs); } } if(oldsess->ws_filelist) { if(oldsess->ws_filelist) // THIS IS STRANGE INDEED { wi_fclose( oldsess->ws_filelist); } } // PB 09/11/2009 18.39.29 if(oldsess->ws_formlist) { if(oldsess->ws_formlist) { wi_free( oldsess->ws_formlist); } } // PB 09/11/2009 18.39.29 ...........................
I added the oldsess->ws_formlist cleanup, but I'm not sure if you can have more than 1 form attached to a session; in that case, my correction would not be enough
I Wait for news from you, best regards,
Paolo
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yup, looks like a leak. Sorry about that. I'm pretty sure the form is a linked list, so I'll have to come with some code that traverses the list, free()ing memory as it goes. What you've posted should be OK for pages with only one form. I finally have the code on a public SVN server - I'll check in these fixes and publish the link in a note here as soon permissions are set up.
Thanks for the fix,
-JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, this is my (tested) upload routine:
/* wi_putfile() * * This is called when a session receives a PUT command. * * * Returns: 0 if no error, else negative WIE_ error code. * */
int wi_putfile( wi_sess * sess) { wi_file *fi; /* info about current file */
char * cp; char * cl; char * rxend; int res; long b_read, b_remain; /* First find end of HTTP header */ rxend = strstr(sess->ws_rxbuf, "\r\n\r\n" ); /* Extract the URL */ cp = wi_nextarg(&sess->ws_rxbuf[3]); if(!cp) { wi_senderr(sess, 400); /* Bad request */ return WIE_CLIENT; } if(*cp == '/') { if(*(cp+1) == ' ') sess->ws_uri = wi_rootfile; else sess->ws_uri = cp+1; /* strip leading slash */ } else sess->ws_uri = cp;
/* Extract other useful fields from header */ sess->ws_auth = wi_getline("Authorization:", cp); sess->ws_referer = wi_getline("Referer:", cp); sess->ws_host = wi_getline("Host:", cp);
cl = wi_getline("Content-Length:", cp); if(cl) sess->ws_contentLength = atoi(cl); else sess->ws_contentLength = 0; /* unset */ /* insert the null terminators in any strings in the rxbuf */ if((sess->ws_uri > sess->ws_rxbuf) && (sess->ws_uri < rxend)) wi_argterm(sess->ws_uri); /* Null terminate the URI */ if((sess->ws_auth > sess->ws_rxbuf) && (sess->ws_auth < rxend)) wi_argterm(sess->ws_auth); /* etc */ if((sess->ws_referer > sess->ws_rxbuf) && (sess->ws_referer < rxend)) wi_argterm(sess->ws_referer); if((sess->ws_uri > sess->ws_host) && (sess->ws_host < rxend)) wi_argterm(sess->ws_host); /* --------------------------------------------- */ /* Decode filename */ wi_urldecode(sess->ws_uri); /* Inizio a leggere il file da scrivere nel mio filesystem */ b_remain = sess->ws_contentLength; res = wi_fopen(sess, fname_path, "w"); if (res == 0) { /* file da scrivere */ fi = sess->ws_filelist; /* vedo se nel primo pacchetto ci sono anche dati da scrivere */ if (sess->ws_data) { b_read = sess->ws_rxsize - (sess->ws_data - sess->ws_rxbuf); b_remain -= b_read; res = wi_fwrite(sess->ws_data, 1, b_read, fi); }
if (b_remain > 0) do { b_read = recv (sess->ws_socket, sess->ws_rxbuf, sizeof(sess->ws_rxbuf), 0); if (b_read != -1) { b_remain -= b_read; res = wi_fwrite(sess->ws_rxbuf, 1, b_read, fi); /* all data written ? */ if (res != b_read) { /* TODO: check, why not all data was written */ b_remain = -1; // segnalo abort } } else { b_remain = -1; // segnalo abort break; } } // do while (b_remain > 0); if (b_remain == 0) { wi_replyhdr(sess, sess->ws_contentLength); wi_fclose(fi); } else { wi_fclose(fi); wi_fremove(sess->ws_uri); wi_senderr(sess, 501); /* Send "Internal server error" reply */ } } else { wi_senderr(sess, 503); /* Send "Service Unavailable" reply */ } return 0; /* No Error */ }
Hope will be useful...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hi again,
if I ask Webio a "big" file (25Kbytes) it seems like wi_readfile allocates more and more sessions with wi_txalloc(sess), until my embedded system runs out of memory. Is that true ? could you help me modify this routine so no more than, say, 3 sessions get allocated at any time ? I understand 26K is insignificant on Linux and Windows, but can be a problem in embedded system with limited heap...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi -
Is this a binary file, or is a "normal" one which may have SSI-type includes?
This could be a bug (after all you've found 'em before ) or it could be an artifact of the way Webio handles the SSI-containing (I'll call them dynamic) files. To return the Content-Length of a dymanic file Webio reads the whole file, including files inside SSIs, into a chain of buffers; then measures the ready-to-send set of buffers to get the length. These buffers can eat a lot of space.
So - is the file binary?
Let me know, -JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, tanks for replying so fast,
it is a normal text file (license_lgpl.txt). If I change the extension to htm nothing changes. I guess It's treated as binary file.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Update: if I force sess->ws_flags |= WF_BINARY in wi_setftype download goes OK. The problem arise with non-binary files (wich get parsed and transferred to RAM before sending via Ethernet)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Glad to hear you got it working. IIRC there's an option in the web page generator to force this flag on a per file basis, but when I went to check this out in the online manual I discovered the Praemio.com web site is defunct . Look like I have to find a new home for Webio and get everything moved. More soon..... -JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hi again (!)
If I refresh countinuosly my webpage my ARM system throws an ADDR_ABORT exception, probably due to recursion (but my stacks seem healty...) Any suggestion on how to avoid recursion on wi_readfile ?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Perhaps I've found the solution (memory leak). wi_alloc needs a check on malloc success:
wi_alloc(int bufsize) { char * buffer; struct memmarker * mark; int totalsize;
totalsize = bufsize + sizeof(struct memmarker) + 4;
buffer = WI_MALLOC(totalsize); if (buffer == 0) // PB 03/07/2009 17.58.07 return (0); // PB 03/07/2009 17.58.12 ...................
Hope this will help somebody
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
This is definitely a bug. I'd better review the code for making sure I check all results of malloc. Thanks for pointing this out. -JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, I am porting your webserver to an ARM processor. I woud need to upload my files (with curl) and wi_putfile seem perfect - but it's empty... Did you put some work on this routine ? Any suggestion should I implement it by myself ?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, very good work. How about adding AJAX support for dynamic refresh of portions of page ? I've already done some work on this, maybe we can cooperate....
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I thought AJAX was mostly client side. As such it should "just work" with Webio. Are there any specific features that are needed? -JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
yes, you are right, it's almost client side. I was thinking to automate some functions (like XMLHttpRequest creation and handling) via fsbuilder, who creates callback stubs already....
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Several users have quite rightly pointed out that I forgot the Linux makefile. A Makefile for Linux is now available at the link below. I've tested it building the code base down-loadable from this page on Fedora 7. Let me know if it works (or not) with other code bases and Linux versions.
Here's the link:
http://www.praemio.com/webio/makefile
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Code works fine in Windows, but how to compile in Linux? There is no make file included! The explanation of compiling in Linux is quite short and I can't follow... 
regards
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi - sorry about forgetting the Linux makefile. I think the easiest way to provide one is to paste it directly into this message. Just copy into a local file, delete these leading lines, and make. Hope this works.... #=================================================== #-------------------------------------------------------------------------------
# Makefile for webio - Linux demo app
#
# The code files (object names) for webio.
WEBIO_OBJS = webclib.o webfs.o webio.o webobjs.o \
websys.o webutils.o webtest.o
# The Content-containing C files produced by fsbuilder CONTENT_C = wsfdata.c wsfcode.c
# Object versions of the content-containing C files CONTENT_OBJS = wsfdata.o
# The Ultimate Target of this makefile
WEBIO = webio
# File system builder utility to convert content into C files FSBUILDER = fsbuilder
# C flags. If you forget the -DLINUX it will try to build a windows version CC_FLAGS = -c -DLINUX
.c.o:
$(CC) $(CC_FLAGS) $*.c
# Build the actual server. This links both the code files (WEBIO_OBJS) and # some embedded content $(CONTENT_OBJS) $(WEBIO): $(WEBIO_OBJS) $(CONTENT_OBJS) gcc $(WEBIO_OBJS) $(CONTENT_OBJS)
# Build C files containing content. $(CONTENT_C): $(FSBUILDER) filelist ./fsbuilder filelist
# Make the fsbuilder utillity. This is required for this example. webio apps # with no embedded content (i.e. content is all regular disk files) don't # need fsbuilder $(FSBUILDER): fsbuilder.cpp g++ -o fsbuilder fsbuilder.cpp
clean:
rm -f *.o rm -f $(CONTENT_C)
rm -f webio
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
This is not working for me.
I am getting cc -c -o webfs.o webfs.c webfs.c:167:21: error: wsfdata.h: No such file or directory webfs.c:175: error: ‘efslist’ undeclared here (not in a function) make: *** [webfs.o] Error 1
If anyone has got the same error and fixed .please do shre the fix with me.
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Hi, I recently discover the embedded server, and I find it great.
In my case, I have to return image whose the name is dynamically generated. In my use case, the user retrieves an XML file containing the image names. From these names he can retrieve the images. As the XML contains data about the images, and they are always changing, the unique name is useful to be sure the images are properly matching the XML. So to summarize I have: http://localhost/data.xml containing
<foo> <image="12345.jpg" x=7 y=5 /> <image="12346.jpg" x=7 y=6 /> </foo>
I need to provide http://localhost/12345.jpg and http://localhost/123456.jpg As these names are always changing, they can not come from the fsbuilder.
If I'm correct it's not possible with the current webio version. Is it true ? To do it, I was thinking to add a new filesystems in the wi_filesys table, allowing pure dynamic recording of file. Is it the right way to do it ?
Thanks
Arno
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
Would ravenspoint be willing to share this cWebIo class that he/she talks about below ? We would greatly appreciate the pointer.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |