mirror of
https://github.com/neovim/neovim.git
synced 2025-11-14 14:29:02 +00:00
(verbose_)?try_malloc() to use on buf_write()
There will be more use cases for try_malloc(): see #556. - Reimplemented xmalloc() using try_malloc(). - verbose_try_malloc() is just like try_malloc() but shows an out-of-memory error message before returning NULL. - Let the compiler generate size>>1 assembly for signed types. We're not using old compilers here. - Add proper function attributes to the new functions in memory.h
This commit is contained in:
committed by
Thiago de Arruda
parent
1befc49414
commit
15d8f702a8
47
src/fileio.c
47
src/fileio.c
@@ -190,7 +190,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
|
|||||||
/*
|
/*
|
||||||
* Read lines from file "fname" into the buffer after line "from".
|
* Read lines from file "fname" into the buffer after line "from".
|
||||||
*
|
*
|
||||||
* 1. We allocate blocks with lalloc, as big as possible.
|
* 1. We allocate blocks with try_malloc, as big as possible.
|
||||||
* 2. Each block is filled with characters from the file with a single read().
|
* 2. Each block is filled with characters from the file with a single read().
|
||||||
* 3. The lines are inserted in the buffer with ml_append().
|
* 3. The lines are inserted in the buffer with ml_append().
|
||||||
*
|
*
|
||||||
@@ -987,9 +987,14 @@ retry:
|
|||||||
if (!skip_read) {
|
if (!skip_read) {
|
||||||
size = 0x10000L; /* use buffer >= 64K */
|
size = 0x10000L; /* use buffer >= 64K */
|
||||||
|
|
||||||
for (; size >= 10; size = (long)((long_u)size >> 1)) {
|
for (; size >= 10; size /= 2) {
|
||||||
if ((new_buffer = lalloc((long_u)(size + linerest + 1),
|
new_buffer = verbose_try_malloc((size_t)size + (size_t)linerest + 1);
|
||||||
FALSE)) != NULL)
|
if (new_buffer) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (new_buffer == NULL) {
|
||||||
|
error = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (linerest) /* copy characters from the previous buffer */
|
if (linerest) /* copy characters from the previous buffer */
|
||||||
@@ -2763,10 +2768,7 @@ buf_write (
|
|||||||
(char_u *)"", 0); /* show that we are busy */
|
(char_u *)"", 0); /* show that we are busy */
|
||||||
msg_scroll = FALSE; /* always overwrite the file message now */
|
msg_scroll = FALSE; /* always overwrite the file message now */
|
||||||
|
|
||||||
buffer = alloc(BUFSIZE);
|
buffer = verbose_try_malloc(BUFSIZE);
|
||||||
// TODO: decide how to handle this now that alloc never returns NULL. The fact
|
|
||||||
// that the OOM handling code calls this should be considered.
|
|
||||||
//
|
|
||||||
// can't allocate big buffer, use small one (to be able to write when out of
|
// can't allocate big buffer, use small one (to be able to write when out of
|
||||||
// memory)
|
// memory)
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
@@ -3006,7 +3008,12 @@ buf_write (
|
|||||||
int did_set_shortname;
|
int did_set_shortname;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
copybuf = alloc(BUFSIZE + 1);
|
copybuf = verbose_try_malloc(BUFSIZE + 1);
|
||||||
|
if (copybuf == NULL) {
|
||||||
|
// out of memory
|
||||||
|
some_error = TRUE;
|
||||||
|
goto nobackup;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to make the backup in each directory in the 'bdir' option.
|
* Try to make the backup in each directory in the 'bdir' option.
|
||||||
@@ -3372,8 +3379,10 @@ nobackup:
|
|||||||
write_info.bw_conv_buflen = bufsize * 2;
|
write_info.bw_conv_buflen = bufsize * 2;
|
||||||
else /* FIO_UCS4 */
|
else /* FIO_UCS4 */
|
||||||
write_info.bw_conv_buflen = bufsize * 4;
|
write_info.bw_conv_buflen = bufsize * 4;
|
||||||
write_info.bw_conv_buf
|
write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
|
||||||
= lalloc((long_u)write_info.bw_conv_buflen, TRUE);
|
if (!write_info.bw_conv_buf) {
|
||||||
|
end = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3390,8 +3399,10 @@ nobackup:
|
|||||||
if (write_info.bw_iconv_fd != (iconv_t)-1) {
|
if (write_info.bw_iconv_fd != (iconv_t)-1) {
|
||||||
/* We're going to use iconv(), allocate a buffer to convert in. */
|
/* We're going to use iconv(), allocate a buffer to convert in. */
|
||||||
write_info.bw_conv_buflen = bufsize * ICONV_MULT;
|
write_info.bw_conv_buflen = bufsize * ICONV_MULT;
|
||||||
write_info.bw_conv_buf
|
write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
|
||||||
= lalloc((long_u)write_info.bw_conv_buflen, TRUE);
|
if (!write_info.bw_conv_buf) {
|
||||||
|
end = 0;
|
||||||
|
}
|
||||||
write_info.bw_first = TRUE;
|
write_info.bw_first = TRUE;
|
||||||
} else
|
} else
|
||||||
# endif
|
# endif
|
||||||
@@ -5048,7 +5059,9 @@ int vim_rename(char_u *from, char_u *to)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = (char *)alloc(BUFSIZE);
|
// Avoid xmalloc() here as vim_rename() is called by buf_write() when neovim
|
||||||
|
// is `preserve_exit()`ing.
|
||||||
|
buffer = try_malloc(BUFSIZE);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
close(fd_out);
|
close(fd_out);
|
||||||
close(fd_in);
|
close(fd_in);
|
||||||
@@ -5616,15 +5629,15 @@ void vim_deltempdir(void)
|
|||||||
*/
|
*/
|
||||||
static void vim_settempdir(char_u *tempdir)
|
static void vim_settempdir(char_u *tempdir)
|
||||||
{
|
{
|
||||||
char_u *buf;
|
char_u *buf = verbose_try_malloc((size_t)MAXPATHL + 2);
|
||||||
|
if (buf) {
|
||||||
buf = alloc((unsigned)MAXPATHL + 2);
|
|
||||||
if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
|
if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
|
||||||
STRCPY(buf, tempdir);
|
STRCPY(buf, tempdir);
|
||||||
add_pathsep(buf);
|
add_pathsep(buf);
|
||||||
vim_tempdir = vim_strsave(buf);
|
vim_tempdir = vim_strsave(buf);
|
||||||
vim_free(buf);
|
vim_free(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
28
src/memory.c
28
src/memory.c
@@ -81,24 +81,40 @@ static void try_to_free_memory()
|
|||||||
trying_to_free = false;
|
trying_to_free = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *xmalloc(size_t size)
|
void *try_malloc(size_t size)
|
||||||
{
|
{
|
||||||
void *ret = malloc(size);
|
void *ret = malloc(size);
|
||||||
|
|
||||||
if (!ret && !size)
|
if (!ret && !size) {
|
||||||
ret = malloc(1);
|
ret = malloc(1);
|
||||||
|
}
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
try_to_free_memory();
|
try_to_free_memory();
|
||||||
ret = malloc(size);
|
ret = malloc(size);
|
||||||
if (!ret && !size)
|
if (!ret && !size) {
|
||||||
ret = malloc(1);
|
ret = malloc(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *verbose_try_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ret = try_malloc(size);
|
||||||
|
if (!ret) {
|
||||||
|
do_outofmem_msg((long_u)size);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *xmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ret = try_malloc(size);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
OUT_STR("Vim: Error: Out of memory.\n");
|
OUT_STR("Vim: Error: Out of memory.\n");
|
||||||
preserve_exit();
|
preserve_exit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
src/memory.h
20
src/memory.h
@@ -10,6 +10,24 @@ char_u *alloc_clear(unsigned size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
|
|||||||
|
|
||||||
/// malloc() wrapper
|
/// malloc() wrapper
|
||||||
///
|
///
|
||||||
|
/// try_malloc() is a malloc() wrapper that tries to free some memory before
|
||||||
|
/// trying again.
|
||||||
|
///
|
||||||
|
/// @see {try_to_free_memory}
|
||||||
|
/// @param size
|
||||||
|
/// @return pointer to allocated space. NULL if out of memory
|
||||||
|
void *try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
|
||||||
|
|
||||||
|
/// try_malloc() wrapper that shows an out-of-memory error message to the user
|
||||||
|
/// before returning NULL
|
||||||
|
///
|
||||||
|
/// @see {try_malloc}
|
||||||
|
/// @param size
|
||||||
|
/// @return pointer to allocated space. NULL if out of memory
|
||||||
|
void *verbose_try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
|
||||||
|
|
||||||
|
/// malloc() wrapper that never returns NULL
|
||||||
|
///
|
||||||
/// xmalloc() succeeds or gracefully aborts when out of memory.
|
/// xmalloc() succeeds or gracefully aborts when out of memory.
|
||||||
/// Before aborting try to free some memory and call malloc again.
|
/// Before aborting try to free some memory and call malloc again.
|
||||||
///
|
///
|
||||||
@@ -51,7 +69,7 @@ void *xmallocz(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET;
|
|||||||
/// @see {xmalloc}
|
/// @see {xmalloc}
|
||||||
/// @param data Pointer to the data that will be copied
|
/// @param data Pointer to the data that will be copied
|
||||||
/// @param len number of bytes that will be copied
|
/// @param len number of bytes that will be copied
|
||||||
void *xmemdupz(const void *data, size_t len);
|
void *xmemdupz(const void *data, size_t len) FUNC_ATTR_NONNULL_RET;
|
||||||
|
|
||||||
/// strdup() wrapper
|
/// strdup() wrapper
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user