(run-python): Remove '' from sys.path.
[bpt/emacs.git] / src / gmalloc.c
index 3f32617..1cf9a8e 100644 (file)
@@ -37,6 +37,10 @@ Fifth Floor, Boston, MA 02110-1301, USA.
 #include <config.h>
 #endif
 
+#ifdef HAVE_GTK_AND_PTHREAD
+#define USE_PTHREAD
+#endif
+
 #if ((defined __cplusplus || (defined (__STDC__) && __STDC__) \
       || defined STDC_HEADERS || defined PROTOTYPES) \
      && ! defined (BROKEN_PROTOTYPES))
@@ -73,6 +77,10 @@ Fifth Floor, Boston, MA 02110-1301, USA.
 #include <unistd.h>
 #endif
 
+#ifdef USE_PTHREAD
+#include <pthread.h>
+#endif
+
 #endif /* _MALLOC_INTERNAL.  */
 
 
@@ -102,10 +110,6 @@ extern "C"
 #define        NULL    0
 #endif
 
-#ifndef FREE_RETURN_TYPE
-#define FREE_RETURN_TYPE void
-#endif
-
 
 /* Allocate SIZE bytes of memory.  */
 extern __ptr_t malloc PP ((__malloc_size_t __size));
@@ -115,12 +119,14 @@ extern __ptr_t realloc PP ((__ptr_t __ptr, __malloc_size_t __size));
 /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
 extern __ptr_t calloc PP ((__malloc_size_t __nmemb, __malloc_size_t __size));
 /* Free a block allocated by `malloc', `realloc' or `calloc'.  */
-extern FREE_RETURN_TYPE free PP ((__ptr_t __ptr));
+extern void free PP ((__ptr_t __ptr));
 
 /* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
 #if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict.  */
 extern __ptr_t memalign PP ((__malloc_size_t __alignment,
                             __malloc_size_t __size));
+extern int posix_memalign PP ((__ptr_t *, __malloc_size_t,
+                              __malloc_size_t size));
 #endif
 
 /* Allocate SIZE bytes on a page boundary.  */
