Recognize -zfollow,ssl,ascii,0 for compatibility
[metze/wireshark/wip.git] / doc / README.wmem
index 1475d242e179922f60567869bc84a8c09c2e3d5f..79ec946df3a8db71cbf7cab087401b4a1f0acd51 100644 (file)
-$Id$
-
 1. Introduction
 
-NB: Wmem still does not provide all of the functionality of emem
-    (see README.malloc), although it should provide most of it. New code
-    may still need to use emem for the time being.
+The 'wmem' memory manager is Wireshark's memory management framework, replacing
+the old 'emem' framework which was removed in Wireshark 2.0.
 
-The 'emem' memory manager (described in README.malloc) has been a part of
-Wireshark since 2005 and has served us well, but is starting to show its age.
-The framework has become increasingly difficult to maintain, and limitations
-in the API have blocked progress on other long-term goals such as multi-
-threading, and opening multiple files at once.
+In order to make memory management easier and to reduce the probability of
+memory leaks, Wireshark provides its own memory management API. This API is
+implemented inside epan/wmem/ and provides memory pools and functions that make
+it easy to manage memory even in the face of exceptions (which many dissector
+functions can raise).
 
-The 'wmem' memory manager is an attempt to write a new memory management
-framework to replace emem. It provides a significantly updated API, a more
-modular design, and it isn't all jammed into one 2500-line file.
+Correct use of these functions will make your code faster, and greatly reduce
+the chances that it will leak memory in exceptional cases.
 
 Wmem was originally conceived in this email to the wireshark-dev mailing list:
 https://www.wireshark.org/lists/wireshark-dev/201210/msg00178.html
 
-The wmem code can now be found in epan/wmem/ in the Wireshark source tree.
-
 2. Usage for Consumers
 
 If you're writing a dissector, or other "userspace" code, then using wmem
-should be very similar to using emem. All you need to do is include the header
-(epan/wmem/wmem.h) and get a handle to a memory pool (if you want to *create*
-a memory pool, see the section "3. Usage for Producers" below).
+should be very similar to using malloc or g_malloc or whatever else you're used
+to. All you need to do is include the header (epan/wmem/wmem.h) and optionally
+get a handle to a memory pool (if you want to *create* a memory pool, see the
+section "3. Usage for Producers" below).
 
 A memory pool is an opaque pointer to an object of type wmem_allocator_t, and
 it is the very first parameter passed to almost every call you make to wmem.
-Other than that parameter (and the fact that functions are prefixed wmem_
-instead of ep_ or se_) usage is exactly like that of emem. For example:
+Other than that parameter (and the fact that functions are prefixed wmem_)
+usage is very similar to glib and other utility libraries. For example:
 
     wmem_alloc(myPool, 20);
 
 allocates 20 bytes in the pool pointed to by myPool.
 
-2.1 Available Pools
+2.1 Memory Pool Lifetimes
+
+Every memory pool should have a defined lifetime, or scope, after which all the
+memory in that pool is unconditionally freed. When you choose to allocate memory
+in a pool, you *must* be aware of its lifetime: if the lifetime is shorter than
+you need, your code will contain use-after-free bugs; if the lifetime is longer
+than you need, your code may contain undetectable memory leaks. In either case,
+the risks outweigh the benefits.
 
-2.1.1 (Sort Of) Global Pools
+If no pool exists whose lifetime matches the lifetime of your memory, you have
+two options: create a new pool (see section 3 of this document) or use the NULL
+pool. Any function that takes a pointer to a wmem_allocator_t can also be passed
+NULL instead, in which case the memory is managed manually (just like malloc or
+g_malloc). Memory allocated like this *must* be manually passed to wmem_free()
+in order to prevent memory leaks (however these memory leaks will at least show
+up in valgrind). Note that passing wmem_allocated memory directly to free()
+or g_free() is not safe; the backing type of manually managed memory may be
+changed without warning.
+
+2.2 Wireshark Global Pools
 
 Dissectors that include the wmem header file will have three pools available
 to them automatically: wmem_packet_scope(), wmem_file_scope() and
 wmem_epan_scope();
 
-The packet pool is scoped to the dissection of each packet, replacing
-emem's ep_ allocators. The file pool is scoped to the dissection of each file,
-replacing emem's se_ allocators. For example:
-
-    ep_malloc(32);
-    se_malloc(sizeof(guint));
-
-could be replaced with
+The packet pool is scoped to the dissection of each packet, meaning that any
+memory allocated in it will be automatically freed at the end of the current
+packet. The file pool is similarly scoped to the dissection of each file,
+meaning that any memory allocated in it will be automatically freed when the
+current capture file is closed.
 
