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
index 79ea177..5951425 100644 (file)
+/* alloc.c
+ *
+ * Written by Erik Andersen <andersee@codepoet.org>
+ * LGPLv2
+ *
+ * Parts of the memalign code were stolen from malloc-930716.
+ */
+
+#define _GNU_SOURCE
 #include <features.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/mman.h>
 
+libc_hidden_proto(memcpy)
+/*libc_hidden_proto(memset)*/
+libc_hidden_proto(mmap)
+libc_hidden_proto(munmap)
 
-#ifdef L_calloc_dbg
-
-void *calloc_dbg(size_t num, size_t size, char *function, char *file,
-                                int line)
-{
-       void *ptr;
-
-       fprintf(stderr, "calloc of %d bytes at %s @%s:%d = ", (int) (num * size),
-                       function, file, line);
-       ptr = calloc(num, size);
-       fprintf(stderr, "%p\n", ptr);
-       return ptr;
-}
-
-#endif
-
-#ifdef L_malloc_dbg
-
-void *malloc_dbg(size_t size, char *function, char *file, int line)
+#ifdef L_malloc
+void *malloc(size_t size)
 {
        void *result;
 
-       fprintf(stderr, "malloc of %d bytes at %s @%s:%d = ", (int) size, function,
-                       file, line);
-       result = malloc(size);
-       fprintf(stderr, "%p\n", result);
-       return result;
-}
-
+       if (unlikely(size == 0)) {
+#if defined(__MALLOC_GLIBC_COMPAT__)
+               size++;
+#else
+               /* Some programs will call malloc (0).  Lets be strict and return NULL */
+               return 0;
 #endif
+       }
 
-#ifdef L_free_dbg
+#ifdef __ARCH_HAS_MMU__
+# define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS
+#else
+# define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS
+#endif
 
-void free_dbg(void *ptr, char *function, char *file, int line)
-{
-       fprintf(stderr, "free of %p at %s @%s:%d\n", ptr, function, file,
-                       line);
-       free(ptr);
+       result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE,
+                     MMAP_FLAGS, 0, 0);
+       if (result == MAP_FAILED)
+               return 0;
+       * (size_t *) result = size;
+       return(result + sizeof(size_t));
 }
-
 #endif
 
-
 #ifdef L_calloc
-
-void *calloc(size_t num, size_t size)
+void * calloc(size_t nmemb, size_t lsize)
 {
-       void *ptr = malloc(num * size);
+       void *result;
+       size_t size=lsize * nmemb;
 
-       if (ptr)
-               memset(ptr, 0, num * size);
-       return ptr;
+       /* guard vs integer overflow, but allow nmemb
+        * to fall through and call malloc(0) */
+       if (nmemb && lsize != (size / nmemb)) {
+               __set_errno(ENOMEM);
+               return NULL;
+       }
+       result=malloc(size);
+#if 0
+       /* Standard unix mmap using /dev/zero clears memory so calloc
+        * doesn't need to actually zero anything....
+        */
+       if (result != NULL) {
+               memset(result, 0, size);
+       }
+#endif
+       return result;
 }
-
 #endif
 
-#ifdef L_malloc
-
-void *malloc(size_t size)
+#ifdef L_realloc
+void *realloc(void *ptr, size_t size)
 {
-       void *result;
-#if 1
-    /* Some programs will call malloc (0).  Lets be strict and return NULL */
-    if (size == 0)
-       return NULL;
-#endif
-       result = mmap((void *) 0, size, PROT_READ | PROT_WRITE,
-#ifdef __UCLIBC_HAS_MMU__
-                                               MAP_PRIVATE | MAP_ANONYMOUS, 0, 0
-#else
-                                               MAP_SHARED | MAP_ANONYMOUS, 0, 0
-#endif
-                                                   );
+       void *newptr = NULL;
 
-       if (result == MAP_FAILED)
-               return 0;
+       if (!ptr)
+               return malloc(size);
+       if (!size) {
+               free(ptr);
+               return malloc(0);
+       }
 
-       return result;
+       newptr = malloc(size);
+       if (newptr) {
+               memcpy(newptr, ptr, *((size_t *) (ptr - sizeof(size_t))));
+               free(ptr);
+       }
+       return newptr;
 }
-
 #endif
 
 #ifdef L_free
-
+extern int weak_function __libc_free_aligned(void *ptr);
 void free(void *ptr)
 {
-       munmap(ptr, 0);
+       if (unlikely(ptr == NULL))
+               return;
+       if (unlikely(__libc_free_aligned != NULL)) {
+               if (__libc_free_aligned(ptr))
+                       return;
+       }
+       ptr -= sizeof(size_t);
+       munmap(ptr, * (size_t *) ptr + sizeof(size_t));
 }
-
 #endif
 
-#ifdef L_realloc
+#ifdef L_memalign
+#ifdef __UCLIBC_HAS_THREADS__
+# include <pthread.h>
+pthread_mutex_t __malloc_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+#endif
+#define LOCK   __pthread_mutex_lock(&__malloc_lock)
+#define UNLOCK __pthread_mutex_unlock(&__malloc_lock)
 
-void *realloc(void *ptr, size_t size)
+/* List of blocks allocated with memalign or valloc */
+struct alignlist
 {
-       void *newptr = NULL;
+       struct alignlist *next;
+       __ptr_t aligned;        /* The address that memaligned returned.  */
+       __ptr_t exact;  /* The address that malloc returned.  */
+};
+struct alignlist *_aligned_blocks;
+
+/* Return memory to the heap. */
+int __libc_free_aligned(void *ptr)
+{
+       struct alignlist *l;
+
+       if (ptr == NULL)
+               return 0;
 
-       if (size > 0) {
-               newptr = malloc(size);
-               if (newptr && ptr) {
-                       memcpy(newptr, ptr, size);
-                       free(ptr);
+       LOCK;
+       for (l = _aligned_blocks; l != NULL; l = l->next) {
+               if (l->aligned == ptr) {
+                       /* Mark the block as free */
+                       l->aligned = NULL;
+                       ptr = l->exact;
+                       ptr -= sizeof(size_t);
+                       munmap(ptr, * (size_t *) ptr + sizeof(size_t));
+                       return 1;
                }
        }
-       else
-               free(ptr);
-       return newptr;
+       UNLOCK;
+       return 0;
 }
+void * memalign (size_t alignment, size_t size)
+{
+       void * result;
+       unsigned long int adj;
+
+       result = malloc (size + alignment - 1);
+       if (result == NULL)
+               return NULL;
+
+       adj = (unsigned long int) ((unsigned long int) ((char *) result -
+             (char *) NULL)) % alignment;
+       if (adj != 0) {
+               struct alignlist *l;
+               LOCK;
+               for (l = _aligned_blocks; l != NULL; l = l->next)
+                       if (l->aligned == NULL)
+                               /* This slot is free.  Use it.  */
+                               break;
+               if (l == NULL) {
+                       l = (struct alignlist *) malloc (sizeof (struct alignlist));
+                       if (l == NULL) {
+                               free(result);
+                               UNLOCK;
+                               return NULL;
+                       }
+                       l->next = _aligned_blocks;
+                       _aligned_blocks = l;
+               }
+               l->exact = result;
+               result = l->aligned = (char *) result + alignment - adj;
+               UNLOCK;
+       }
 
+       return result;
+}
 #endif