[asterisk-dev] iax2-parser.c - Memory
Russell Bryant
russell at digium.com
Fri Jul 25 10:08:14 CDT 2008
Octavio Ascanio Suárez wrote:
> I am Octavio, I am working with Eric in this problem. We have added some
> ast_log in iax_frame_free and iax_frame_new we have seen that
> iax_frame_new dont find a block of 160 bytes in the linked list when
> iax_frame_free has added it previously.
Keep in mind that just because you saw a frame of that size go into
iax_frame_free, does not mean that is available for the next call to
iax_frame_new. There is a cache of available frames _per thread_. So,
if the call to iax_frame_free is done from a different thread than the
call to iax_frame_new, then this behavior would be expected.
It is possible that there is a thread (or number of a specific type of
threads) in chan_iax2 which has code that frees frames, but does not
allocate them. If that is the case, then the frame cache for that
thread would grow for forever.
If that is the issue we're facing, then the following patch would avoid
the infinite leak. However, a full solution would be to add an argument
for iax_frame_free which hints that the frame shouldn't be cached when
we know it will never be pulled out of the cache.
Index: channels/iax2-parser.c
===================================================================
--- channels/iax2-parser.c (revision 133577)
+++ channels/iax2-parser.c (working copy)
@@ -58,7 +58,14 @@
/*! \brief This is just so iax_frames, a list head struct for holding
a list of
* iax_frame structures, is defined. */
-AST_LIST_HEAD_NOLOCK(iax_frames, iax_frame);
+AST_LIST_HEAD_NOLOCK(iax_frame_list, iax_frame);
+
+struct iax_frames {
+ struct iax_frame_list list;
+ size_t size;
+};
+
+#define FRAME_CACHE_MAX_SIZE 20
#endif
static void internaloutput(const char *str)
@@ -957,10 +964,11 @@
/* Attempt to get a frame from this thread's cache */
if ((iax_frames = ast_threadstorage_get(&frame_cache,
sizeof(*iax_frames)))) {
- AST_LIST_TRAVERSE_SAFE_BEGIN(iax_frames, fr, list) {
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
if (fr->afdatalen >= datalen) {
size_t afdatalen = fr->afdatalen;
- AST_LIST_REMOVE_CURRENT(iax_frames, list);
+ AST_LIST_REMOVE_CURRENT(&iax_frames->list, list);
+ iax_frames->size--;
memset(fr, 0, sizeof(*fr));
fr->afdatalen = afdatalen;
break;
@@ -1017,11 +1025,14 @@
return;
}
- fr->direction = 0;
- AST_LIST_INSERT_HEAD(iax_frames, fr, list);
-#else
+ if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
+ fr->direction = 0;
+ AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
+ iax_frames->size++;
+ return;
+ }
+#endif
free(fr);
-#endif
}
#if !defined(LOW_MEMORY)
@@ -1030,7 +1041,7 @@
struct iax_frames *frames = data;
struct iax_frame *cur;
- while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
+ while ((cur = AST_LIST_REMOVE_HEAD(&frames->list, list)))
free(cur);
free(frames);
--
Russell Bryant
Senior Software Engineer
Open Source Team Lead
Digium, Inc.
More information about the asterisk-dev
mailing list