diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog index f6f506364..d1b9bf629 100644 --- a/winsup/mingw/ChangeLog +++ b/winsup/mingw/ChangeLog @@ -1,3 +1,8 @@ +2004-08-24 Steven G. Johnson + + * mingwex/mingw-aligned-malloc.c: New file. + * mingwex/tst-aligned-malloc.c: New file. + 2004-08-24 Danny Smith * crt1.c: (__mingw_CRTStartup): Change return to void. Add diff --git a/winsup/mingw/mingwex/mingw-aligned-malloc.c b/winsup/mingw/mingwex/mingw-aligned-malloc.c new file mode 100755 index 000000000..a6d4ac934 --- /dev/null +++ b/winsup/mingw/mingwex/mingw-aligned-malloc.c @@ -0,0 +1,120 @@ +/* + __mingw_aligned_malloc and friends, implemented using Microsoft's public + interfaces and with the help of the algorithm description provided + by Wu Yongwei: http://sourceforge.net/mailarchive/message.php?msg_id=3847075 + + I hereby place this implementation in the public domain. + -- Steven G. Johnson (stevenj@alum.mit.edu) +*/ + +#include +#include +#include /* ptrdiff_t */ +#include /* memmove */ + +#ifdef HAVE_STDINT_H +# include /* uintptr_t */ +#else +# define uintptr_t size_t +#endif + +#define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1))) +#define UI(p) ((uintptr_t) (p)) +#define CP(p) ((char *) p) + +#define PTR_ALIGN(p0, alignment, offset) \ + ((void *) (((UI(p0) + (alignment + sizeof(void*)) + offset) \ + & (~UI(alignment - 1))) \ + - offset)) + +/* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */ +#define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1)) + +void * +__mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset) +{ + void *p0, *p; + + if (NOT_POWER_OF_TWO (alignment)) + { + errno = EINVAL; + return ((void *) 0); + } + if (size == 0) + return ((void *) 0); + if (alignment < sizeof (void *)) + alignment = sizeof (void *); + + /* Including the extra sizeof(void*) is overkill on a 32-bit + machine, since malloc is already 8-byte aligned, as long + as we enforce alignment >= 8 ...but oh well. */ + + p0 = malloc (size + (alignment + sizeof (void *))); + if (!p0) + return ((void *) 0); + p = PTR_ALIGN (p0, alignment, offset); + ORIG_PTR (p) = p0; + return p; +} + +void * +__mingw_aligned_malloc (size_t size, size_t alignment) +{ + return __mingw_aligned_offset_malloc (size, alignment, 0); +} + +void +__mingw_aligned_free (void *memblock) +{ + if (memblock) + free (ORIG_PTR (memblock)); +} + +void * +__mingw_aligned_offset_realloc (void *memblock, size_t size, + size_t alignment, size_t offset) +{ + void *p0, *p; + ptrdiff_t shift; + + if (!memblock) + return __mingw_aligned_offset_malloc (size, alignment, offset); + if (NOT_POWER_OF_TWO (alignment)) + goto bad; + if (size == 0) + { + __mingw_aligned_free (memblock); + return ((void *) 0); + } + if (alignment < sizeof (void *)) + alignment = sizeof (void *); + + p0 = ORIG_PTR (memblock); + /* It is an error for the alignment to change. */ + if (memblock != PTR_ALIGN (p0, alignment, offset)) + goto bad; + shift = CP (memblock) - CP (p0); + + p0 = realloc (p0, size + (alignment + sizeof (void *))); + if (!p0) + return ((void *) 0); + p = PTR_ALIGN (p0, alignment, offset); + + /* Relative shift of actual data may be different from before, ugh. */ + if (shift != CP (p) - CP (p0)) + /* ugh, moves more than necessary if size is increased. */ + memmove (CP (p), CP (p0) + shift, size); + + ORIG_PTR (p) = p0; + return p; + +bad: + errno = EINVAL; + return ((void *) 0); +} + +void * +__mingw_aligned_realloc (void *memblock, size_t size, size_t alignment) +{ + return __mingw_aligned_offset_realloc (memblock, size, alignment, 0); +} diff --git a/winsup/mingw/mingwex/tst-aligned-malloc.c b/winsup/mingw/mingwex/tst-aligned-malloc.c new file mode 100755 index 000000000..43ee734bc --- /dev/null +++ b/winsup/mingw/mingwex/tst-aligned-malloc.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +# include /* uintptr_t */ +#else +# define uintptr_t size_t +#endif + +#define NELEM(a) (sizeof(a) / sizeof(a[0])) + +static int +is_aligned (void *p, size_t alignment, size_t offset) +{ + return !((((uintptr_t) p) + offset) & (alignment - 1)); +} + +#define MAX_SIZE (1 << sizeof(unsigned char)) +#define NP 1000 +#define NTST 100000U + +#define ERRMSG fprintf(stderr, "Iteration %u, align = %u, offset = %u, size = %u (oldsize = %u), errno = %d (%s)\n", i, align[j % NELEM(align)], offset[j % NELEM(offset)], size[j], oldsize, errno, strerror(errno)) + +int +main (void) +{ + unsigned char *p[NP]; + size_t size[NP]; + size_t align[] = { 2, 4, 8, 16, 32, 64 }; + size_t offset[20]; + unsigned i; + + srand (time (NULL)); + + for (i = 0; i < NELEM (p); ++i) + { + p[i] = 0; + size[i] = 0; + } + + for (i = 0; i < NELEM (offset); ++i) + offset[i] = rand () % 512; + + for (i = 0; i < NTST; ++i) + { + size_t oldsize; + unsigned j, k; + j = rand () % NELEM (p); + oldsize = size[j]; + p[j] = __mingw_aligned_offset_realloc (p[j], + size[j] = rand () % MAX_SIZE, + align[j % NELEM (align)], + offset[j % NELEM (offset)]); + + if (size[j] && !p[j]) + { + fprintf (stderr, "Returned NULL!\n"); + ERRMSG; + return EXIT_FAILURE; + } + if (size[j] && !is_aligned (p[j], + align[j % NELEM (align)], + offset[j % NELEM (offset)])) + { + fprintf (stderr, "Misaligned block!\n"); + ERRMSG; + return EXIT_FAILURE; + } + if (oldsize > size[j]) + oldsize = size[j]; + for (k = 0; k < oldsize; ++k) + if (p[j][k] != k) + { + fprintf (stderr, "Miscopied block!\n"); + ERRMSG; + return EXIT_FAILURE; + } + for (k = 0; k < size[j]; ++k) + p[j][k] = k; + } + + for (i = 0; i < NELEM (p); ++i) + __mingw_aligned_free (p[i]); + + return EXIT_SUCCESS; +}