]> git.sur5r.net Git - cc65/commitdiff
New function: _aligned_malloc
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 5 Jan 2005 21:07:23 +0000 (21:07 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 5 Jan 2005 21:07:23 +0000 (21:07 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3349 b7a2c559-68d2-44c3-8de9-860c34a00d81

include/stdlib.h
libsrc/common/.cvsignore
libsrc/common/Makefile
libsrc/common/_aligned_malloc.c [new file with mode: 0644]

index f18421a414597445056927c264ce492b1011e404..6924481679451f6665b88142958b855c9d8aee59 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2004 Ullrich von Bassewitz                                       */
+/* (C) 1998-2005 Ullrich von Bassewitz                                       */
 /*               Römerstrasse 52                                             */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
@@ -62,6 +62,15 @@ void __fastcall__ free (void* block);
 
 /* Non standard memory management functions */
 
+void* __fastcall__ _aligned_malloc (size_t size, size_t alignment)
+/* Allocate a block of memory with the given size, which is aligned to a
+ * memory address that is a multiple of alignment. alignment MUST NOT be
+ * zero and MUST be a power of two, otherwise a call to this function will
+ * cause undefined behaviour. The function returns NULL if not enough memory
+ * is available to satisfy the request. To free the allocated block, use the
+ * free() function.
+ */
+
 void __fastcall__ _heapadd (void* mem, size_t size);
 /* Add a block to the heap */
 
index b91764795bdc37a52de29a1dc0e2572166dba218..89274f3516c12786b53a14c459b3f4ab27119789 100644 (file)
@@ -1,5 +1,6 @@
 *.lst
 _afailed.s
+_aligned_malloc.s
 _hextab.s
 _poserror.s
 _scanf.s
index 7a6eeb1b5c416c43b91d8a579977ec8537db55f5..9f44723f4f494d85133316f51c3b7de7e246588f 100644 (file)
@@ -29,41 +29,42 @@ CFLAGS      = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include
 #--------------------------------------------------------------------------
 # Object files
 
-C_OBJS =       _afailed.o      \
-               _hextab.o       \
-                _poserror.o     \
-               _scanf.o        \
-               abort.o         \
-                asctime.o       \
-               bsearch.o       \
-               errormsg.o      \
-               fdopen.o        \
-               fgetc.o         \
-               fgetpos.o       \
-               fgets.o         \
-               fputc.o         \
-               fputs.o         \
-               freopen.o       \
-               fseek.o         \
-               fsetpos.o       \
-               ftell.o         \
-               getchar.o       \
-               gets.o          \
-                gmtime.o        \
-               locale.o        \
-                localtime.o     \
-                mktime.o        \
-               perror.o        \
-               puts.o          \
-               qsort.o         \
-               realloc.o       \
-               rewind.o        \
-                scanf.o         \
-               sleep.o         \
-                strftime.o      \
-               strxfrm.o       \
-               strtok.o        \
-                system.o        \
+C_OBJS =       _afailed.o              \
+                _aligned_malloc.o       \
+               _hextab.o               \
+                _poserror.o             \
+               _scanf.o                \
+               abort.o                 \
+                asctime.o               \
+               bsearch.o               \
+               errormsg.o              \
+               fdopen.o                \
+               fgetc.o                 \
+               fgetpos.o               \
+               fgets.o                 \
+               fputc.o                 \
+               fputs.o                 \
+               freopen.o               \
+               fseek.o                 \
+               fsetpos.o               \
+               ftell.o                 \
+               getchar.o               \
+               gets.o                  \
+                gmtime.o                \
+               locale.o                \
+                localtime.o             \
+                mktime.o                \
+               perror.o                \
+               puts.o                  \
+               qsort.o                 \
+               realloc.o               \
+               rewind.o                \
+                scanf.o                 \
+               sleep.o                 \
+                strftime.o              \
+               strxfrm.o               \
+               strtok.o                \
+                system.o                \
                 timezone.o
 
 
diff --git a/libsrc/common/_aligned_malloc.c b/libsrc/common/_aligned_malloc.c
new file mode 100644 (file)
index 0000000..a74608b
--- /dev/null
@@ -0,0 +1,163 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                              _aligned_malloc                              */
+/*                                                                           */
+/*                     Allocate an aligned memory block                      */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2004-2005 Ullrich von Bassewitz                                       */
+/*               Römerstrasse 52                                             */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <_heap.h>
+
+
+
+/* This is a very simple version of an aligned memory allocator. We will
+ * allocate a greater block, so we can place the aligned block within it
+ * that is returned. We use our knowledge about the internal heap
+ * structures to free the unused parts of the bigger block (the two chunks
+ * below and above the aligned block).
+ */
+
+
+
+void* __fastcall__ _aligned_malloc (size_t size, size_t alignment)
+/* Allocate a block of memory with the given size, which is aligned to a
+ * memory address that is a multiple of alignment. alignment MUST NOT be
+ * zero and MUST be a power of two, otherwise a call to this function will 
+ * cause undefined behaviour. The function returns NULL if not enough memory 
+ * is available to satisfy the request. To free the allocated block, use the
+ * free() function.
+ */
+{
+    size_t rawsize;
+    size_t uppersize;
+    size_t lowersize;
+    register struct usedblock* b;
+    register struct usedblock* u;
+    register struct usedblock* p;
+
+    /* Handle requests for zero sized blocks */
+    if (size == 0) {
+        return 0;
+    }
+
+    /* We don't really need alignment, but alignment-1 */
+    --alignment;
+
+    /* Round up the block size and allocate memory. We don't need to account
+     * for the additional admin data needed to manage the used block, since
+     * the block returned by malloc has this overhead added one time, and
+     * the worst thing that may happen is that we cannot free the upper and
+     * lower blocks.
+     */
+    b = malloc (size + alignment);
+
+    /* Handle out of memory */
+    if (b == 0) {
+        return 0;
+    }
+
+    /* Create a new pointer that points to the user visible aligned block. */
+    u = (struct usedblock*) (((unsigned)b + alignment) & ~alignment);
+
+    /* Get the raw block pointer, which is located just below the user visible
+     * block. The first word of this raw block is the total size of the block
+     * including the admin space.
+     */
+    b = (b-1)->start;
+    rawsize = b->size;
+
+    /* Get a pointer to the (raw) upper block */
+    p = (struct usedblock*) (size + (unsigned)u);
+
+    /* Check if we can free the space above the allocated block. This is the
+     * case if the size of the block is at least sizeof (struct freeblock)
+     * bytes and the size of the remaining block is at least of this size,
+     * too. If the upper block is smaller, we will just pass it to the caller
+     * together with the requested aligned block.
+     */
+    uppersize = rawsize + (unsigned)b - (unsigned)p;
+    if (uppersize >= sizeof (struct freeblock) &&
+        (rawsize - uppersize) >= sizeof (struct freeblock)) {
+
+        /* Setup the usedblock structure */
+        p->size  = uppersize;
+        p->start = p;
+
+        /* Generate a pointer to the user space and free the block */
+        free (p + 1);
+
+        /* Decrement the raw block size by the amount of space just free'd */
+        rawsize -= uppersize;
+    }
+
+    /* Check if we can free the space below the allocated block. This is the
+     * case, if the size of the block is at least sizeof (struct freeblock)
+     * bytes and the size of the remaining block is at least of this size,
+     * too. If the lower block is smaller, we will just pass it to the caller
+     * together with the requested aligned block.
+     * Beware: We need an additional struct usedblock in the lower block which
+     * is part of the block that is passed back to the caller.
+     */
+    lowersize = ((unsigned)u - (unsigned)b) - sizeof (struct usedblock);
+    if (lowersize >= sizeof (struct freeblock) &&
+        (rawsize - lowersize) >= sizeof (struct freeblock)) {
+
+        /* b does already point to the raw lower block. Setup the usedblock
+         * structure.
+         */
+        b->size  = lowersize;
+        b->start = b;
+
+        /* Generate a pointer to the user space and free the block */
+        free (b + 1);
+
+        /* Decrement the raw block size by the amount of space just free'd */
+        rawsize -= lowersize;
+
+        /* Set b to the raw user block */
+        b = u - 1;
+    }
+
+    /* u does now point to the user visible block, while b points to the raw
+     * block, and rawsize contains the size of the raw block. Setup the
+     * usedblock structure but beware: If we didn't free the lower block, it
+     * is splitted, which means that we must use u to write the start field,
+     * and b to write the size.
+     */
+    (u-1)->start = b;
+    b->size  = rawsize;
+
+    /* Return the user portion of the aligned block */
+    return u;
+}
+
+
+