@@ -128,6 +134,10 @@ extern __ptr_t memalign PP ((__malloc_size_t __alignment,
 extern __ptr_t valloc PP ((__malloc_size_t __size));
 #endif
 
+#ifdef USE_PTHREAD
+/* Set up mutexes and make malloc etc. thread-safe.  */
+extern void malloc_enable_thread PP ((void));
+#endif
 
 #ifdef _MALLOC_INTERNAL
 
@@ -228,6 +238,39 @@ extern __malloc_size_t _bytes_free;
 extern __ptr_t _malloc_internal PP ((__malloc_size_t __size));
 extern __ptr_t _realloc_internal PP ((__ptr_t __ptr, __malloc_size_t __size));
 extern void _free_internal PP ((__ptr_t __ptr));
+extern __ptr_t _malloc_internal_nolock PP ((__malloc_size_t __size));
+extern __ptr_t _realloc_internal_nolock PP ((__ptr_t __ptr, __malloc_size_t __size));
+extern void _free_internal_nolock PP ((__ptr_t __ptr));
+
+#ifdef USE_PTHREAD
+extern pthread_mutex_t _malloc_mutex, _aligned_blocks_mutex;
+extern int _malloc_thread_enabled_p;
+#define LOCK()                                 \
+  do {                                         \
+    if (_malloc_thread_enabled_p)              \
+      pthread_mutex_lock (&_malloc_mutex);     \
+  } while (0)
+#define UNLOCK()                               \
+  do {                                         \
+    if (_malloc_thread_enabled_p)              \
+      pthread_mutex_unlock (&_malloc_mutex);   \
+  } while (0)
+#define LOCK_ALIGNED_BLOCKS()                          \
+  do {                                                 \
+    if (_malloc_thread_enabled_p)                      \
+      pthread_mutex_lock (&_aligned_blocks_mutex);     \
+  } while (0)
+#define UNLOCK_ALIGNED_BLOCKS()                                \
+  do {                                                 \
+    if (_malloc_thread_enabled_p)                      \
+      pthread_mutex_unlock (&_aligned_blocks_mutex);   \
+  } while (0)
+#else
+#define LOCK()
+#define UNLOCK()
+#define LOCK_ALIGNED_BLOCKS()
+#define UNLOCK_ALIGNED_BLOCKS()
+#endif
 
 #endif /* _MALLOC_INTERNAL.  */
 
@@ -357,7 +400,7 @@ Fifth Floor, Boston, MA 02110-1301, USA.
 extern __ptr_t bss_sbrk PP ((ptrdiff_t __size));
 extern int bss_sbrk_did_unexec;
 #endif
-__ptr_t (*__morecore) PP ((ptrdiff_t __size)) = __default_morecore;
+__ptr_t (*__morecore) PP ((__malloc_ptrdiff_t __size)) = __default_morecore;
 
 /* Debugging hook for `malloc'.  */
 __ptr_t (*__malloc_hook) PP ((__malloc_size_t __size));
@@ -536,13 +579,55 @@ register_heapinfo ()
     _heapinfo[block + blocks].busy.info.size = -blocks;
 }
 
-/* Set everything up and remember that we have.  */
-int
-__malloc_initialize ()
+#ifdef USE_PTHREAD
+pthread_mutex_t _malloc_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _aligned_blocks_mutex = PTHREAD_MUTEX_INITIALIZER;
+int _malloc_thread_enabled_p;
+
+static void
+malloc_atfork_handler_prepare ()
 {
-  if (__malloc_initialized)
-    return 0;
+  LOCK ();
+  LOCK_ALIGNED_BLOCKS ();
+}
+
+static void
+malloc_atfork_handler_parent ()
+{
+  UNLOCK_ALIGNED_BLOCKS ();
+  UNLOCK ();
+}
+
+static void
+malloc_atfork_handler_child ()
+{
+  UNLOCK_ALIGNED_BLOCKS ();
+  UNLOCK ();
+}
+
+/* Set up mutexes and make malloc etc. thread-safe.  */
+void
+malloc_enable_thread ()
+{
+  if (_malloc_thread_enabled_p)
+    return;
 
+  /* Some pthread implementations call malloc for statically
+     initialized mutexes when they are used first.  To avoid such a
+     situation, we initialize mutexes here while their use is
+     disabled in malloc etc.  */
+  pthread_mutex_init (&_malloc_mutex, NULL);
+  pthread_mutex_init (&_aligned_blocks_mutex, NULL);
+  pthread_atfork (malloc_atfork_handler_prepare,
+                 malloc_atfork_handler_parent,
+                 malloc_atfork_handler_child);
+  _malloc_thread_enabled_p = 1;
+}
+#endif
+
+static void
+malloc_initialize_1 ()
+{
 #ifdef GC_MCHECK
   mcheck (NULL);
 #endif
@@ -553,7 +638,7 @@ __malloc_initialize ()
   heapsize = HEAP / BLOCKSIZE;
   _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
   if (_heapinfo == NULL)
-    return 0;
+    return;
   memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
   _heapinfo[0].free.size = 0;
   _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
@@ -565,16 +650,30 @@ __malloc_initialize ()
 
   __malloc_initialized = 1;
   PROTECT_MALLOC_STATE (1);
-  return 1;
+  return;
+}
+
+/* Set everything up and remember that we have.
+   main will call malloc which calls this function.  That is before any threads
+   or signal handlers has been set up, so we don't need thread protection.  */
+int
+__malloc_initialize ()
+{
+  if (__malloc_initialized)
+    return 0;
+
+  malloc_initialize_1 ();
+
+  return __malloc_initialized;
 }
 
 static int morecore_recursing;
 
 /* Get neatly aligned memory, initializing or
    growing the heap info table as necessary. */
-static __ptr_t morecore PP ((__malloc_size_t));
+static __ptr_t morecore_nolock PP ((__malloc_size_t));
 static __ptr_t
-morecore (size)
+morecore_nolock (size)
      __malloc_size_t size;
 {
   __ptr_t result;
@@ -617,7 +716,7 @@ morecore (size)
             `morecore_recursing' flag and return null.  */
          int save = errno;     /* Don't want to clobber errno with ENOMEM.  */
          morecore_recursing = 1;
-         newinfo = (malloc_info *) _realloc_internal
+         newinfo = (malloc_info *) _realloc_internal_nolock
            (_heapinfo, newsize * sizeof (malloc_info));
          morecore_recursing = 0;
          if (newinfo == NULL)
@@ -673,7 +772,7 @@ morecore (size)
       /* Reset _heaplimit so _free_internal never decides
         it can relocate or resize the info table.  */
       _heaplimit = 0;
-      _free_internal (oldinfo);
+      _free_internal_nolock (oldinfo);
       PROTECT_MALLOC_STATE (0);
 
       /* The new heap limit includes the new table just allocated.  */
@@ -688,7 +787,7 @@ morecore (size)
 
 /* Allocate memory from the heap.  */
 __ptr_t
-_malloc_internal (size)
+_malloc_internal_nolock (size)
      __malloc_size_t size;
 {
   __ptr_t result;
@@ -713,11 +812,6 @@ _malloc_internal (size)
   if (size < sizeof (struct list))
     size = sizeof (struct list);
 
-#ifdef SUNOS_LOCALTIME_BUG
-  if (size < 16)
-    size = 16;
-#endif
-
   /* Determine the allocation policy based on the request size.  */
   if (size <= BLOCKSIZE / 2)
     {
@@ -757,15 +851,17 @@ _malloc_internal (size)
          /* No free fragments of the desired size, so get a new block
             and break it into fragments, returning the first.  */
 #ifdef GC_MALLOC_CHECK
-         result = _malloc_internal (BLOCKSIZE);
+         result = _malloc_internal_nolock (BLOCKSIZE);
          PROTECT_MALLOC_STATE (0);
+#elif defined (USE_PTHREAD)
+         result = _malloc_internal_nolock (BLOCKSIZE);
 #else
          result = malloc (BLOCKSIZE);
 #endif
          if (result == NULL)
            {
              PROTECT_MALLOC_STATE (1);
-             return NULL;
+             goto out;
            }
 
          /* Link all fragments but the first into the free list.  */
@@ -815,7 +911,7 @@ _malloc_internal (size)
                 final free block; if so we don't need to get as much.  */
              if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
                  /* We can't do this if we will have to make the heap info
-                     table bigger to accomodate the new space.  */
+                     table bigger to accommodate the new space.  */
                  block + wantblocks <= heapsize &&
                  get_contiguous_space ((wantblocks - lastblocks) * BLOCKSIZE,
                                        ADDRESS (block + lastblocks)))
@@ -829,9 +925,9 @@ _malloc_internal (size)
                  _heaplimit += wantblocks - lastblocks;
                  continue;
                }
-             result = morecore (wantblocks * BLOCKSIZE);
+             result = morecore_nolock (wantblocks * BLOCKSIZE);
              if (result == NULL)
-               return NULL;
+               goto out;
              block = BLOCK (result);
              /* Put the new block at the end of the free list.  */
              _heapinfo[block].free.size = wantblocks;
@@ -886,6 +982,20 @@ _malloc_internal (size)
     }
 
   PROTECT_MALLOC_STATE (1);
+ out:
+  return result;
+}
+
+__ptr_t
+_malloc_internal (size)
+     __malloc_size_t size;
+{
+  __ptr_t result;
+
+  LOCK ();
+  result = _malloc_internal_nolock (size);
+  UNLOCK ();
+
   return result;
 }
 
@@ -893,10 +1003,21 @@ __ptr_t
 malloc (size)
      __malloc_size_t size;
 {
+  __ptr_t (*hook) (__malloc_size_t);
+
   if (!__malloc_initialized && !__malloc_initialize ())
     return NULL;
 
-  return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size);
+  /* Copy the value of __malloc_hook to an automatic variable in case
+     __malloc_hook is modified in another thread between its
+     NULL-check and the use.
+
+     Note: Strictly speaking, this is not a right solution.  We should
+     use mutexes to access non-read-only variables that are shared
+     among multiple threads.  We just leave it for compatibility with
+     glibc malloc (i.e., assignments to __malloc_hook) for now.  */
+  hook = __malloc_hook;
+  return (hook != NULL ? *hook : _malloc_internal) (size);
 }
 \f
 #ifndef _LIBC
@@ -957,8 +1078,7 @@ Fifth Floor, Boston, MA 02110-1301, USA.
 
 /* Cope with systems lacking `memmove'.    */
 #ifndef memmove
-#if  (defined (MEMMOVE_MISSING) || \
-      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+#if  (!defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
 #ifdef emacs
 #undef __malloc_safe_bcopy
 #define __malloc_safe_bcopy safe_bcopy
@@ -977,9 +1097,9 @@ void (*__free_hook) PP ((__ptr_t __ptr));
 struct alignlist *_aligned_blocks = NULL;
 
 /* Return memory to the heap.
-   Like `free' but don't call a __free_hook if there is one.  */
+   Like `_free_internal' but don't lock mutex.  */
 void
-_free_internal (ptr)
+_free_internal_nolock (ptr)
      __ptr_t ptr;
 {
   int type;
@@ -998,6 +1118,7 @@ _free_internal (ptr)
 
   PROTECT_MALLOC_STATE (0);
 
+  LOCK_ALIGNED_BLOCKS ();
   for (l = _aligned_blocks; l != NULL; l = l->next)
     if (l->aligned == ptr)
       {
@@ -1005,6 +1126,7 @@ _free_internal (ptr)
        ptr = l->exact;
        break;
       }
+  UNLOCK_ALIGNED_BLOCKS ();
 
   block = BLOCK (ptr);
 
@@ -1110,7 +1232,7 @@ _free_internal (ptr)
                 table's blocks to the system before we have copied them to
                 the new location.  */
              _heaplimit = 0;
-             _free_internal (_heapinfo);
+             _free_internal_nolock (_heapinfo);
              _heaplimit = oldlimit;
 
              /* Tell malloc to search from the beginning of the heap for
@@ -1118,8 +1240,8 @@ _free_internal (ptr)
              _heapindex = 0;
 
              /* Allocate new space for the info table and move its data.  */
-             newinfo = (malloc_info *) _malloc_internal (info_blocks
-                                                         * BLOCKSIZE);
+             newinfo = (malloc_info *) _malloc_internal_nolock (info_blocks
+                                                                * BLOCKSIZE);
              PROTECT_MALLOC_STATE (0);
              memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE);
              _heapinfo = newinfo;
@@ -1182,8 +1304,8 @@ _free_internal (ptr)
          _chunks_free -= BLOCKSIZE >> type;
          _bytes_free -= BLOCKSIZE;
 
-#ifdef GC_MALLOC_CHECK
-         _free_internal (ADDRESS (block));
+#if defined (GC_MALLOC_CHECK) || defined (USE_PTHREAD)
+         _free_internal_nolock (ADDRESS (block));
 #else
          free (ADDRESS (block));
 #endif
@@ -1223,14 +1345,27 @@ _free_internal (ptr)
   PROTECT_MALLOC_STATE (1);
 }
 
+/* Return memory to the heap.
+   Like `free' but don't call a __free_hook if there is one.  */
+void
+_free_internal (ptr)
+     __ptr_t ptr;
+{
+  LOCK ();
+  _free_internal_nolock (ptr);
+  UNLOCK ();
+}
+
 /* Return memory to the heap.  */
 
-FREE_RETURN_TYPE
+void
 free (ptr)
      __ptr_t ptr;
 {
-  if (__free_hook != NULL)
-    (*__free_hook) (ptr);
+  void (*hook) (__ptr_t) = __free_hook;
+
+  if (hook != NULL)
+    (*hook) (ptr);
   else
     _free_internal (ptr);
 }
@@ -1276,8 +1411,7 @@ Fifth Floor, Boston, MA 02110-1301, USA.
 
 
 /* Cope with systems lacking `memmove'.    */
-#if  (defined (MEMMOVE_MISSING) || \
-      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+#if  (!defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
 
 #ifdef emacs
 #undef __malloc_safe_bcopy
@@ -1366,7 +1500,7 @@ __ptr_t (*__realloc_hook) PP ((__ptr_t __ptr, __malloc_size_t __size));
    new region.  This module has incestuous knowledge of the
    internals of both free and malloc. */
 __ptr_t
-_realloc_internal (ptr, size)
+_realloc_internal_nolock (ptr, size)
      __ptr_t ptr;
      __malloc_size_t size;
 {
@@ -1376,11 +1510,11 @@ _realloc_internal (ptr, size)
 
   if (size == 0)
     {
-      _free_internal (ptr);
-      return _malloc_internal (0);
+      _free_internal_nolock (ptr);
+      return _malloc_internal_nolock (0);
     }
   else if (ptr == NULL)
-    return _malloc_internal (size);
+    return _malloc_internal_nolock (size);
 
   block = BLOCK (ptr);
 
@@ -1393,12 +1527,12 @@ _realloc_internal (ptr, size)
       /* Maybe reallocate a large block to a small fragment.  */
       if (size <= BLOCKSIZE / 2)
        {
-         result = _malloc_internal (size);
+         result = _malloc_internal_nolock (size);
          if (result != NULL)
            {
              memcpy (result, ptr, size);
-             _free_internal (ptr);
-             return result;
+             _free_internal_nolock (ptr);
+             goto out;
            }
        }
 
@@ -1417,7 +1551,7 @@ _realloc_internal (ptr, size)
             Now we will free this chunk; increment the statistics counter
             so it doesn't become wrong when _free_internal decrements it.  */
          ++_chunks_used;
-         _free_internal (ADDRESS (block + blocks));
+         _free_internal_nolock (ADDRESS (block + blocks));
          result = ptr;
        }
       else if (blocks == _heapinfo[block].busy.info.size)
@@ -1432,8 +1566,8 @@ _realloc_internal (ptr, size)
          /* Prevent free from actually returning memory to the system.  */
          oldlimit = _heaplimit;
          _heaplimit = 0;
-         _free_internal (ptr);
-         result = _malloc_internal (size);
+         _free_internal_nolock (ptr);
+         result = _malloc_internal_nolock (size);
          PROTECT_MALLOC_STATE (0);
          if (_heaplimit == 0)
            _heaplimit = oldlimit;
@@ -1443,15 +1577,15 @@ _realloc_internal (ptr, size)
                 the thing we just freed.  Unfortunately it might
                 have been coalesced with its neighbors.  */
              if (_heapindex == block)
-               (void) _malloc_internal (blocks * BLOCKSIZE);
+               (void) _malloc_internal_nolock (blocks * BLOCKSIZE);
              else
                {
                  __ptr_t previous
-                   = _malloc_internal ((block - _heapindex) * BLOCKSIZE);
-                 (void) _malloc_internal (blocks * BLOCKSIZE);
-                 _free_internal (previous);
+                   = _malloc_internal_nolock ((block - _heapindex) * BLOCKSIZE);
+                 (void) _malloc_internal_nolock (blocks * BLOCKSIZE);
+                 _free_internal_nolock (previous);
                }
-             return NULL;
+             goto out;
            }
          if (ptr != result)
            memmove (result, ptr, blocks * BLOCKSIZE);
@@ -1469,16 +1603,31 @@ _realloc_internal (ptr, size)
        {
          /* The new size is different; allocate a new space,
             and copy the lesser of the new size and the old. */
-         result = _malloc_internal (size);
+         result = _malloc_internal_nolock (size);
          if (result == NULL)
-           return NULL;
+           goto out;
          memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type));
