Welcome to mirror list, hosted at ThFree Co, Russian Federation.

mingw-aligned-malloc.c « mingwex « mingw « winsup - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a6d4ac934b46a0db0c9c516fb95b7b09a3c30be6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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 <stdlib.h>
#include <errno.h>
#include <stddef.h>		/* ptrdiff_t */
#include <string.h>		/* memmove */

#ifdef HAVE_STDINT_H
#  include <stdint.h>		/* 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);
}