diff options
Diffstat (limited to 'src/gmalloc.c')
| -rw-r--r-- | src/gmalloc.c | 237 |
1 files changed, 154 insertions, 83 deletions
diff --git a/src/gmalloc.c b/src/gmalloc.c index 27965e37539..3456ff0ec6f 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c | |||
| @@ -21,13 +21,18 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
| 21 | 21 | ||
| 22 | #include <config.h> | 22 | #include <config.h> |
| 23 | 23 | ||
| 24 | #ifdef HAVE_PTHREAD | 24 | #if defined HAVE_PTHREAD && !defined HYBRID_MALLOC |
| 25 | #define USE_PTHREAD | 25 | #define USE_PTHREAD |
| 26 | #endif | 26 | #endif |
| 27 | 27 | ||
| 28 | #include <string.h> | 28 | #include <string.h> |
| 29 | #include <limits.h> | 29 | #include <limits.h> |
| 30 | #include <stdint.h> | 30 | #include <stdint.h> |
| 31 | |||
| 32 | #ifdef HYBRID_GET_CURRENT_DIR_NAME | ||
| 33 | #undef get_current_dir_name | ||
| 34 | #endif | ||
| 35 | |||
| 31 | #include <unistd.h> | 36 | #include <unistd.h> |
| 32 | 37 | ||
| 33 | #ifdef USE_PTHREAD | 38 | #ifdef USE_PTHREAD |
| @@ -42,6 +47,41 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
| 42 | extern void emacs_abort (void); | 47 | extern void emacs_abort (void); |
| 43 | #endif | 48 | #endif |
| 44 | 49 | ||
| 50 | /* If HYBRID_MALLOC is defined, then temacs will use malloc, | ||
| 51 | realloc... as defined in this file (and renamed gmalloc, | ||
| 52 | grealloc... via the macros that follow). The dumped emacs, | ||
| 53 | however, will use the system malloc, realloc.... In other source | ||
| 54 | files, malloc, realloc... are renamed hybrid_malloc, | ||
| 55 | hybrid_realloc... via macros in conf_post.h. hybrid_malloc and | ||
| 56 | friends are wrapper functions defined later in this file. | ||
| 57 | aligned_alloc is defined as a macro only in alloc.c. | ||
| 58 | |||
| 59 | As of this writing (August 2014), Cygwin is the only platform on | ||
| 60 | which HYBRID_MACRO is defined. Any other platform that wants to | ||
| 61 | define it will have to define the macros DUMPED and | ||
| 62 | ALLOCATED_BEFORE_DUMPING, defined below for Cygwin. */ | ||
| 63 | #ifdef HYBRID_MALLOC | ||
| 64 | #undef malloc | ||
| 65 | #undef realloc | ||
| 66 | #undef calloc | ||
| 67 | #undef free | ||
| 68 | #define malloc gmalloc | ||
| 69 | #define realloc grealloc | ||
| 70 | #define calloc gcalloc | ||
| 71 | #define aligned_alloc galigned_alloc | ||
| 72 | #define free gfree | ||
| 73 | #endif /* HYBRID_MALLOC */ | ||
| 74 | |||
| 75 | #ifdef CYGWIN | ||
| 76 | extern void *bss_sbrk (ptrdiff_t size); | ||
| 77 | extern int bss_sbrk_did_unexec; | ||
| 78 | extern char bss_sbrk_buffer[]; | ||
| 79 | extern void *bss_sbrk_buffer_end; | ||
| 80 | #define DUMPED bss_sbrk_did_unexec | ||
| 81 | #define ALLOCATED_BEFORE_DUMPING(P) \ | ||
| 82 | ((P) < bss_sbrk_buffer_end && (P) >= (void *) bss_sbrk_buffer) | ||
| 83 | #endif | ||
| 84 | |||
| 45 | #ifdef __cplusplus | 85 | #ifdef __cplusplus |
| 46 | extern "C" | 86 | extern "C" |
| 47 | { | 87 | { |
| @@ -306,22 +346,6 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
| 306 | 346 | ||
| 307 | #include <errno.h> | 347 | #include <errno.h> |
| 308 | 348 | ||
| 309 | /* On Cygwin there are two heaps. temacs uses the static heap | ||
| 310 | (defined in sheap.c and managed with bss_sbrk), and the dumped | ||
| 311 | emacs uses the Cygwin heap (managed with sbrk). When emacs starts | ||
| 312 | on Cygwin, it reinitializes malloc, and we save the old info for | ||
| 313 | use by free and realloc if they're called with a pointer into the | ||
| 314 | static heap. | ||
| 315 | |||
| 316 | Currently (2011-08-16) the Cygwin build doesn't use ralloc.c; if | ||
| 317 | this is changed in the future, we'll have to similarly deal with | ||
| 318 | reinitializing ralloc. */ | ||
| 319 | #ifdef CYGWIN | ||
| 320 | extern void *bss_sbrk (ptrdiff_t size); | ||
| 321 | extern int bss_sbrk_did_unexec; | ||
| 322 | char *bss_sbrk_heapbase; /* _heapbase for static heap */ | ||
| 323 | malloc_info *bss_sbrk_heapinfo; /* _heapinfo for static heap */ | ||
| 324 | #endif | ||
| 325 | void *(*__morecore) (ptrdiff_t size) = __default_morecore; | 349 | void *(*__morecore) (ptrdiff_t size) = __default_morecore; |
| 326 | 350 | ||
| 327 | /* Debugging hook for `malloc'. */ | 351 | /* Debugging hook for `malloc'. */ |
| @@ -490,18 +514,8 @@ register_heapinfo (void) | |||
| 490 | } | 514 | } |
| 491 | 515 | ||
| 492 | #ifdef USE_PTHREAD | 516 | #ifdef USE_PTHREAD |
| 493 | /* On Cygwin prior to 1.7.31, pthread_mutexes were ERRORCHECK mutexes | ||
| 494 | by default. When the default changed to NORMAL in Cygwin-1.7.31, | ||
| 495 | deadlocks occurred (bug#18222). As a temporary workaround, we | ||
| 496 | explicitly set the mutexes to be of ERRORCHECK type, restoring the | ||
| 497 | previous behavior. */ | ||
| 498 | #ifdef CYGWIN | ||
| 499 | pthread_mutex_t _malloc_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; | ||
| 500 | pthread_mutex_t _aligned_blocks_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; | ||
| 501 | #else /* not CYGWIN */ | ||
| 502 | pthread_mutex_t _malloc_mutex = PTHREAD_MUTEX_INITIALIZER; | 517 | pthread_mutex_t _malloc_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 503 | pthread_mutex_t _aligned_blocks_mutex = PTHREAD_MUTEX_INITIALIZER; | 518 | pthread_mutex_t _aligned_blocks_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 504 | #endif /* not CYGWIN */ | ||
| 505 | int _malloc_thread_enabled_p; | 519 | int _malloc_thread_enabled_p; |
| 506 | 520 | ||
| 507 | static void | 521 | static void |
| @@ -536,17 +550,8 @@ malloc_enable_thread (void) | |||
| 536 | initialized mutexes when they are used first. To avoid such a | 550 | initialized mutexes when they are used first. To avoid such a |
| 537 | situation, we initialize mutexes here while their use is | 551 | situation, we initialize mutexes here while their use is |
| 538 | disabled in malloc etc. */ | 552 | disabled in malloc etc. */ |
| 539 | #ifdef CYGWIN | ||
| 540 | /* Use ERRORCHECK mutexes; see comment above. */ | ||
| 541 | pthread_mutexattr_t attr; | ||
| 542 | pthread_mutexattr_init (&attr); | ||
| 543 | pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); | ||
| 544 | pthread_mutex_init (&_malloc_mutex, &attr); | ||
| 545 | pthread_mutex_init (&_aligned_blocks_mutex, &attr); | ||
| 546 | #else /* not CYGWIN */ | ||
| 547 | pthread_mutex_init (&_malloc_mutex, NULL); | 553 | pthread_mutex_init (&_malloc_mutex, NULL); |
| 548 | pthread_mutex_init (&_aligned_blocks_mutex, NULL); | 554 | pthread_mutex_init (&_aligned_blocks_mutex, NULL); |
| 549 | #endif /* not CYGWIN */ | ||
| 550 | pthread_atfork (malloc_atfork_handler_prepare, | 555 | pthread_atfork (malloc_atfork_handler_prepare, |
| 551 | malloc_atfork_handler_parent, | 556 | malloc_atfork_handler_parent, |
| 552 | malloc_atfork_handler_child); | 557 | malloc_atfork_handler_child); |
| @@ -561,16 +566,6 @@ malloc_initialize_1 (void) | |||
| 561 | mcheck (NULL); | 566 | mcheck (NULL); |
| 562 | #endif | 567 | #endif |
| 563 | 568 | ||
| 564 | #ifdef CYGWIN | ||
| 565 | if (bss_sbrk_did_unexec) | ||
| 566 | /* we're reinitializing the dumped emacs */ | ||
| 567 | { | ||
| 568 | bss_sbrk_heapbase = _heapbase; | ||
| 569 | bss_sbrk_heapinfo = _heapinfo; | ||
| 570 | memset (_fraghead, 0, BLOCKLOG * sizeof (struct list)); | ||
| 571 | } | ||
| 572 | #endif | ||
| 573 | |||
| 574 | if (__malloc_initialize_hook) | 569 | if (__malloc_initialize_hook) |
| 575 | (*__malloc_initialize_hook) (); | 570 | (*__malloc_initialize_hook) (); |
| 576 | 571 | ||
| @@ -1027,12 +1022,6 @@ _free_internal_nolock (void *ptr) | |||
| 1027 | if (ptr == NULL) | 1022 | if (ptr == NULL) |
| 1028 | return; | 1023 | return; |
| 1029 | 1024 | ||
| 1030 | #ifdef CYGWIN | ||
| 1031 | if ((char *) ptr < _heapbase) | ||
| 1032 | /* We're being asked to free something in the static heap. */ | ||
| 1033 | return; | ||
| 1034 | #endif | ||
| 1035 | |||
| 1036 | PROTECT_MALLOC_STATE (0); | 1025 | PROTECT_MALLOC_STATE (0); |
| 1037 | 1026 | ||
| 1038 | LOCK_ALIGNED_BLOCKS (); | 1027 | LOCK_ALIGNED_BLOCKS (); |
| @@ -1314,30 +1303,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
| 1314 | or (US mail) as Mike Haertel c/o Free Software Foundation. */ | 1303 | or (US mail) as Mike Haertel c/o Free Software Foundation. */ |
| 1315 | 1304 | ||
| 1316 | #ifndef min | 1305 | #ifndef min |
| 1317 | #define min(A, B) ((A) < (B) ? (A) : (B)) | 1306 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
| 1318 | #endif | ||
| 1319 | |||
| 1320 | /* On Cygwin the dumped emacs may try to realloc storage allocated in | ||
| 1321 | the static heap. We just malloc space in the new heap and copy the | ||
| 1322 | data. */ | ||
| 1323 | #ifdef CYGWIN | ||
| 1324 | void * | ||
| 1325 | special_realloc (void *ptr, size_t size) | ||
| 1326 | { | ||
| 1327 | void *result; | ||
| 1328 | int type; | ||
| 1329 | size_t block, oldsize; | ||
| 1330 | |||
| 1331 | block = ((char *) ptr - bss_sbrk_heapbase) / BLOCKSIZE + 1; | ||
| 1332 | type = bss_sbrk_heapinfo[block].busy.type; | ||
| 1333 | oldsize = | ||
| 1334 | type == 0 ? bss_sbrk_heapinfo[block].busy.info.size * BLOCKSIZE | ||
| 1335 | : (size_t) 1 << type; | ||
| 1336 | result = _malloc_internal_nolock (size); | ||
| 1337 | if (result) | ||
| 1338 | return memcpy (result, ptr, min (oldsize, size)); | ||
| 1339 | return result; | ||
| 1340 | } | ||
| 1341 | #endif | 1307 | #endif |
| 1342 | 1308 | ||
| 1343 | /* Debugging hook for realloc. */ | 1309 | /* Debugging hook for realloc. */ |
| @@ -1364,12 +1330,6 @@ _realloc_internal_nolock (void *ptr, size_t size) | |||
| 1364 | else if (ptr == NULL) | 1330 | else if (ptr == NULL) |
| 1365 | return _malloc_internal_nolock (size); | 1331 | return _malloc_internal_nolock (size); |
| 1366 | 1332 | ||
| 1367 | #ifdef CYGWIN | ||
| 1368 | if ((char *) ptr < _heapbase) | ||
| 1369 | /* ptr points into the static heap */ | ||
| 1370 | return special_realloc (ptr, size); | ||
| 1371 | #endif | ||
| 1372 | |||
| 1373 | block = BLOCK (ptr); | 1333 | block = BLOCK (ptr); |
| 1374 | 1334 | ||
| 1375 | PROTECT_MALLOC_STATE (0); | 1335 | PROTECT_MALLOC_STATE (0); |
| @@ -1566,7 +1526,7 @@ __default_morecore (ptrdiff_t increment) | |||
| 1566 | { | 1526 | { |
| 1567 | void *result; | 1527 | void *result; |
| 1568 | #if defined (CYGWIN) | 1528 | #if defined (CYGWIN) |
| 1569 | if (!bss_sbrk_did_unexec) | 1529 | if (!DUMPED) |
| 1570 | { | 1530 | { |
| 1571 | return bss_sbrk (increment); | 1531 | return bss_sbrk (increment); |
| 1572 | } | 1532 | } |
| @@ -1689,6 +1649,9 @@ memalign (size_t alignment, size_t size) | |||
| 1689 | return aligned_alloc (alignment, size); | 1649 | return aligned_alloc (alignment, size); |
| 1690 | } | 1650 | } |
| 1691 | 1651 | ||
| 1652 | /* If HYBRID_MALLOC is defined, we may want to use the system | ||
| 1653 | posix_memalign below. */ | ||
| 1654 | #ifndef HYBRID_MALLOC | ||
| 1692 | int | 1655 | int |
| 1693 | posix_memalign (void **memptr, size_t alignment, size_t size) | 1656 | posix_memalign (void **memptr, size_t alignment, size_t size) |
| 1694 | { | 1657 | { |
| @@ -1707,6 +1670,7 @@ posix_memalign (void **memptr, size_t alignment, size_t size) | |||
| 1707 | 1670 | ||
| 1708 | return 0; | 1671 | return 0; |
| 1709 | } | 1672 | } |
| 1673 | #endif | ||
| 1710 | 1674 | ||
| 1711 | /* Allocate memory on a page boundary. | 1675 | /* Allocate memory on a page boundary. |
| 1712 | Copyright (C) 1991, 92, 93, 94, 96 Free Software Foundation, Inc. | 1676 | Copyright (C) 1991, 92, 93, 94, 96 Free Software Foundation, Inc. |
| @@ -1747,6 +1711,113 @@ valloc (size_t size) | |||
| 1747 | return aligned_alloc (pagesize, size); | 1711 | return aligned_alloc (pagesize, size); |
| 1748 | } | 1712 | } |
| 1749 | 1713 | ||
| 1714 | #ifdef HYBRID_MALLOC | ||
| 1715 | #undef malloc | ||
| 1716 | #undef realloc | ||
| 1717 | #undef calloc | ||
| 1718 | #undef aligned_alloc | ||
| 1719 | #undef free | ||
| 1720 | |||
| 1721 | /* Declare system malloc and friends. */ | ||
| 1722 | extern void *malloc (size_t size); | ||
| 1723 | extern void *realloc (void *ptr, size_t size); | ||
| 1724 | extern void *calloc (size_t nmemb, size_t size); | ||
| 1725 | extern void free (void *ptr); | ||
| 1726 | #ifdef HAVE_ALIGNED_ALLOC | ||
| 1727 | extern void *aligned_alloc (size_t alignment, size_t size); | ||
| 1728 | #elif defined HAVE_POSIX_MEMALIGN | ||
| 1729 | extern int posix_memalign (void **memptr, size_t alignment, size_t size); | ||
| 1730 | #endif | ||
| 1731 | |||
| 1732 | /* See the comments near the beginning of this file for explanations | ||
| 1733 | of the following functions. */ | ||
| 1734 | |||
| 1735 | void * | ||
| 1736 | hybrid_malloc (size_t size) | ||
| 1737 | { | ||
| 1738 | if (DUMPED) | ||
| 1739 | return malloc (size); | ||
| 1740 | return gmalloc (size); | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | void * | ||
| 1744 | hybrid_calloc (size_t nmemb, size_t size) | ||
| 1745 | { | ||
| 1746 | if (DUMPED) | ||
| 1747 | return calloc (nmemb, size); | ||
| 1748 | return gcalloc (nmemb, size); | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | void | ||
| 1752 | hybrid_free (void *ptr) | ||
| 1753 | { | ||
| 1754 | if (!DUMPED) | ||
| 1755 | gfree (ptr); | ||
| 1756 | else if (!ALLOCATED_BEFORE_DUMPING (ptr)) | ||
| 1757 | free (ptr); | ||
| 1758 | /* Otherwise the dumped emacs is trying to free something allocated | ||
| 1759 | before dumping; do nothing. */ | ||
| 1760 | return; | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | #if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN | ||
| 1764 | void * | ||
| 1765 | hybrid_aligned_alloc (size_t alignment, size_t size) | ||
| 1766 | { | ||
| 1767 | if (!DUMPED) | ||
| 1768 | return galigned_alloc (alignment, size); | ||
| 1769 | /* The following is copied from alloc.c */ | ||
| 1770 | #ifdef HAVE_ALIGNED_ALLOC | ||
| 1771 | return aligned_alloc (alignment, size); | ||
| 1772 | #else /* HAVE_POSIX_MEMALIGN */ | ||
| 1773 | void *p; | ||
| 1774 | return posix_memalign (&p, alignment, size) == 0 ? p : 0; | ||
| 1775 | #endif | ||
| 1776 | } | ||
| 1777 | #endif | ||
| 1778 | |||
| 1779 | void * | ||
| 1780 | hybrid_realloc (void *ptr, size_t size) | ||
| 1781 | { | ||
| 1782 | void *result; | ||
| 1783 | int type; | ||
| 1784 | size_t block, oldsize; | ||
| 1785 | |||
| 1786 | if (!DUMPED) | ||
| 1787 | return grealloc (ptr, size); | ||
| 1788 | if (!ALLOCATED_BEFORE_DUMPING (ptr)) | ||
| 1789 | return realloc (ptr, size); | ||
| 1790 | |||
| 1791 | /* The dumped emacs is trying to realloc storage allocated before | ||
| 1792 | dumping. We just malloc new space and copy the data. */ | ||
| 1793 | if (size == 0 || ptr == NULL) | ||
| 1794 | return malloc (size); | ||
| 1795 | block = ((char *) ptr - _heapbase) / BLOCKSIZE + 1; | ||
| 1796 | type = _heapinfo[block].busy.type; | ||
| 1797 | oldsize = | ||
| 1798 | type == 0 ? _heapinfo[block].busy.info.size * BLOCKSIZE | ||
| 1799 | : (size_t) 1 << type; | ||
| 1800 | result = malloc (size); | ||
| 1801 | if (result) | ||
| 1802 | return memcpy (result, ptr, min (oldsize, size)); | ||
| 1803 | return result; | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | #ifdef HYBRID_GET_CURRENT_DIR_NAME | ||
| 1807 | /* Defined in sysdep.c. */ | ||
| 1808 | char *gget_current_dir_name (void); | ||
| 1809 | |||
| 1810 | char * | ||
| 1811 | hybrid_get_current_dir_name (void) | ||
| 1812 | { | ||
| 1813 | if (DUMPED) | ||
| 1814 | return get_current_dir_name (); | ||
| 1815 | return gget_current_dir_name (); | ||
| 1816 | } | ||
| 1817 | #endif | ||
| 1818 | |||
| 1819 | #endif /* HYBRID_MALLOC */ | ||
| 1820 | |||
| 1750 | #ifdef GC_MCHECK | 1821 | #ifdef GC_MCHECK |
| 1751 | 1822 | ||
| 1752 | /* Standard debugging hooks for `malloc'. | 1823 | /* Standard debugging hooks for `malloc'. |