OSDN Git Service

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