changeset 1420:9721661d7ecc

Fixes to zlib decompression - from Ian Campbell
author gthomas
date Fri, 05 Dec 2003 14:15:52 +0000
parents fa9edbd9ccaa
children 170fbc1a5bbc
files packages/redboot/current/ChangeLog packages/redboot/current/src/decompress.c
diffstat 2 files changed, 77 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,10 @@
+2003-12-05  Ian Campbell  <icampbell@arcom.com>
+
+	* src/decompress.c: Ensure that free'd blocks are returned to the
+	free pool and that adjacent free blocks are merged. Initialise the
+	pool in _zlib_init() so that things are initialised even when
+	gzip_init hasn't been called.
+
 2003-12-05  Gary Thomas  <gary@mlbassoc.com>
 
 	* src/io.c (_rb_gets_preloaded): ^A could have moved the cursor to
--- a/packages/redboot/current/src/decompress.c
+++ b/packages/redboot/current/src/decompress.c
@@ -63,15 +63,15 @@ static bool stream_end;
 
 //
 // Free memory [blocks] are stored as a linked list of "struct _block"
-// When free, 'size' is the size of the whole block
-// When allocated, 'size' is the allocation size
 // The 'magic' is kept to insure that the block being freed is reasonable
 //
+// One of either next or size might be removable, if a sentinal block
+// is placed at the end of the region at initialisation time.
 struct _block {
-    int            size;
-    long           magic;  // Must be __ZLIB_MAGIC__
+    int            size;   // always the total length of the block, including this header
+    long           magic;  // Must be __ZLIB_MAGIC__ if allocated and 0 if free
     struct _block *next;
-    struct _block *self;
+    struct _block *prev;
 };
 static struct _block *memlist;
 
@@ -92,6 +92,7 @@ static void *zlib_workspace;
 static void
 _zlib_init(void)
 {
+    struct _block *bp;
 #ifdef CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER
     zlib_workspace = fis_zlib_common_buffer;
 #else
@@ -99,6 +100,14 @@ static void
     workspace_end -= ZLIB_COMPRESSION_OVERHEAD;
     zlib_workspace = workspace_end;
 #endif
+    bp = (struct _block *)zlib_workspace;
+    memlist = bp;
+    bp->next = bp->prev = 0;
+    bp->size = ZLIB_COMPRESSION_OVERHEAD; 
+    bp->magic = 0;
+#ifdef DEBUG_ZLIB_MALLOC
+    show_memlist(__FUNCTION__);
+#endif
 }
 
 RedBoot_init(_zlib_init, RedBoot_INIT_FIRST);
@@ -111,10 +120,13 @@ show_memlist(char *when)
     struct _block *bp = memlist;
 
     diag_printf("memory list after %s\n", when);
+    diag_printf("   --START--- --END----- --SIZE---- --PREV---- --NEXT---- TYPE-----\n");
     while (bp != (struct _block *)0) {
-        diag_printf("   %08p %5d %08p\n", bp, bp->size, bp->next);
+        diag_printf("   %08p-%08p 0x%08x %08p %08p %s\n", bp, (unsigned char *)bp+bp->size, 
+                    bp->size, bp->prev, bp->next, bp->magic == 0 ? "FREE" : "ALLOCATED" );
         bp = bp->next;
     }
+    diag_printf("\n");
 }
 #endif
 
