]> git.buserror.net Git - polintos/scott/priv.git/blobdiff - doc/orb/memory-management
Document new memory management semantics.
[polintos/scott/priv.git] / doc / orb / memory-management
index 98871b6c271b8aee56a12ee20afdcc8938f4b86b..3189696af52935de4dfdafe03ff31f270a9051a2 100644 (file)
 1.1 Overview
 ============
 
-The writeability, sharedness, and lifetime of memory passed by reference
-as a parameter (in or out) depends on the parameter attributes, as well as
-whether the method is asynchronous.  The implementation of the semantics
-will be different for in-process and remote methods, and not all
-restrcitions are enforced as strictly for in-process methods, but the
-semantics when the rules are followed must be the same for both.
-
-The data type of parameter also affects how it is handled.  Built-in
-datatypes, bitfields, enums, and inline structs and arrays are passed
-directly by value (or, depending on the ABI, simple reference-valid-
-until-end-of-method for out parameters), and thus do not require memory
-management.  Object references are reference counted both at the ORB and
-process level, and are unique in that the client data structures are
-read-only and uncopyable (because a unique object needs a unique address)
-within an address space; most of this section does not apply to them.
-
-That leaves non-inline structs and arrays.  The ideal way of treating
-these depends on how they're being used.  Simple, small structs and arrays
-would benefit from being passed as a simple pointer (plus a length field
-in the case of arrays), with the method copying anything it wants to keep
-and/or change.  For async methods, the caller would need to avoid
-modifying referenced memory until it knows the method has been executed
-(in the case of remote methods, it only matters until the ORB has COWed or
-copied the memory, but client code should not depend on this, or it will
-not work with an in-process server).  This is the default behavior if no
-parameter attributes are specified.  With this type of parameter, there
-are no restrictions on what allocator the memory being passed came from
-for in parameters.  "Out" and inout parameters will be discussed later.
-
-The only major complexity here is in how the duplicate is made. Struct
-duplications will need to do a deep copy without being confused by
-reference loops; the stubs will need to provide a "duplicate" function
-that does this (possibly using a hash table or other associative array to
-identify reference loops if IDLC determines that they are possible with
-that particular type of struct).
-
-To avoid a double-copy, out-of-process methods may want to merely ask the
-ORB to give it full, permanent access (via COW if not already copied) to
-the memory.  This may be hard to implement, though, as it requires the
-server to know that the data came from an out-of-process implementation
-(even if it's been passed to other functions, some of which may be
-in-process object-model methods).  This optimization may only be useful
-for large amounts of data that is not likely to have most of its pages
-modified; if it is likely to be heavily modified, then COW doesn't help
-much, and may hurt (and if it's large, it probably hasn't already been
-copied).  It may be better to not implement this optimization, and instead
-recommend that the user use a parameter attribute to deal with the
-problem.
-
-1.2 Parameter Attributes
-========================
+This document defines the lifetime and writeability of memory passed by
+reference as a parameter under various circumstances (in or out, sync or
+async).  The implementation of the semantics will be different for local
+and remote methods, and not all restrcitions are enforced as strictly for
+local methods, but the semantics when the rules are followed must be the
+same for both.
+
+1.2 Definitions
+===============
 
