diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2015-02-23 02:54:41 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2015-02-23 02:54:41 +0100 |
commit | b40fe867e021bc365df1a904c2b1ed2068208f13 (patch) | |
tree | 94fa618661bec5e25980bde2cb01249c5c3e2c35 /src/undo.cpp | |
parent | 611bb221a96e50fd8561886ec34d8a42e136b5ce (diff) | |
download | sciteco-b40fe867e021bc365df1a904c2b1ed2068208f13.tar.gz |
implemented to undo stack memory limiting
* acts as a safe-guard against uninterrupted infinite loops
or other operations that are costly to undo in interactive mode.
If we're out of memory, it is usually too late to react properly.
This implementation tries to avoid OOMs due to SciTECO behaviour.
We cannot fully exclude the chance of an OOM error.
* The undo stack size is only approximated using the
UndoToken::get_size() method.
Other ways to measure the exact amount of allocated heap
(including size fields in every heap object or using sbrk(0) and
similar) are either costly in terms of memory or platform-specific.
This implementation does not need any additional memory per heap
object or undo token but exploits the fact that undo tokens
are virtual already. The size of an undo token is determined
at compile time.
* Default memory limit of 500mb should be OK for most people.
* The current limit can be queried with "2EJ" and set with <x>,2EJ.
This also works interactively (a bit tricky!)
* Limiting can be disabled. In this case, undo token processing
is a bit faster.
* closes #3
Diffstat (limited to 'src/undo.cpp')
-rw-r--r-- | src/undo.cpp | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/src/undo.cpp b/src/undo.cpp index 25303f5..c1e842a 100644 --- a/src/undo.cpp +++ b/src/undo.cpp @@ -30,6 +30,7 @@ #include "sciteco.h" #include "cmdline.h" #include "interface.h" +#include "error.h" #include "undo.h" namespace SciTECO { @@ -38,18 +39,61 @@ namespace SciTECO { UndoStack undo; +static inline gdouble +size_to_mb(gsize s) +{ + return ((gdouble)s)/(1024*1024); +} + +void +UndoStack::set_memory_limit(gsize new_limit) +{ + if (new_limit) { + if (!memory_limit) { + /* memory_usage outdated - recalculate */ + UndoToken *token; + + memory_usage = 0; + SLIST_FOREACH(token, &head, tokens) + memory_usage += token->get_size(); + } + + if (memory_usage > new_limit) + throw Error("Cannot set undo memory limit (%gmb): " + "Current stack too large (%gmb).", + size_to_mb(new_limit), + size_to_mb(memory_usage)); + } + + push_var(memory_limit) = new_limit; +} + void UndoStack::push(UndoToken *token) { - if (enabled) { -#ifdef DEBUG - g_printf("UNDO PUSH %p\n", token); -#endif - token->pos = cmdline_pos; - SLIST_INSERT_HEAD(&head, token, tokens); - } else { + if (!enabled) { delete token; + return; + } + + if (memory_limit) { + gsize token_size = token->get_size(); + + if (memory_usage + token_size > memory_limit) { + delete token; + throw Error("Undo stack memory limit (%gmb) exceeded. " + "See <EJ> command.", + size_to_mb(memory_limit)); + } + + memory_usage += token_size; } + +#ifdef DEBUG + g_printf("UNDO PUSH %p\n", token); +#endif + token->pos = cmdline_pos; + SLIST_INSERT_HEAD(&head, token, tokens); } void @@ -62,6 +106,8 @@ UndoStack::pop(gint pos) fflush(stdout); #endif + if (memory_limit) + memory_usage -= top->get_size(); top->run(); SLIST_REMOVE_HEAD(&head, tokens); @@ -78,6 +124,8 @@ UndoStack::clear(void) SLIST_REMOVE_HEAD(&head, tokens); delete cur; } + + memory_usage = 0; } UndoStack::~UndoStack() |