diff options
Diffstat (limited to 'src/alloc.c')
-rw-r--r-- | src/alloc.c | 106 |
1 files changed, 98 insertions, 8 deletions
diff --git a/src/alloc.c b/src/alloc.c index b96fc1f064..2d25680046 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -24,7 +24,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <signal.h> -#ifdef HAVE_GTK_AND_PTHREAD +#ifdef HAVE_PTHREAD #include <pthread.h> #endif @@ -46,6 +46,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "syssignal.h" #include "termhooks.h" /* For struct terminal. */ #include <setjmp.h> +#include <verify.h> /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd memory. Can do this only if using gmalloc.c. */ @@ -84,13 +85,15 @@ extern size_t __malloc_extra_blocks; #endif /* not DOUG_LEA_MALLOC */ #if ! defined SYSTEM_MALLOC && ! defined SYNC_INPUT -#ifdef HAVE_GTK_AND_PTHREAD +#ifdef HAVE_PTHREAD /* When GTK uses the file chooser dialog, different backends can be loaded dynamically. One such a backend is the Gnome VFS backend that gets loaded if you run Gnome. That backend creates several threads and also allocates memory with malloc. + Also, gconf and gsettings may create several threads. + If Emacs sets malloc hooks (! SYSTEM_MALLOC) and the emacs_blocked_* functions below are called from malloc, there is a chance that one of these threads preempts the Emacs main thread and the hook variables @@ -122,12 +125,12 @@ static pthread_mutex_t alloc_mutex; } \ while (0) -#else /* ! defined HAVE_GTK_AND_PTHREAD */ +#else /* ! defined HAVE_PTHREAD */ #define BLOCK_INPUT_ALLOC BLOCK_INPUT #define UNBLOCK_INPUT_ALLOC UNBLOCK_INPUT -#endif /* ! defined HAVE_GTK_AND_PTHREAD */ +#endif /* ! defined HAVE_PTHREAD */ #endif /* ! defined SYSTEM_MALLOC && ! defined SYNC_INPUT */ /* Mark, unmark, query mark bit of a Lisp string. S must be a pointer @@ -731,6 +734,93 @@ xfree (POINTER_TYPE *block) } +/* Other parts of Emacs pass large int values to allocator functions + expecting ptrdiff_t. This is portable in practice, but check it to + be safe. */ +verify (INT_MAX <= PTRDIFF_MAX); + + +/* Allocate an array of NITEMS items, each of size ITEM_SIZE. + Signal an error on memory exhaustion, and block interrupt input. */ + +void * +xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) +{ + xassert (0 <= nitems && 0 < item_size); + if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems) + memory_full (SIZE_MAX); + return xmalloc (nitems * item_size); +} + + +/* Reallocate an array PA to make it of NITEMS items, each of size ITEM_SIZE. + Signal an error on memory exhaustion, and block interrupt input. */ + +void * +xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) +{ + xassert (0 <= nitems && 0 < item_size); + if (min (PTRDIFF_MAX, SIZE_MAX) / item_size < nitems) + memory_full (SIZE_MAX); + return xrealloc (pa, nitems * item_size); +} + + +/* Grow PA, which points to an array of *NITEMS items, and return the + location of the reallocated array, updating *NITEMS to reflect its + new size. The new array will contain at least NITEMS_INCR_MIN more + items, but will not contain more than NITEMS_MAX items total. + ITEM_SIZE is the size of each item, in bytes. + + ITEM_SIZE and NITEMS_INCR_MIN must be positive. *NITEMS must be + nonnegative. If NITEMS_MAX is -1, it is treated as if it were + infinity. + + If PA is null, then allocate a new array instead of reallocating + the old one. Thus, to grow an array A without saving its old + contents, invoke xfree (A) immediately followed by xgrowalloc (0, + &NITEMS, ...). + + Block interrupt input as needed. If memory exhaustion occurs, set + *NITEMS to zero if PA is null, and signal an error (i.e., do not + return). */ + +void * +xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, + ptrdiff_t nitems_max, ptrdiff_t item_size) +{ + /* The approximate size to use for initial small allocation + requests. This is the largest "small" request for the GNU C + library malloc. */ + enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; + + /* If the array is tiny, grow it to about (but no greater than) + DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%. */ + ptrdiff_t n = *nitems; + ptrdiff_t tiny_max = DEFAULT_MXFAST / item_size - n; + ptrdiff_t half_again = n >> 1; + ptrdiff_t incr_estimate = max (tiny_max, half_again); + + /* Adjust the increment according to three constraints: NITEMS_INCR_MIN, + NITEMS_MAX, and what the C language can represent safely. */ + ptrdiff_t C_language_max = min (PTRDIFF_MAX, SIZE_MAX) / item_size; + ptrdiff_t n_max = (0 <= nitems_max && nitems_max < C_language_max + ? nitems_max : C_language_max); + ptrdiff_t nitems_incr_max = n_max - n; + ptrdiff_t incr = max (nitems_incr_min, min (incr_estimate, nitems_incr_max)); + + xassert (0 < item_size && 0 < nitems_incr_min && 0 <= n && -1 <= nitems_max); + if (! pa) + *nitems = 0; + if (nitems_incr_max < incr) + memory_full (SIZE_MAX); + n += incr; + pa = xrealloc (pa, n * item_size); + *nitems = n; + return pa; +} + + /* Like strdup, but uses xmalloc. */ char * @@ -1265,7 +1355,7 @@ emacs_blocked_realloc (void *ptr, size_t size, const void *ptr2) } -#ifdef HAVE_GTK_AND_PTHREAD +#ifdef HAVE_PTHREAD /* Called from Fdump_emacs so that when the dumped Emacs starts, it has a normal malloc. Some thread implementations need this as they call malloc before main. The pthread_self call in BLOCK_INPUT_ALLOC then @@ -1278,7 +1368,7 @@ reset_malloc_hooks (void) __malloc_hook = old_malloc_hook; __realloc_hook = old_realloc_hook; } -#endif /* HAVE_GTK_AND_PTHREAD */ +#endif /* HAVE_PTHREAD */ /* Called from main to set up malloc to use our hooks. */ @@ -1286,7 +1376,7 @@ reset_malloc_hooks (void) void uninterrupt_malloc (void) { -#ifdef HAVE_GTK_AND_PTHREAD +#ifdef HAVE_PTHREAD #ifdef DOUG_LEA_MALLOC pthread_mutexattr_t attr; @@ -1300,7 +1390,7 @@ uninterrupt_malloc (void) and the bundled gmalloc.c doesn't require it. */ pthread_mutex_init (&alloc_mutex, NULL); #endif /* !DOUG_LEA_MALLOC */ -#endif /* HAVE_GTK_AND_PTHREAD */ +#endif /* HAVE_PTHREAD */ if (__free_hook != emacs_blocked_free) old_free_hook = __free_hook; |