-    wmem_alloc(wmem_packet_scope(), 32);
-    wmem_alloc(wmem_file_scope(),   sizeof(guint));
-
-NB: Using these pools outside of the appropriate scope (eg using the packet
+NB: Using these pools outside of the appropriate scope (e.g. using the packet
     pool when there isn't a packet being dissected) will throw an assertion.
     See the comment in epan/wmem/wmem_scopes.c for details.
 
 The epan pool is scoped to the library's lifetime - memory allocated in it is
-not freed until epan_cleanup() is called, which is typically at the end of the
-program. 
+not freed until epan_cleanup() is called, which is typically but not necessarily
+at the very end of the program.
 
-2.1.2 Pinfo Pool
+2.3 The Pinfo Pool
 
-Certain places (such as AT_STRINGZ address allocations) need their memory to
-stay around a little longer than the usual packet scope - basically until the
-next packet is dissected. This is effectively the scope of Wireshark's pinfo
+Certain allocations (such as AT_STRINGZ address allocations and anything that
+might end up being passed to add_new_data_source) need their memory to stick
+around a little longer than the usual packet scope - basically until the
+next packet is dissected. This is, in fact, the scope of Wireshark's pinfo
 structure, so the pinfo struct has a 'pool' member which is a wmem pool scoped
 to the lifetime of the pinfo struct.
 
-2.2 Core API
+2.4 API
+
+Full documentation for each function (parameters, return values, behaviours)
+lives (or will live) in Doxygen-format in the header files for those functions.
+This is just an overview of which header files you should be looking at.
+
+2.4.1 Core API
+
+wmem_core.h
+ - Basic memory management functions (wmem_alloc, wmem_realloc, wmem_free).
+
+2.4.2 Strings
 
- - wmem_alloc
- - wmem_alloc0
+wmem_strutl.h
+ - Utility functions for manipulating null-terminated C-style strings.
+   Functions like strdup and strdup_printf.
 
-2.3 String Utilities
+wmem_strbuf.h
+ - A managed string object implementation, similar to std::string in C++ or
+   GString from Glib.
 
- - wmem_strdup
- - wmem_strndup
- - wmem_strdup_printf
- - wmem_strdup_vprintf
+2.4.3 Container Data Structures
 
-2.4 Stack
+wmem_array.h
+ - A growable array (AKA vector) implementation.
 
- - wmem_stack_new
- - wmem_stack_push
- - wmem_stack_pop
- - wmem_stack_peek
- - wmem_stack_count
+wmem_list.h
+ - A doubly-linked list implementation.
 
-2.5 Singly-Linked List
+wmem_map.h
+ - A hash map (AKA hash table) implementation.
 
- - wmem_slist_new
- - wmem_slist_prepend
- - wmem_slist_remove
- - wmem_slist_front
- - wmem_slist_frame_next
- - wmem_slist_frame_data
- - wmem_slist_count
+wmem_queue.h
+ - A queue implementation (first-in, first-out).
 
-2.6 Slab
+wmem_stack.h
+ - A stack implementation (last-in, first-out).
 
- - wmem_slab_new
- - wmem_slab_alloc
- - wmem_slab_free
+wmem_tree.h
+ - A balanced binary tree (red-black tree) implementation.
 
-2.7 String-Buffers
+2.4.4 Miscellaneous Utilities
 
- - wmem_strbuf_new
- - wmem_strbuf_sized_new
- - wmem_strbuf_append
- - wmem_strbuf_get_str
- - wmem_strbuf_get_len
+wmem_miscutl.h
+ - Misc. utility functions like memdup.
+
+2.5 Callbacks
+
+WARNING: You probably don't actually need these; use them only when you're
+         sure you understand the dangers.
+
+Sometimes (though hopefully rarely) it may be necessary to store data in a wmem
+pool that requires additional cleanup before it is freed. For example, perhaps
+you have a pointer to a file-handle that needs to be closed. In this case, you
+can register a callback with the wmem_register_callback function
+declared in wmem_user_cb.h. Every time the memory in a pool is freed, all
+registered cleanup functions are called first.
+
+Note that callback calling order is not defined, you cannot rely on a
+certain callback being called before or after another.
+
+WARNING: Manually freeing or moving memory (with wmem_free or wmem_realloc)
+         will NOT trigger any callbacks. It is an error to call either of
+         those functions on memory if you have a callback registered to deal
+         with the contents of that memory.
 
 3. Usage for Producers
 
@@ -131,15 +160,8 @@ pool to pick one.
 3.1 Available Allocator Back-Ends
 
 Each available allocator type has a corresponding entry in the
-wmem_allocator_type_t enumeration defined in wmem_core.h.
-
-The currently available allocators are:
- - WMEM_ALLOCATOR_SIMPLE (wmem_allocator_simple.*)
-        A trivial allocator that g_allocs requested memory and tracks
-        allocations via a simple linked list.
- - WMEM_ALLOCATOR_BLOCK (wmem_allocator_block.*)
-        A block allocator that grabs large chunks of memory at a time
-        (8 MB currently) and serves allocations out of those chunks.
+wmem_allocator_type_t enumeration defined in wmem_core.h. See the doxygen
+comments in that header file for details on each type.
 
 3.2 Creating a Pool
 
@@ -202,32 +224,78 @@ the pool would otherwise be scoped to a single iteration of a loop. For example:
 
 Despite being written in Wireshark's standard C90, wmem follows a fairly
 object-oriented design pattern. Although efficiency is always a concern, the
-primary goals in writing wmem were maintainability, and preventing memory
+primary goals in writing wmem were maintainability and preventing memory
 leaks.
 
 4.1 struct _wmem_allocator_t
 
 The heart of wmem is the _wmem_allocator_t structure defined in the
 wmem_allocator.h header file. This structure uses C function pointers to
-implement a common object-oriented pattern known as an interface (AKA 'abstract
-class' to those of you who are more familiar with C++).
+implement a common object-oriented design pattern known as an interface (also
+known as an abstract class to those who are more familiar with C++).
 
 Different allocator implementations can provide exactly the same interface by
-assigning their own functions (of the appropriate signature) to the members of
-an instance of the structure. The structure currently has five values:
+assigning their own functions to the members of an instance of the structure.
+The structure has eight members in three groups.
+
+4.1.1 Implementation Details
 
- - alloc()
- - free_all()
- - destroy()
  - private_data
  - type
 
-The private_data pointer is a void pointer that the implementation can use to
-store whatever internal structures it needs. The type field is an enumeration of
-type wmem_allocator_type_t (see section 3.1) set by the wmem_allocator_new()
-function and not by the implementation. The three function pointers should
-be fairly obvious - each one is called with a pointer to the private_data in
-addition to any other arguments.
+The private_data pointer is a void pointer that the allocator implementation can
+use to store whatever internal structures it needs. A pointer to private_data is
+passed to almost all of the other functions that the allocator implementation
+must define.
+
+The type field is an enumeration of type wmem_allocator_type_t (see
+section 3.1). Its value is set by the wmem_allocator_new() function, not
+by the implementation-specific constructor. This field should be considered
+read-only by the allocator implementation.
+
+4.1.2 Consumer Functions
+
+ - walloc()
+ - wfree()
+ - wrealloc()
+
+These function pointers should be set to functions with semantics obviously
+similar to their standard-library namesakes. Each one takes an extra parameter
+that is a copy of the allocator's private_data pointer.
+
+Note that wrealloc() and wfree() are not expected to be called directly by user
+code in most cases - they are primarily optimizations for use by data
+structures that wmem might want to implement (it's inefficient, for example, to
+implement a dynamically sized array without some form of realloc).
+
+Also note that allocators do not have to handle NULL pointers or 0-length
+requests in any way - those checks are done in an allocator-agnostic way
+higher up in wmem. Allocator authors can assume that all incoming pointers
+(to wrealloc and wfree) are non-NULL, and that all incoming lengths (to walloc
+and wrealloc) are non-0.
+
+4.1.3 Producer/Manager Functions
+
+ - free_all()
+ - gc()
+ - cleanup()
+
+All of these functions take only one parameter, which is the allocator's
+private_data pointer.
+
+The free_all() function should free all the memory currently allocated in the
+pool. Note that this is not necessarily exactly the same as calling free()
+on all the allocated blocks - free_all() is allowed to do additional cleanup
+or to make use of optimizations not available when freeing one block at a time.
+
+The gc() function should do whatever it can to reduce excess memory usage in
+the dissector by returning unused blocks to the OS, optimizing internal data
+structures, etc.
+
+The cleanup() function should do any final cleanup and free any and all memory.
+It is basically the equivalent of a destructor function. For simplicity, wmem
+is guaranteed to call free_all() immediately before calling this function. There
+is no such guarantee that gc() has (ever) been called.
 
 4.2 Pool-Agnostic API
 
@@ -243,30 +311,80 @@ wmem's stack implementation only take the pool when created - the provided
 pointer is stored internally with the data structure, and subsequent calls
 (like push and pop) will take the stack itself instead of the pool.
 
-5. TODO List
+4.3 Debugging
+
+The primary debugging control for wmem is the WIRESHARK_DEBUG_WMEM_OVERRIDE
+environment variable. If set, this value forces all calls to
+wmem_allocator_new() to return the same type of allocator, regardless of which
+type is requested normally by the code. It currently has three valid values:
+
+ - The value "simple" forces the use of WMEM_ALLOCATOR_SIMPLE. The valgrind
+   script currently sets this value, since the simple allocator is the only
+   one whose memory allocations are trackable properly by valgrind.
+
+ - The value "strict" forces the use of WMEM_ALLOCATOR_STRICT. The fuzz-test
+   script currently sets this value, since the goal when fuzz-testing is to find
+   as many errors as possible.
+
+ - The value "block" forces the use of WMEM_ALLOCATOR_BLOCK. This is not
+   currently used by any scripts, but is useful for stress-testing the block
+   allocator.
+
+ - The value "block_fast" forces the use of WMEM_ALLOCATOR_BLOCK_FAST. This is
+   not currently used by any scripts, but is useful for stress-testing the fast
+   block allocator.
+
+Note that regardless of the value of this variable, it will always be safe to
+call allocator-specific helpers functions. They are required to be safe no-ops
+if the allocator argument is of the wrong type.
+
+4.4 Testing
+
+There is a simple test suite for wmem that lives in the file wmem_test.c and
+should get automatically built into the binary 'wmem_test' when building
+Wireshark. It contains at least basic tests for all existing functionality.
+The suite is run automatically by the build-bots via the shell script
+test/test.py which calls out to test/suite_unittests.py.
+
+New features added to wmem (allocators, data structures, utility
+functions, etc.) MUST also have tests added to this suite.
+
+The test suite could potentially use a clean-up by someone more
+intimately familiar with Glib's testing framework, but it does the job.
 
-The following is a list of things that wmem provides but are incomplete
-(i.e. missing common operations):
+5. A Note on Performance
 
- - string buffers
- - singly-linked list
+Because of my own bad judgment, there is the persistent idea floating around
+that wmem is somehow magically faster than other allocators in the general case.
+This is false.
 
-The following is an incomplete list of things that emem provides but wmem has
-not yet implemented:
+First, wmem supports multiple different allocator backends (see sections 3 and 4
+of this document), so it is confusing and misleading to try and compare the
+performance of "wmem" in general with another system anyways.
 
- - red-black tree
- - tvb_memdup
- - canaries
+Second, any modern system-provided malloc already has a very clever and
+efficient allocator algorithm that makes use of blocks, arenas and all sorts of
+other fancy tricks. Trying to be faster than libc's allocator is generally a
+waste of time unless you have a specific allocation pattern to optimize for.
 
-The following is a list of things that emem doesn't provide but that it might
-be nice if wmem did provide them:
+Third, while there were historically arguments to be made for putting something
+in front of the kernel to reduce the number of context-switches, modern libc
+implementations should already do that. Making a dynamic library call is still
+marginally more expensive than calling a locally-defined linker-optimized
+function, but it's a difference too small to care about.
 
- - radix tree
- - dynamic array
- - realloc
+With all that said, it is true that *some* of wmem's allocators can be
+substantially faster than your standard libc malloc, in *some* use cases:
+ - The BLOCK and BLOCK_FAST allocators both provide very efficient free_all
+   operations, which can be many orders of magnitude faster than calling free()
+   on each individual allocation.
+ - The BLOCK_FAST allocator in particular is optimized for Wireshark's packet
+   scope pool. It has an extremely short, well-defined lifetime, and a very
+   regular pattern of allocations; I was able to use that knowledge to beat libc
+   rather handily, *in that specific use case*.
 
 /*
- * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
  *
  * Local variables:
  * c-basic-offset: 4