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.h | |
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.h')
-rw-r--r-- | src/undo.h | 86 |
1 files changed, 80 insertions, 6 deletions
@@ -18,6 +18,8 @@ #ifndef __UNDO_H #define __UNDO_H +#include <string.h> + #include <bsd/sys/queue.h> #include <glib.h> @@ -29,25 +31,65 @@ namespace SciTECO { +/** + * Default undo stack memory limit (500mb). + */ +#define UNDO_MEMORY_LIMIT_DEFAULT (500*1024*1024) + class UndoToken { public: SLIST_ENTRY(UndoToken) tokens; + /** + * Command-line character position corresponding + * to this token. + * + * @todo This wastes memory in macro calls and loops + * because all undo tokens will have the same + * value. It may be better to redesign the undo + * stack data structure - as a list/array pointing + * to undo stacks per character. + */ gint pos; virtual ~UndoToken() {} - virtual void run() = 0; + virtual void run(void) = 0; + + /** + * Return approximated size of this object. + * If possible it should take all heap objects + * into account that are memory-managed by the undo + * token. + * For a simple implementation, you may derive + * from UndoTokenWithSize. + */ + virtual gsize get_size(void) const = 0; +}; + +/** + * UndoToken base class employing the CRTP idiom. + * Deriving this class adds a size approximation based + * on the shallow size of the template parameter. + */ +template <class UndoTokenImpl> +class UndoTokenWithSize : public UndoToken { +public: + gsize + get_size(void) const + { + return sizeof(UndoTokenImpl); + } }; template <typename Type> -class UndoTokenVariable : public UndoToken { +class UndoTokenVariable : public UndoTokenWithSize< UndoTokenVariable<Type> > { Type *ptr; Type value; public: UndoTokenVariable(Type &variable, Type _value) - : UndoToken(), ptr(&variable), value(_value) {} + : ptr(&variable), value(_value) {} void run(void) @@ -66,7 +108,7 @@ class UndoTokenString : public UndoToken { public: UndoTokenString(gchar *&variable, gchar *_str) - : UndoToken(), ptr(&variable) + : ptr(&variable) { str = _str ? g_strdup(_str) : NULL; } @@ -83,6 +125,13 @@ public: *ptr = str; str = NULL; } + + gsize + get_size(void) const + { + return str ? sizeof(*this) + strlen(str) + 1 + : sizeof(*this); + } }; template <class Type> @@ -92,7 +141,7 @@ class UndoTokenObject : public UndoToken { public: UndoTokenObject(Type *&variable, Type *_obj) - : UndoToken(), ptr(&variable), obj(_obj) {} + : ptr(&variable), obj(_obj) {} ~UndoTokenObject() { @@ -108,20 +157,45 @@ public: *ptr = obj; obj = NULL; } + + gsize + get_size(void) const + { + return obj ? sizeof(*this) + sizeof(*obj) + : sizeof(*this); + } }; extern class UndoStack { SLIST_HEAD(Head, UndoToken) head; + /** + * Current approx. memory usage of all + * undo tokens in the stack. + * It is only up to date if memory limiting + * is enabled. + */ + gsize memory_usage; + public: bool enabled; - UndoStack(bool _enabled = false) : enabled(_enabled) + /** + * Undo stack memory limit in bytes. + * 0 means no limiting. + */ + gsize memory_limit; + + UndoStack(bool _enabled = false) + : memory_usage(0), enabled(_enabled), + memory_limit(UNDO_MEMORY_LIMIT_DEFAULT) { SLIST_INIT(&head); } ~UndoStack(); + void set_memory_limit(gsize new_limit = 0); + void push(UndoToken *token); template <typename Type> |