-         _free_internal (ptr);
+         _free_internal_nolock (ptr);
        }
       break;
     }
 
   PROTECT_MALLOC_STATE (1);
+ out:
+  return result;
+}
+
+__ptr_t
+_realloc_internal (ptr, size)
+     __ptr_t ptr;
+     __malloc_size_t size;
+{
+  __ptr_t result;
+
+  LOCK();
+  result = _realloc_internal_nolock (ptr, size);
+  UNLOCK ();
+
   return result;
 }
 
@@ -1487,11 +1636,13 @@ realloc (ptr, size)
      __ptr_t ptr;
      __malloc_size_t size;
 {
+  __ptr_t (*hook) (__ptr_t, __malloc_size_t);
+
   if (!__malloc_initialized && !__malloc_initialize ())
     return NULL;
 
-  return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal)
-    (ptr, size);
+  hook = __realloc_hook;
+  return (hook != NULL ? *hook : _realloc_internal) (ptr, size);
 }
 /* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc.
 
@@ -1629,9 +1780,10 @@ memalign (alignment, size)
 {
   __ptr_t result;
   unsigned long int adj, lastadj;
+  __ptr_t (*hook) (__malloc_size_t, __malloc_size_t) = __memalign_hook;
 
-  if (__memalign_hook)
-    return (*__memalign_hook) (alignment, size);
+  if (hook)
+    return (*hook) (alignment, size);
 
   /* Allocate a block with enough extra space to pad the block with up to
      (ALIGNMENT - 1) bytes if necessary.  */