-With larger arrays and complex data structures, one would often benefit
-from being able to avoid the copy altogether.  This can be accomplished by
-altering the interface semantics.  All of the parameter attributes but
-"copy" do this, and thus cannot be changed without breaking interface
-compatibility.  None of the current parameter attributes can be combined
-with any other current parameter attribute.
-
-1.2.1 Default Semantics
-=======================
-
-If no attribute is specified, "in" parameters are visible only until the
-method returns, and are read-only.  There will be a "duplicate" function
-provided by the language binding for the server to use if it wants to
-retain and/or write to the data.  For "small" data (the threshold needs to
-be empirically determined), it just makes a copy.  For "large" data, the
-pages will be copy-on-write mapped (unless the caller asks for an
-immediate copy).  The only real reason not to use the immediate flag for
-small data (as determined by the programmer) as well (rather than have a
-threshold) is so that the threshold can be tunable based on the relative
-performance of copies versus traps on a given system.  It'd also be nice
-if the programmer could ask a profiler to determine whether large data
-should be COWed or copied immediately on a per-call basis.
-
-When the "duplicate" function is called, a copy-on-write mapping of the
-data will be created.  Edge data will be overmapped regardless of page
-type, but the overmap status will be retained (so that edge pages will not
-be overmapped into some other address space), though read overmap will be
-promoted to read/write overmap, as the extra data in the copy will not be
-used anymore.  There will be an option to the "duplicate" function to
-create fully overmappable pages by copying the edge data and zeroing the
-rest of the edge pages (in case the caller wants to share the data).
-   
-1.2.2 Copy
-==========
+implementation attribute: An attribute that is defined only for a specific
+server object, and affects only the server stubs.  It can be changed
+without breaking client compatibility.
+
+interface attribute: An attribute that is defined as a part of an IDL
+interface, and cannot be changed without breaking compatibility.
+
+local: The method being called exists in the caller's address space, and
+thus no marshalling need occur.
+
+remote: The method being called exists in an address space other than the
+caller's.  All data must be marshalled and passed through some form of
+IPC.
+
+1.3 In Parameters
+=================
+
+Built-in datatypes, bitfields, enums, and inline structs and arrays are
+passed directly by value (or, depending on the ABI, a reference valid
+until the end of the method for out parameters), and thus do not require
+memory management for local calls.  For remote calls, data passed by
+value is treated as a single non-inline struct for synchronous methods,
+and as an inline struct (copied at invocation time, and freed when the
+message is removed from the queue by the ORB) for async methods.
+
+Object references are reference counted both at the ORB and process
+level, and are unique in that the client data structures are read-only
+and uncopyable (because a unique object needs a unique address) within an
+address space; most of this section does not apply to them.
+
+That leaves non-inline structs and arrays.  These are  passed as a simple
+pointer (plus a length field in the case of arrays), with the method
+copying anything it wants to change and/or keep beyond the end of the
+method.  For async methods, the caller needs to avoid modifying referenced
+memory until it knows the method has been executed (in the remote case, it
+only matters until the ORB has COWed or copied the memory, but client code
+should not depend on this, or it will not work with an local server). 
+There are no allocator or alignment restrictions on the memory being
+passed (though page alignment and overmap can improve performance when
+sending large buffers).
+
+If the server wants to keep the data past the end of the method, or if it
+wants to modify the data, it must call a duplicate() function to copy the
+data, map it copy-on-write.  Struct duplications will need to do a deep
+copy without being confused by reference loops (possibly by using a hash
+table or other associative array to identify reference loops if IDLC
+determines that they are possible with that particular type of struct).
+
+To avoid a double-copy, remote methods may want to merely ask the ORB to
+give it full, permanent access (via COW if not already copied) to the
+memory.  This may be hard to implement, though, as it requires the server
+to know that the data came from an remote implementation, and be able to
+modify the set of pages that the ORB reclaims at the end of the method
+call.  This may not provide a significant benefit over simply creating a
+new copy-on-write mapping.
+
+In remote calls, the caller is charged with the temporary allocations made
+by the ORB in the callee's address space.
+
+1.3.1 Copy (interface)
+======================
+
+The "copy" interface attribute may be used to achieve the effect of
+calling duplicate() in the server.  For local calls, this simply results
+in a call to duplicate() in the client stubs.  For remote calls, the
+copied data segments are marked with the Copy flag, which are read/write
+(using copy-on-write) and not freed at the end of the method.  These pages
+are charged to the callee, and must be freed using the callee's ORB memory
+manager.  The callee should be able to specify how much data it is willing
+to have copied to a given object.
+
+The "copy" interface attribute may not be used on "out" parameters, and
+for "inout" parameters only applies to the "in" phase.  Do not confuse
+this with the implementation "copy" attribute used on "out" parameters.
 
-The "copy" attribute affects only the implementation; changing it does not
-break interface compatibility (and thus require a new GUID).  As such, the
-use of this attribute is specified in the CDL rather than the IDL. 
-Language bindings that do not require a CDL file will provide some way of
-specifying copy semantics directly from the implementation language.
+1.4 Out parameters
+==================
 
-This attribute directs the ORB to automatically make a copy (possibly via
-COW, but no read-only or shared mappings) of the parameter.  For
-in-process invocation, methods with any "copy" parameters will need to go
-through a stub to do the copy before calling the real method.
+When a non-inline struct or array is being returned via an out or inout
+parameter, there is no end of method on which to base reference lifetime. 
+As such, the ownership of such data is transferred to the ORB memory
+manager in the caller's address space.  For remote calls, the caller
+should be able to specify a limit on how much memory it is willing to
+receive from the callee.
 
