
=====================================================================
                      Copy On Write Shared Memory
=====================================================================

Smart Pointers
--------------

to do COW shared memory, we use smart pointers for the image data.
these are small structures that encapsulate the actual data pointer.
user code obtains and keeps pointers to these structures rather than
the data itself.

a smart pointer never moves after it's been allocated.  however, the
internal variables, including the wrapped data pointer, may change at
any time.  in particular, the piece of memory it points to, or the
location of that memory, may change over time.  always use the macro
wrappers when dealing with a smart pointer.

the smart pointer object has a set of routines which implement a
lifecycle for the data.  this lifecycle is a small state machine.



Lifecycle States
----------------

 UNINIT
  - the smart pointer has not been constructed

 UNALLOC
  - the smart pointer itself is inited, but the encapsulated data
    pointer does not refer to any storage

 SHARABLE
  - the smart pointer refers to storage and will allow other smart
    pointers to refer to it as well

 UNSHARABLE
  - the smart pointer refers to storage but will not allow other smart
    pointers to refer to it.

 SHARED
  - the smart pointer refers to storage.  other smart pointers may
    also refer to it, but this is not known for sure.  at some
    point in the past, there were but they may have split and
    not informed us.



Lifecycle State Transitions
---------------------------

UNINIT     -> UNALLOC
  d_init created an SP

UNALLOC    -> UNINIT
  d_uninit destroyed an SP

UNALLOC    -> SHARABLE
  d_alloc reserved storage for the SP

SHARABLE   -> UNALLOC
  d_unalloc killed storage for an SP

SHARABLE   -> SHARABLE
  d_read used an unused/readonly SP
  d_release let go of a readonly SP
  d_split tried to split an unused/readonly SP

SHARABLE   -> UNSHARABLE
  d_write used an unused/readonly SP

SHARABLE   -> SHARED
  d_join added an SP to an unused/readonly SP

UNSHARABLE -> UNSHARABLE
  d_read used a readwrite SP
  d_write used a readwrite SP
  d_release let go of a readwrite SP (not the last use though)
  d_join made a copy of us for the other SP and left us alone
  d_split tried to split a readwrite SP

UNSHARABLE -> SHARABLE
  d_release let go of a readwrite SP (the last use)

SHARED     -> SHARABLE
  d_write made a copy and detached one of our SP, we had 1 left
  d_split made a copy and detached one of our SP, we had 1 left

SHARED     -> SHARED
  d_read used an unused/readonly SP
  d_write made a copy and detached one of our SP, we had 2+ left
  d_release let go of a readonly SP
  d_join added an SP to an unused/readonly SP
  d_split made a copy and detached one of our SP, we had 2+ left

(new)      -> SHARABLE
  d_join made a copy of a readwrite SP and made it sharable
  d_split made a copy of an unused/readonly SP and made it sharable

(new)      -> UNSHARABLE
  d_write made a copy and detached us from our shared memory




Smart Pointer Routines w/ State Transitions
-------------------------------------------

d_init         UNINIT     -> UNALLOC

d_uninit       UNALLOC    -> UNINIT [1]

d_alloc        UNALLOC    -> SHARABLE

d_unalloc      SHARABLE   -> UNALLOC

d_read         SHARABLE   -> SHARABLE
               UNSHARABLE -> UNSHARABLE
               SHARED     -> SHARED

d_write        SHARABLE   -> UNSHARABLE
               UNSHARABLE -> UNSHARABLE
               SHARED     -> SHARED + UNSHARABLE [2]
               SHARED     -> SHARABLE + UNSHARABLE [2]

d_release      SHARABLE   -> SHARABLE
               UNSHARABLE -> UNSHARABLE
               UNSHARABLE -> SHARABLE [3]
               SHARED     -> SHARED

d_join         SHARABLE   -> SHARED
               SHARED     -> SHARED
               UNSHARABLE -> UNSHARABLE + SHARABLE [4]

d_split        SHARABLE   -> SHARABLE
               UNSHARABLE -> UNSHARABLE
               SHARED     -> SHARED + SHARABLE
               SHARED     -> SHARABLE + SHARABLE [5]

[1] can be called from any state, but bad things may happen

[2] does a copy-on-write, new copy is unsharable, old one is
    left unmodified, unless it now has only one smart pointer.
    then it's made sharable instead of shared

[3] the last release of unsharable leaves it sharable

[4] joining to unsharable will make a new sharable copy, old one is
    left unmodified

[5] splitting a shared memory always makes a new sharable copy.  if
    the old one now has only a single smart pointer, it reverts to
    sharable as well.



=====================================================================
                       Caching and Swapping
=====================================================================


Caching is managed using the three doubly linked lists described
below.  Every GimpMem object lives in one of these lists.  They move
from list to list in response to the following operations:

  gimp_mem_new
  gimp_mem_use
  gimp_mem_unuse

GimpMems are always inserted at the head of the list, unless they are
already in that list in which case they don't move.


 A - active list
  - GimpMem is
     in use
     in memory
     maybe on disk
     maybe dirty
  - enter A
      from B on first use
      from C on first use
  - leave A
      to B on last unuse


B - inactive list
  - GimpMem is
     not in use
     in memory
     maybe on disk
     maybe dirty
  - enter B
      on creation
      from A on last unuse
  - leave B
      to A on first use
      to C on swapout


C - swapped list
   - GimpMem is
      not in use
      not in memory
      on disk
      not dirty
   - enter C
       from B on swapout
  - leave C
      to A on first use


Swapping may be initiated anytime a GimpMem moves to a new list.  The
total size of the active and inactive list is checked against the
desired memory size.  if it's too large, we start moving GimpMems from
B to C.  The B list if walked from the tail to the head (ie: LRU mem
is swapped out first).  Clean mem is dropped, dirty mem is swapped and
dropped.  This continues until we bring the memory size down below the
target or empty the B list.



=====================================================================
                           ShmMgr
=====================================================================

ShmMgr manages OS shared memory segments.  Each segment will have one
or more ShmPtr created for it which define regions inside the segment.
the intent is to create a GimpShmBuffer subclass of GimpBuffer that
will construct itself around a ShmPtr and manage the image data
contained within.


