OSDN Git Service

fix static linking of pthread apps
[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 extern int weak_function __libc_free_aligned(void *ptr) attribute_hidden;
21
22 #ifdef L_malloc
23 void *malloc(size_t size)
24 {
25         void *result;
26
27         if (unlikely(size == 0)) {
28 #if defined(__MALLOC_GLIBC_COMPAT__)
29                 size++;
30 #else
31                 /* Some programs will call malloc (0).  Lets be strict and return NULL */
32                 __set_errno(ENOMEM);
33                 return NULL;
34 #endif
35         }
36
37 #ifdef __ARCH_USE_MMU__
38 # define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS
39 #else
40 # define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS | MAP_UNINITIALIZED
41 #endif
42
43         result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE,
44                       MMAP_FLAGS, 0, 0);
45         if (result == MAP_FAILED) {
46                 __set_errno(ENOMEM);
47                 return 0;
48         }
49         * (size_t *) result = size;
50         return(result + sizeof(size_t));
51 }
52 #endif
53
54 #ifdef L_calloc
55 void * calloc(size_t nmemb, size_t lsize)
56 {
57         void *result;
58         size_t size=lsize * nmemb;
59
60         /* guard vs integer overflow, but allow nmemb
61          * to fall through and call malloc(0) */
62         if (nmemb && lsize != (size / nmemb)) {
63                 __set_errno(ENOMEM);
64                 return NULL;
65         }
66         result = malloc(size);
67
68 #ifndef __ARCH_USE_MMU__
69         /* mmap'd with MAP_UNINITIALIZED, we have to blank memory ourselves */
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                 size_t old_size = *((size_t *) (ptr - sizeof(size_t)));
93                 memcpy(newptr, ptr, (old_size < size ? old_size : size));
94                 free(ptr);
95         }
96         return newptr;
97 }
98 #endif
99
100 #ifdef L_free
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
116 #include <bits/uClibc_mutex.h>
117 __UCLIBC_MUTEX_INIT(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
118 #define __MALLOC_LOCK           __UCLIBC_MUTEX_LOCK(__malloc_lock)
119 #define __MALLOC_UNLOCK         __UCLIBC_MUTEX_UNLOCK(__malloc_lock)
120
121 /* List of blocks allocated with memalign or valloc */
122 struct alignlist
123 {
124         struct alignlist *next;
125         __ptr_t aligned;        /* The address that memaligned returned.  */
126         __ptr_t exact;  /* The address that malloc returned.  */
127 };
128 static struct alignlist *_aligned_blocks;
129
130 /* Return memory to the heap. */
131 int __libc_free_aligned(void *ptr)
132 {
133         struct alignlist *l;
134
135         if (ptr == NULL)
136                 return 0;
137
138         __MALLOC_LOCK;
139         for (l = _aligned_blocks; l != NULL; l = l->next) {
140                 if (l->aligned == ptr) {
141                         /* Mark the block as free */
142                         l->aligned = NULL;
143                         ptr = l->exact;
144                         ptr -= sizeof(size_t);
145                         munmap(ptr, * (size_t *) ptr + sizeof(size_t));
146                         return 1;
147                 }
148         }
149         __MALLOC_UNLOCK;
150         return 0;
151 }
152 void * memalign (size_t alignment, size_t size)
153 {
154         void * result;
155         unsigned long int adj;
156
157         result = malloc (size + alignment - 1);
158         if (result == NULL)
159                 return NULL;
160
161         adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % alignment;
162         if (adj != 0) {
163                 struct alignlist *l;
164                 __MALLOC_LOCK;
165                 for (l = _aligned_blocks; l != NULL; l = l->next)
166                         if (l->aligned == NULL)
167                                 /* This slot is free.  Use it.  */
168                                 break;
169                 if (l == NULL) {
170                         l = (struct alignlist *) malloc (sizeof (struct alignlist));
171                         if (l == NULL) {
172                                 free(result);
173                                 result = NULL;
174                                 goto DONE;
175                         }
176                         l->next = _aligned_blocks;
177                         _aligned_blocks = l;
178                 }
179                 l->exact = result;
180                 result = l->aligned = (char *) result + alignment - adj;
181 DONE:
182                 __MALLOC_UNLOCK;
183         }
184
185         return result;
186 }
187 libc_hidden_def(memalign)
188 #endif