-1.2.3 Shared
-============
+Inline "out" parameters are returned into a buffer provided by the caller.
+All value types are implicitly inline.
 
-The "shared" attribute declares that the method implementation and caller
-will treat the data as a read/write shared memory region, lasting beyond
-the end of the method.  The caller must ensure that all segments of data
-provided (including every nested struct, or struct/array in an array of
-structs/arrays) either begins and ends exactly on a page boundary, or has
-all partial pages marked for read/write overmap.  For out-of-process
-methods, an exception will be thrown if this is not the case.  For
-in-process methods, you'll merely go to hell for writing bugs that won't
-show up until someone hands your code a reference to an out-of-process
-implementation.  All data must be under the management of the ORB memory
-manager.
-
-The shared region is terminated when the caller or callee frees the memory
-using the ORB memory manager.  This requires calling some function that
-knows whether to actually free it (in the out-of-process case), or release
-a reference or something (in the in-process case).  For arrays, where
-we're already using a struct with pointer and length, adding a reference
-count pointer wouldn't be a big deal.  Struct pointers, OTOH, are
-currently plain pointers, and adding an indirection struct with pointer
-and reference pointer would be ugly, but doable.  The alternative is to
-have the memory manager look up the memory fragment and find the refcount
-in its internal data structures, which would require a lookup for every
-reference count operation.
-1.2.4 Push
-==========
+1.4.1 Copy (implementation)
+===========================
 
-The "push" attribute transfers the memory region to the destination,
-unlinking it from the source address space.  The source memory region will
-be unmapped for out-of-process invocations; for in-process invocations,
-the memory region will simply belong to the callee, and the caller must
-not reference it any more.  Like "shared", all data fragments must either
-begin and end on a page boundary, or be in a page with read/write overmap
-enabled.  It is also required that every page being pushed be under the
-management of the ORB allocator.
+If the "copy" implementation attribute is specified on the out parameter,
+then the buffer the caller receives will be newly allocated, and the
+buffer provided by the callee remains the callee's.  In this case, there
+are no allocator or alignment restrictions on the callee's buffer.
 
-1.2.5 Inline
-============
+If the "copy" attribute is not specified, then the buffer provided by the
+callee must be under the control of the ORB memory manager, and it must
+begin and end on page boundaries.  When returning from a remote call, the
+pages will be unmapped from the callee and mapped into the caller.
+
+The "copy" implementation attribute may not be used on "in" parameters,
+and for "inout" parameters only applies to the "out" phase.  Do not
+confuse this with the interface "copy" attribute used on "in" parameters.
+
+1.5 Inline
+==========
 
 When used as a parameter attribute (either explicitly or as part of the
 type definition), "inline" specifies that the struct or array will be
@@ -150,11 +128,6 @@ passed directly as a value parameter.  A NULL reference cannot be passed,
 and for out parameters, the method cannot return a reference to an
 existing struct or array, but instead must fill in the reference given.
 