@@ -124,120 +136,90 @@ show_memlist(char *when)
 void 
 *zcalloc(void *opaque, unsigned int items, unsigned int size)
 {
-    voidpf res;
-    int len = (items*size);
+    voidpf res = 0;
+    int len = (items*size) + sizeof(struct _block);
     struct _block *bp = memlist;
-    struct _block *nbp, *pbp;
+    struct _block *nbp;
+
+#ifdef DEBUG_ZLIB_MALLOC
+    /* do this here because when int is called output is not setup yet */
+    static int first_alloc = 1;
+    if ( first_alloc ) {
+        show_memlist("initialization");
+        first_alloc = 0;
+    }
+#endif
 
     // Simple, first-fit algorithm
-    pbp = (struct _block *)0;
     while (bp) {
-        if (bp->size > len) {
-            nbp = (struct _block *)((char *)bp + len + sizeof(struct _block));
+        if (bp->magic == 0 && bp->size > len) {
+            nbp = (struct _block *)((char *)bp + len);
+            /* link new block into chain */
             nbp->next = bp->next;
+            bp->next = nbp;
+            nbp->prev = bp;
+            /* split size between the two blocks */
             nbp->size = bp->size - len;
-            if (pbp) {
-                pbp->next = nbp;
-            } else {
-                memlist = nbp;
-            }
-            res = bp;
+            bp->size = len;
+            /* mark the new block as free */
+            nbp->magic = 0;
+            /* mark allocated block as allocated */
+            bp->magic = __ZLIB_MAGIC__;
+            res = bp +1;
+            memset(res, 0, len - sizeof(struct _block));
             break;
         }
-        pbp = bp;
         bp = bp->next;
     }
-    if (bp) {
-        bp->size = len;
-        bp->magic = __ZLIB_MAGIC__;
-        bp->self = bp;
-        res = bp+1;
-        memset(res, 0, len);
-    } else {
-        res = 0;  // No memory left
-    }
 #ifdef DEBUG_ZLIB_MALLOC
-    diag_printf("%s(%d,%d) = %p\n", __FUNCTION__, items, size, res);
+    diag_printf("%s(0x%x,0x%x) = %p\n", __FUNCTION__, items, size, res);
     show_memlist(__FUNCTION__);
 #endif
+    if ( res == NULL )
+        diag_printf("zcalloc: failed to allocate 0x%x items of 0x%x bytes == 0x%x bytes\n", items, size, len);
     return res;
 }
 
 void 
 zcfree(void *opaque, void *ptr)
 {
-    struct _block *bp, *pbp, *nbp;
-    int size;
+    struct _block *bp;
 
     if (!ptr) return;  // Safety
     bp = (struct _block *)((char *)ptr - sizeof(struct _block));
-    if ((bp->magic != __ZLIB_MAGIC__) || (bp->self != bp)) {
+    if (bp->magic != __ZLIB_MAGIC__) {
         diag_printf("%s(%p) - invalid block\n", __FUNCTION__, ptr);
         return;
     }
-    size = bp->size;
+
+    /* mark as free */
+    bp->magic = 0;
+
 #ifdef DEBUG_ZLIB_MALLOC
-    diag_printf("%s(%p) = %d bytes\n", __FUNCTION__, ptr, size);
-#endif
-    // See if this block is adjacent to a free block
-    nbp = memlist;
-    pbp = (struct _block *)0;
-    while (nbp) {
-        if ((char *)bp+size+sizeof(struct _block) == (char *)nbp) {
-            // The block being freed fits just before
-            bp->next = nbp->next;
-            bp->size = nbp->size + size + sizeof(struct _block);
-#ifdef DEBUG_ZLIB_MALLOC
-            diag_printf("Free before\n");
+    diag_printf("%s(%p) = 0x%x bytes\n", __FUNCTION__, ptr, bp->size);
 #endif
-            if (pbp) {
-                pbp->next = bp;
-                // See if this new block and the previous one can
-                // be combined.
-                if ((char *)pbp+pbp->size == (char *)bp) {
-#ifdef DEBUG_ZLIB_MALLOC
-                    diag_printf("Collapse [before] - p: %p/%d/%p, n: %p/%d/%p\n",
-                                pbp, pbp->size, pbp->next,
-                                bp, bp->size, bp->next);
-#endif
-                    pbp->size += bp->size;
-                    pbp->next = bp->next;
-                }
-            } else {
-                memlist = bp;
-            }
+
+    bp = (struct _block *)((char *)ptr - sizeof(struct _block));
+    while(bp->next && bp->next->magic == 0) {
 #ifdef DEBUG_ZLIB_MALLOC
-            show_memlist(__FUNCTION__);
+        diag_printf("  merging %08p and %08p (after)\n", bp, bp->next);
 #endif
-            return;
-        } else
-        if ((char *)nbp+nbp->size == (char *)bp) {
-            // The block being freed fits just after
-            nbp->size += size + sizeof(struct _block);
-            // See if it will now collapse with the following block
-#ifdef DEBUG_ZLIB_MALLOC
-            diag_printf("Free after\n");
-#endif
-            if (nbp->next != (struct _block *)0) {
-                if ((char *)nbp+nbp->size == (char *)nbp->next) {
+        bp->size += bp->next->size;
+        bp->next = bp->next->next;
+    }
+
+    while(bp->prev && bp->prev->magic == 0) {
 #ifdef DEBUG_ZLIB_MALLOC
-                    diag_printf("Collapse [after] - p: %p/%d/%p, n: %p/%d/%p\n",
-                                nbp, nbp->size, nbp->next,
-                                nbp->next, nbp->next->size, nbp->next->next);
+        diag_printf("  merging %08p and %08p (before)\n", bp->prev, bp);
 #endif
-                    nbp->size += (nbp->next)->size;
-                    nbp->next = (nbp->next)->next;
-                }
-            }
+        bp->prev->size += bp->size;
+        bp->prev->next = bp->next;
+        bp = bp->prev;
+    }
+
 #ifdef DEBUG_ZLIB_MALLOC
-            show_memlist(__FUNCTION__);
+    show_memlist(__FUNCTION__);
 #endif
-            return;
-        } else {
-            pbp = nbp;
-            nbp = nbp->next;
-        }
-    }
 }
 
 //
@@ -252,7 +234,7 @@ gzip_init(_pipe_t* p)
 
     bp = (struct _block *)zlib_workspace;
     memlist = bp;
-    bp->next = 0;
+    bp->next = bp->prev = 0;
     bp->size = ZLIB_COMPRESSION_OVERHEAD;
     stream.zalloc = zcalloc;
     stream.zfree = zcfree;