OSDN Git Service

- pull in prototype for memalign()
[uclinux-h8/uclibc-ng.git] / libc / stdlib / malloc-simple / alloc.c
1 /* alloc.c
2  *
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7 /*
8  * Parts of the memalign code were stolen from malloc-930716.
9  */
10
11 #include <features.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <sys/mman.h>
18 #include <malloc.h>
19
20 /* Experimentally off - libc_hidden_proto(memcpy) */
21 /*libc_hidden_proto(memset)*/
22 libc_hidden_proto(mmap)
23 libc_hidden_proto(munmap)
24
25 #ifdef L_malloc
26 void *malloc(size_t size)
27 {
28         void *result;
29
30         if (unlikely(size == 0)) {
31 #if defined(__MALLOC_GLIBC_COMPAT__)
32                 size++;
33 #else
34                 /* Some programs will call malloc (0).  Lets be strict and return NULL */
35                 __set_errno(ENOMEM);
36                 return NULL;
37 #endif
38         }
39
40 #ifdef __ARCH_USE_MMU__
41 # define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS
42 #else
43 # define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS
44 #endif
45
46         result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE,
47                       MMAP_FLAGS, 0, 0);
48         if (result == MAP_FAILED)
49                 return 0;
50         * (size_t *) result = size;
51         return(result + sizeof(size_t));
52 }
53 #endif
54
55 #ifdef L_calloc
56 void * calloc(size_t nmemb, size_t lsize)
57 {
58         void *result;
59         size_t size=lsize * nmemb;
60
61         /* guard vs integer overflow, but allow nmemb
62          * to fall through and call malloc(0) */
63         if (nmemb && lsize != (size / nmemb)) {
64                 __set_errno(ENOMEM);
65                 return NULL;
66         }
67         result=malloc(size);
68 #if 0
69         /* Standard unix mmap using /dev/zero clears memory so calloc
70          * doesn't need to actually zero anything....
71          */
72         if (result != NULL) {
73                 memset(result, 0, size);
74         }
75 #endif
76         return result;
77 }
78 #endif
79
80 #ifdef L_realloc
81 void *realloc(void *ptr, size_t size)
82 {
83         void *newptr = NULL;
84
85         if (!ptr)
86                 return malloc(size);
87         if (!size) {
88                 free(ptr);
89                 return malloc(0);
90         }
91
92         newptr = malloc(size);
93         if (newptr) {
94                 size_t old_size = *((size_t *) (ptr - sizeof(size_t)));
95                 memcpy(newptr, ptr, (old_size < size ? old_size : size));
96                 free(ptr);
97         }
98         return newptr;
99 }
100 #endif
101
102 #ifdef L_free
103 extern int weak_function __libc_free_aligned(void *ptr);
104 void free(void *ptr)
105 {
106         if (unlikely(ptr == NULL))
107                 return;
108         if (unlikely(__libc_free_aligned != NULL)) {
109                 if (__libc_free_aligned(ptr))
110                         return;
111         }
112         ptr -= sizeof(size_t);
113         munmap(ptr, * (size_t *) ptr + sizeof(size_t));
114 }
115 #endif
116
117 #ifdef L_memalign
118
119 #include <bits/uClibc_mutex.h>
120 __UCLIBC_MUTEX_INIT(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
121 #define __MALLOC_LOCK           __UCLIBC_MUTEX_LOCK(__malloc_lock)
122 #define __MALLOC_UNLOCK         __UCLIBC_MUTEX_UNLOCK(__malloc_lock)
123
124 /* List of blocks allocated with memalign or valloc */
125 struct alignlist
126 {
127         struct alignlist *next;
128         __ptr_t aligned;        /* The address that memaligned returned.  */
129         __ptr_t exact;  /* The address that malloc returned.  */
130 };
131 struct alignlist *_aligned_blocks;
132
133 /* Return memory to the heap. */
134 int __libc_free_aligned(void *ptr)
135 {
136         struct alignlist *l;
137
138         if (ptr == NULL)
139                 return 0;
140
141         __MALLOC_LOCK;
142         for (l = _aligned_blocks; l != NULL; l = l->next) {
143                 if (l->aligned == ptr) {
144                         /* Mark the block as free */
145                         l->aligned = NULL;
146                         ptr = l->exact;
147                         ptr -= sizeof(size_t);
148                         munmap(ptr, * (size_t *) ptr + sizeof(size_t));
149                         return 1;
150                 }
151         }
152         __MALLOC_UNLOCK;
153         return 0;
154 }
155 void * memalign (size_t alignment, size_t size)
156 {
157         void * result;
158         unsigned long int adj;
159
160         result = malloc (size + alignment - 1);
161         if (result == NULL)
162                 return NULL;
163
164         adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % alignment;
165         if (adj != 0) {
166                 struct alignlist *l;
167                 __MALLOC_LOCK;
168                 for (l = _aligned_blocks; l != NULL; l = l->next)
169                         if (l->aligned == NULL)
170                                 /* This slot is free.  Use it.  */
171                                 break;
172                 if (l == NULL) {
173                         l = (struct alignlist *) malloc (sizeof (struct alignlist));
174                         if (l == NULL) {
175                                 free(result);
176                                 result = NULL;
177                                 goto DONE;
178                         }
179                         l->next = _aligned_blocks;
180                         _aligned_blocks = l;
181                 }
182                 l->exact = result;
183                 result = l->aligned = (char *) result + alignment - adj;
184 DONE:
185                 __MALLOC_UNLOCK;
186         }
187
188         return result;
189 }
190 #endif