-The "inline" attribute is similar to "copy", except that no in-process
-stub is required because it is part of the interface (though a stub may be
-required in certain languages if they do not provide automatic copying of
-value-passed structs/arrays).
-
 An inline array cannot be of variable length, and may be treated
 differently from other arrays in the language binding (e.g. in C++, inline
 arrays are bare language arrays, and do not use the Array or MutableArray
@@ -164,24 +137,7 @@ The "inline" attribute can also be used on members of a struct, to
 indicate that the member is embedded directly in the outer struct, rather
 than linked with a pointer.
 
-1.2.6 Immutable
-===============
-
-The "immutable" attribute is similar to "const" in C/C++ ("const" in
-IDL is used only for compile-time constants), and specifies that the
-array or struct cannot be modified through this particular reference.
-It is the default for parameters when neither "shared" nor "push" is
-used ("copy" and "inline" parameters will accept immutable references
-on the caller side, but will produce a mutable copy for the server
-side). It may be specified without effect when it is the default.
-
-Immutable "shared"/"push" parameters will result in read-only
-mappings in the destination address space, though for "push"
-parameters, the process will have permission to enable writes (this
-is intended for use by the ORB memory manager when the memory is
-freed).
-
-The "immutable" attribute may also be used on members of a struct.
+"Inline" is an interface attribute.
 
 1.3 Asynchronous methods
 ========================
@@ -193,65 +149,26 @@ When invoking an async method, there should be a mechanism to get a handle
 to track the progress of the invocation.  This can be used by the caller
 to try to cancel the method on a timeout, which can only be done if the
 message has not yet been accepted by the recipient.  Once the message has
-been accepted, in the in-process, non-"copy" case, the caller must not
+been accepted, in the local, non-"copy" case, the caller must not
 touch the data after this point until it receives a message from the
-callee that it is finished.  In the out-of-process case, if a caller loses
+callee that it is finished.  In the remote case, if a caller loses
 patience with the callee, it can free the memory (thus making it exist
 only in the callee's address space, non-shared).
 
-1.4 Out parameters
-==================
-
-When a struct or array is being returned via an out or inout parameter,
-there is no end of method on which to base reference lifetime.  As such,
-if neither "shared" nor "inline" is specified, an out parameter is treated
-as "push".  The default of "push" only applies to the out half of an inout
-parameter; in general, use of inout should be probably limited to value
-types and parameters that use "push" in both directions so as to avoid
-potentially confusing semantics.
-
-To return static data that does not need to be freed, out parameters can
-use the "copy" implementation attribute.  The interface semantics will
-still be "push", but the ORB (or a wrapper function for in-process calls)
-will allocate a pushable buffer and copy the data into it.  If the static
-data is managed by the ORB memory manager, it will reference count the
-page rather than make a copy if the buffer is of sufficient size.
-
 1.5 Exceptions
 ==============
 
-Exceptions are thrown as copy/push out parameters.  This will often mean
-unnecessary copies at in-process IDL method boundaries, but exceptions
-should be small and infrequently thrown, and usually not managed by the
-ORB memory manager except across method boundaries.
-
-1.6 Unmet needs
-===============
-
-It is currently impossible to specify attributes (other than "immutable"
-and "inline") on individual struct members.  This would be useful to pass
-a struct normally that contains a status code or other metadata along with
-a pushed or shared buffer, without making the outer struct also pushed or
-shared.  It would also be useful to pass a pushed buffer through some
-fixed superstruct such as a NotifierInfo.
+Exceptions are thrown as copied out parameters.  This will often mean
+unnecessary copies at local IDL method boundaries, but exceptions should
+be small and infrequently thrown, and usually not managed by the ORB
+memory manager except across method boundaries.
 
 2. The ORB Memory Manager (ORBMM)
 =================================
 
-The ORB memory manager keeps track of memory allocated by the ORB during
-an out-of-process method invocation.  It is also used for allocations made
-by user code for memory that may need to be freed by another component in
-the same address space (such as when using the shared or push attributes).
-
-A reference count is kept on each page, so that shared-within-a-process
-mappings must be released by both caller and callee before the memory is
-freed.  Passing a chunk of data through a "shared" parameter to in-process
-method increments the page's reference count; this requires a memory
-manager lookup for every such parameter.  Because of this, consider using
-"push" instead if sharing is not required.
-
-In the out-of-process case, each mapping is freed separately, and the
-kernel handles reference counting the physical page.
+The ORB memory manager keeps track of memory that is allocated in the
+process of calling or returning from a method.  This happens with "copy"
+in parameters, and all non-inline out parameters.
 
 2.1 Methods
 ===========
@@ -266,121 +183,56 @@ System::RunTime::ORBMM.
 2.1.1 alloc
 ===========
 
-void *ORBMM::alloc(size_t size, ORBMM::AllocGroup *group = NULL);
-
-Allocate the memory required for the given type (and the given array size,
-if the type is an array).  A group handle may be passed; if not, no page
-will contain more than one allocation.  The reference count on the page is
-incremented if a page has been reused and per-object refcounts are not
-supported; otherwise, the object's reference count is one.  If the
-allocation spans multiple pages, it will be tracked as an "object", so
-that each page will have its reference count incremented and/or
-decremented when appropriate.
+void *ORBMM::alloc(size_t size, int refs = 1);
 
-The implementation may, but is not required to, track reference counts on
-a per-page basis rather than per-object.  The former will generally be
-more efficient, but will preclude the reuse of an object's memory upon
-release until the entire page is released.
+Allocate the memory required for the given type, array length, and
+inital refcount.
 
-Alternative forms:
+Alternate forms:
 Type *obj = new(orbmm) Type;
 Type *obj = new(orbmm) Type[];
-Type *obj = new(orbmm, group) Type;
-Type *obj = new(orbmm, group) Type[];
+Type *obj = new(orbmm, refs) Type;
+Type *obj = new(orbmm, refs) Type[];
 
 2.1.2 retain
 ============
 
-void ORBMM::retain(Region region);
-
-Increment the reference count on the specified object.  
+void ORBMM::retain(void *ptr, int refs = 1);
 
-The region must refer to only one ORBMM object; the implementation may,
-but is not required to, throw an exception if this rule is violated.  If a
-region smaller than the object is retained, it will not prevent other
-pages in the region from being freed.
+Add the specified number of references to the ORBMM object.  "ptr" can
+be anywhere inside the object; it does not have to point to the
+beginning of the object.
 
 2.1.3 release
 =============
 
-void ORBMM::release(Region region);
-
-Decrement the reference count on the specified object, freeing it if it
-reaches zero.  
-
-It is allowed, but not required, that space in multi-object groups be
-reused when freed, if the same group is used to allocate new objects. 
-This is only possible if reference counts are kept on a per-object basis
-rather than per-page.
-
-The region must refer to only one ORBMM object; the implementation may,
-but is not required to, throw an exception if this rule is violated.  If a
-region smaller than the object is released resulting in a reference count
-of zero, portions may be freed prior to the rest of the region's reference
-count reaching zero.
-
-2.1.4 super_retain
-==================
-
-void ORBMM::super_retain(Region region);
-
-Increment the reference and super-reference counts on the specified
-object.  If the reference count ever goes below the super-reference count,
-an exception is thrown.  This mechanism is intended to ease debugging
-reference count problems, by turning memory corruption into an exception. 
-
-It would typically be used when a given object is not intended to be
-released until the program exits (or some well-defined cleanup procedure
-is done), such as program and module code and static data.  It should also
-be used when a mapping is created using mmap() or other higher-level
-function, so as to be able to detect if such a reference is released
-through release() rather than through the high-level mechanism.
-
-The region must refer to only one ORBMM object; the implementation may,
-but is not required to, throw an exception if this rule is violated. 
+void ORBMM::free(void *ptr, int refs = 1);
 
-2.1.5 super_release
-===================
+Alternate forms:
+delete(orbmm) Type;
+delete(orbmm) Type[];
+delete(orbmm, refs) Type;
+delete(orbmm, refs) Type[];
 
-void ORBMM::super_release(Region region);
+Release the specified number of references to the ORBMM object. If
+the refcount falls to zero, the memory will be unmapped.  If the
+refcount goes below zero, an exception may be thrown.  "ptr" can be
+anywhere inside the object; it does not have to point to the
+beginning of the object.
 
-Decrement the reference and super-reference counts on the given object.
-
-The region must refer to only one ORBMM object; the implementation may,
-but is not required to, throw an exception if this rule is violated. 
-
-2.1.6 create_group
-==================
-
-ORBMM::AllocGroup *ORBMM::create_group();
-
-Create a group handle that can be passed to the alloc function to pack
-multiple allocations into the same page(s).
-
-2.1.7 destroy_group
-===================
-
-void ORBMM::destroy_group(ORBMM::AllocGroup *group);
-
-Free the memory associated with the group handle returned by create_group.
-The allocations made under the group are unaffected, and must be released
-separately.
-
-2.1.8 add_region
+2.1.3 add_region
 ================
 
-void *ORBMM::add_region(System::Mem::Region region);
-
-The ORB memory manager can manage reference counts of pages that were not
-allocated using ORBMM.  This can be used to refcount non-anonymous
-mappings (and thus make them usable with parameters that require ORBMM
-memory).  It can also be used on static pages that will never be freed
-until the program exits.
+void ORBMM::add_region(System::Mem::Region region, bool unmap_orig,
+                       int refs = 1);
 
 The add_region method places a non-ORBMM controlled region under ORBMM
-control.  The ORBMM may use the existing mapping, or it may remap the
-pages into its own region of the virtual address space.  The address that
-it uses will be returned.  The entire region will be one ORBMM object.
-
-Upon a reference count of zero, the pages will be unmapped using
-System.AddrSpace.unmap().
+control.  This can be used to return data that was not allocated using
+ORBMM (such as static data or non-anonymous mappings), without having
+to always do so (as the "copy" attribute would require).  It is also
+used internally by IDL stubs.
+
+The entire region will be one ORBMM object, and will be freed all at
+once when the refcount goes to zero.  When it is freed, the region
+will cease to be under ORBMM control.  The original region will only
+be unmapped if unmap_orig is true.