@@ -1666,6 +1818,7 @@ memalign (alignment, size)
         of an allocated block.  */
 
       struct alignlist *l;
+      LOCK_ALIGNED_BLOCKS ();
       for (l = _aligned_blocks; l != NULL; l = l->next)
        if (l->aligned == NULL)
          /* This slot is free.  Use it.  */
@@ -1673,21 +1826,58 @@ memalign (alignment, size)
       if (l == NULL)
        {
          l = (struct alignlist *) malloc (sizeof (struct alignlist));
-         if (l == NULL)
+         if (l != NULL)
            {
-             free (result);
-             return NULL;
+             l->next = _aligned_blocks;
+             _aligned_blocks = l;
            }
-         l->next = _aligned_blocks;
-         _aligned_blocks = l;
        }
-      l->exact = result;
-      result = l->aligned = (char *) result + alignment - adj;
+      if (l != NULL)
+       {
+         l->exact = result;
+         result = l->aligned = (char *) result + alignment - adj;
+       }
+      UNLOCK_ALIGNED_BLOCKS ();
+      if (l == NULL)
+       {
+         free (result);
+         result = NULL;
+       }
     }
 
   return result;
 }
 
+#ifndef ENOMEM
+#define ENOMEM 12
+#endif
+
+#ifndef EINVAL
+#define EINVAL 22
+#endif
+
+int
+posix_memalign (memptr, alignment, size)
+     __ptr_t *memptr;
+     __malloc_size_t alignment;
+     __malloc_size_t size;
+{
+  __ptr_t mem;
+
+  if (alignment == 0
+      || alignment % sizeof (__ptr_t) != 0
+      || (alignment & (alignment - 1)) != 0)
+    return EINVAL;
+
+  mem = memalign (alignment, size);
+  if (mem == NULL)
+    return ENOMEM;
+
+  *memptr = mem;
+
+  return 0;
+}
+
 #endif /* Not DJGPP v1 */
 /* Allocate memory on a page boundary.
    Copyright (C) 1991, 92, 93, 94, 96 Free Software Foundation, Inc.