OSDN Git Service

Fix bug 4994 hangs on read(). I have tested the patch extensibly on ARM/LT.old.
[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
19 /* Experimentally off - 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                 __set_errno(ENOMEM);
35                 return NULL;
36 #endif
37         }
38
39 #ifdef __ARCH_USE_MMU__
40 # define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS
41 #else
42 # define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS
43 #endif
44
45         result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE,
46                       MMAP_FLAGS, 0, 0);
47         if (result == MAP_FAILED)
48                 return 0;
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 #if 0
68         /* Standard unix mmap using /dev/zero clears memory so calloc
69          * doesn't need to actually zero anything....
70          */
71         if (result != NULL) {
72                 memset(result, 0, size);
73         }
74 #endif
75         return result;
76 }
77 #endif
78
79 #ifdef L_realloc
80 void *realloc(void *ptr, size_t size)
81 {
82         void *newptr = NULL;
83
84         if (!ptr)
85                 return malloc(size);
86         if (!size) {
87                 free(ptr);
88                 return malloc(0);
89         }
90
91         newptr = malloc(size);
92         if (newptr) {
93                 size_t old_size = *((size_t *) (ptr - sizeof(size_t)));
94                 memcpy(newptr, ptr, (old_size < size ? old_size : size));
95                 free(ptr);
96         }
97         return newptr;
98 }
99 #endif
100
101 #ifdef L_free
102 extern int weak_function __libc_free_aligned(void *ptr);
103 void free(void *ptr)
104 {
105         if (unlikely(ptr == NULL))
106                 return;
107         if (unlikely(__libc_free_aligned != NULL)) {
108                 if (__libc_free_aligned(ptr))
109                         return;
110         }
111         ptr -= sizeof(size_t);
112         munmap(ptr, * (size_t *) ptr + sizeof(size_t));
113 }
114 #endif
115
116 #ifdef L_memalign
117
118 #include <bits/uClibc_mutex.h>
119 __UCLIBC_MUTEX_INIT(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
120 #define __MALLOC_LOCK           __UCLIBC_MUTEX_LOCK(__malloc_lock)
121 #define __MALLOC_UNLOCK         __UCLIBC_MUTEX_UNLOCK(__malloc_lock)
122
123 /* List of blocks allocated with memalign or valloc */
124 struct alignlist
125 {
126         struct alignlist *next;
127         __ptr_t aligned;        /* The address that memaligned returned.  */
128         __ptr_t exact;  /* The address that malloc returned.  */
129 };
130 struct alignlist *_aligned_blocks;
131
132 /* Return memory to the heap. */
133 int __libc_free_aligned(void *ptr)
134 {
135         struct alignlist *l;
136
137         if (ptr == NULL)
138                 return 0;
139
140         __MALLOC_LOCK;
141         for (l = _aligned_blocks; l != NULL; l = l->next) {
142                 if (l->aligned == ptr) {
143                         /* Mark the block as free */
144                         l->aligned = NULL;
145                         ptr = l->exact;
146                         ptr -= sizeof(size_t);
147                         munmap(ptr, * (size_t *) ptr + sizeof(size_t));
148                         return 1;
149                 }
150         }
151         __MALLOC_UNLOCK;
152         return 0;
153 }
154 void * memalign (size_t alignment, size_t size)
155 {
156         void * result;
157         unsigned long int adj;
158
159         result = malloc (size + alignment - 1);
160         if (result == NULL)
161                 return NULL;
162
163         adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % alignment;
164         if (adj != 0) {
165                 struct alignlist *l;
166                 __MALLOC_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                                 result = NULL;
176                                 goto DONE;
177                         }
178                         l->next = _aligned_blocks;
179                         _aligned_blocks = l;
180                 }
181                 l->exact = result;
182                 result = l->aligned = (char *) result + alignment - adj;
183 DONE:
184                 __MALLOC_UNLOCK;
185         }
186
187         return result;
188 }
189 #endif