Changeset 5a4f1a8


Ignore:
Timestamp:
Jun 21, 2021, 4:48:11 PM (7 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
jacob/cs343-translation, master, new-ast-unique-expr
Children:
33e1c91
Parents:
029cbc0
Message:

Andrew MMath: Folded in feedback into the implement chapter. (6/6 files done.)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/andrew_beach_MMath/implement.tex

    r029cbc0 r5a4f1a8  
    22\label{c:implement}
    33
    4 The implementation work for this thesis covers two components: the virtual
     4The implementation work for this thesis covers the two components: virtual
    55system and exceptions. Each component is discussed in detail.
    66
     
    2121\todo{Talk about constructors for virtual types (after they are working).}
    2222
    23 This is what binds an instance of a virtual type to a virtual table. This
    24 pointer can be used as an identity check. It can also be used to access the
     23The virtual table pointer binds an instance of a virtual type
     24to a virtual table.
     25The pointer is also the table's id and how the system accesses the
    2526virtual table and the virtual members there.
    2627
    2728\subsection{Type Id}
    2829Every virtual type has a unique id.
    29 Type ids can be compared for equality (the types reperented are the same)
     30Type ids can be compared for equality,
     31which checks if the types reperented are the same,
    3032or used to access the type's type information.
    3133The type information currently is only the parent's type id or, if the
    32 type has no parent, zero.
     34type has no parent, the null pointer.
    3335
    3436The id's are implemented as pointers to the type's type information instance.
    35 Derefencing the pointer gets the type information.
    36 By going back-and-forth between the type id and
    37 the type info one can find every ancestor of a virtual type.
    38 It also pushes the issue of creating a unique value (for
     37Dereferencing the pointer gets the type information.
     38The ancestors of a virtual type are found by traversing type ids through
     39the type information.
     40The information pushes the issue of creating a unique value (for
    3941the type id) to the problem of creating a unique instance (for type
    40 information) which the linker can solve.
    41 
    42 Advanced linker support is required because there is no place that appears
    43 only once to attach the type information to. There should be one structure
    44 definition but it is included in multiple translation units. Each virtual
    45 table definition should be unique but there are an arbitrary number of thoses.
    46 So the special section prefix \texttt{.gnu.linkonce} is used.
    47 With a unique suffix (making the entire section name unique) the linker will
    48 remove multiple definition making sure only one version exists after linking.
    49 Then it is just a matter of making sure there is a unique name for each type.
    50 
    51 This is done in three phases.
    52 The first phase is to generate a new structure definition to store the type
     42information), which the linker can solve.
     43
     44The advanced linker support is used here to avoid having to create
     45a new declaration to attach this data to.
     46With C/\CFA's header/implementation file divide for something to appear
     47exactly once it must come from a declaration that appears in exactly one
     48implementation file; the declarations in header files may exist only once
     49they can be included in many different translation units.
     50Therefore, structure's declaration will not work.
     51Neither will attaching the type information to the virtual table -- although
     52a vtable declarations are in implemention files they are not unique, see
     53\autoref{ss:VirtualTable}.
     54Instead the same type information is generated multiple times and then
     55the new attribute \snake{cfa_linkone} is used to removed duplicates.
     56
     57Type information is constructed as follows:
     58\begin{enumerate}
     59\item
     60Use the type's name to generate a name for the type information structure.
     61This is saved so it may be reused.
     62\item
     63Generate a new structure definition to store the type
    5364information. The layout is the same in each case, just the parent's type id,
    54 but the types are changed.
    55 The structure's name is change, it is based off the virtual type's name, and
    56 the type of the parent's type id.
     65but the types used change from instance to instance.
     66The generated name is used for both this structure and, if relivant, the
     67parent pointer.
    5768If the virtual type is polymorphic then the type information structure is
    5869polymorphic as well, with the same polymorphic arguments.
    59 
    60 The second phase is to generate an instance of the type information with a
    61 almost unique name, generated by mangling the virtual type name.
    62 
    63 The third phase is implicit with \CFA's overloading scheme. \CFA mangles
    64 names with type information so that all of the symbols exported to the linker
    65 are unique even if in \CFA code they are the same. Having two declarations
    66 with the same name and same type is forbidden because it is impossible for
    67 overload resolution to pick between them. This is why a unique type is
    68 generated for each virtual type.
    69 Polymorphic information is included in this mangling so polymorphic
    70 types will have seperate instances for each set of polymorphic arguments.
    71 
    72 \begin{cfa}
    73 struct TYPE_ID_TYPE {
    74         PARENT_ID_TYPE const * parent;
     70\item
     71A seperate name for instances is generated from the type's name.
     72\item
     73The definition is generated and initialised.
     74The parent id is set to the null pointer or to the address of the parent's
     75type information instance. Name resolution handles the rest.
     76\item
     77\CFA's name mangler does its regular name mangling encoding the type of
     78the declaration into the instance name. This gives a completely unique name
     79including different instances of the same polymorphic type.
     80\end{enumerate}
     81\todo{The list is making me realise, some of this isn't ordered.}
     82
     83Writing that code manually, with helper macros for the early name mangling,
     84would look like this:
     85\begin{cfa}
     86struct INFO_TYPE(TYPE) {
     87        INFO_TYPE(PARENT) const * parent;
    7588};
    7689
    7790__attribute__((cfa_linkonce))
    78 TYPE_ID_TYPE const TYPE_ID_NAME = {
    79         &PARENT_ID_NAME,
     91INFO_TYPE(TYPE) const INFO_NAME(TYPE) = {
     92        &INFO_NAME(PARENT),
    8093};
    8194\end{cfa}
    8295
    83 \subsubsection{cfa\_linkonce Attribute}
     96\subsubsection{\lstinline{cfa\_linkonce} Attribute}
     97% I just realised: This is an extension of the inline keyword.
     98% An extension of C's at least, it is very similar to C++'s.
    8499Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}.
    85 This attribute can be put on an object or function definition
    86 (any global declaration with a name and a type).
    87 This allows you to define that object or function multiple times.
    88 All definitions should have the link-once attribute on them and all should
    89 be identical.
    90 
    91 The simplist way to use it is to put a definition in a header where the
    92 forward declaration would usually go.
    93 This is how it is used for type-id instances. There was is no unique location
    94 associated with a type except for the type definition which is in a header.
    95 This allows the unique type-id object to be generated there.
    96 
    97 Internally @cfa_linkonce@ removes all @section@ attributes
    98 from the declaration (as well as itself) and replaces them with
     100This attribute is attached to an object or function definition
     101(any global declaration with a name and a type)
     102allowing it to be defined multiple times.
     103All matching definitions mush have the link-once attribute
     104and their implementations should be identical as well.
     105
     106A single definition with the attribute can be included in a header
     107file as if it was a forward declaration, except no definition is required.
     108
     109This technique is used for type-id instances. A link-once definition is
     110generated each time the structure is seen. This will result in multiple
     111copies but the link-once attribute ensures all but one are removed for a
     112unique instance.
     113
     114Internally, @cfa_linkonce@ is replaced with
    99115@section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the
    100116mangled name of the object.
     117Any other @section@ attributes are removed from the declaration.
    101118The prefix \texttt{.gnu.linkonce} in section names is recognized by the
    102 linker. If two of these sections with the same name, including everything
    103 that comes after the special prefix, then only one will be used and the other
    104 will be discarded.
     119linker. If two of these sections appear with the same name, including
     120everything that comes after the special prefix, then only one is used
     121and the other is discarded.
    105122
    106123\subsection{Virtual Table}
     124\label{ss:VirtualTable}
    107125Each virtual type has a virtual table type that stores its type id and
    108126virtual members.
     
    113131
    114132The layout always comes in three parts.
     133\todo{Add labels to the virtual table layout figure.}
    115134The first section is just the type id at the head of the table. It is always
    116 there to ensure that
     135there to ensure that it can be found even when the accessing code does not
     136know which virtual type it has.
    117137The second section are all the virtual members of the parent, in the same
    118138order as they appear in the parent's virtual table. Note that the type may
     
    133153prefix that has the same layout and types as its parent virtual table.
    134154This, combined with the fixed offset to the virtual table pointer, means that
    135 for any virtual type it doesn't matter if we have it or any of its
    136 descendants, it is still always safe to access the virtual table through
    137 the virtual table pointer.
    138 From there it is safe to check the type id to identify the exact type of the
     155for any virtual type, it is always safe to access its virtual table and,
     156from there, it is safe to check the type id to identify the exact type of the
    139157underlying object, access any of the virtual members and pass the object to
    140158any of the method-like virtual members.
    141159
    142 When a virtual table is declared the user decides where to declare it and its
     160When a virtual table is declared, the user decides where to declare it and its
    143161name. The initialization of the virtual table is entirely automatic based on
    144162the context of the declaration.
    145163
    146 The type id is always fixed, each virtual table type will always have one
     164The type id is always fixed; with each virtual table type having
    147165exactly one possible type id.
    148 The virtual members are usually filled in by resolution. The best match for
    149 a given name and type at the declaration site is filled in.
    150 There are two exceptions to that rule: the @size@ field is the type's size
    151 and is set to the result of a @sizeof@ expression, the @align@ field is the
    152 type's alignment and similarly uses an @alignof@ expression.
     166The virtual members are usually filled in by type resolution.
     167The best match for a given name and type at the declaration site is used.
     168There are two exceptions to that rule: the @size@ field, the type's size,
     169is set using a @sizeof@ expression and the @align@ field, the
     170type's alignment, is set using an @alignof@ expression.
    153171
    154172\subsubsection{Concurrency Integration}
    155173Coroutines and threads need instances of @CoroutineCancelled@ and
    156174@ThreadCancelled@ respectively to use all of their functionality. When a new
    157 data type is declared with @coroutine@ or @thread@ the forward declaration for
     175data type is declared with @coroutine@ or @thread@, a forward declaration for
    158176the instance is created as well. The definition of the virtual table is created
    159177at the definition of the main function.
     178
     179This is showned through code re-writing in
     180\autoref{f:ConcurrencyTransformations}.
    160181
    161182\begin{figure}
     
    211232the cast target is passed in as @child@.
    212233
    213 For C generation both arguments and the result are wrapped with type casts.
    214 There is also an internal store inside the compiler to make sure that the
     234For generated C code wraps both arguments and the result with type casts.
     235There is also an internal check inside the compiler to make sure that the
    215236target type is a virtual type.
    216237% It also checks for conflicting definitions.
    217238
    218 The virtual cast either returns the original pointer as a new type or null.
    219 So the function just does the parent check and returns the approprate value.
     239The virtual cast either returns the original pointer or the null pointer
     240as the new type.
     241So the function does the parent check and returns the appropriate value.
    220242The parent check is a simple linear search of child's ancestors using the
    221243type information.
     
    229251% resumption doesn't as well.
    230252
    231 % Many modern languages work with an interal stack that function push and pop
     253% Many modern languages work with an internal stack that function push and pop
    232254% their local data to. Stack unwinding removes large sections of the stack,
    233255% often across functions.
     
    236258stack. On function entry and return, unwinding is handled directly by the
    237259call/return code embedded in the function.
    238 In many cases the position of the instruction pointer (relative to parameter
     260In many cases, the position of the instruction pointer (relative to parameter
    239261and local declarations) is enough to know the current size of the stack
    240262frame.
    241263
    242264Usually, the stack-frame size is known statically based on parameter and
    243 local variable declarations. Even with dynamic stack-size the information
    244 to determain how much of the stack has to be removed is still contained
     265local variable declarations. Even with dynamic stack-size, the information
     266to determine how much of the stack has to be removed is still contained
    245267within the function.
    246268Allocating/deallocating stack space is usually an $O(1)$ operation achieved by
    247269bumping the hardware stack-pointer up or down as needed.
    248 Constructing/destructing values on the stack takes longer put in terms of
    249 figuring out what needs to be done is of similar complexity.
     270Constructing/destructing values within a stack frame has
     271a similar complexity but can add additional work and take longer.
    250272
    251273Unwinding across multiple stack frames is more complex because that
     
    261283reseting to a snap-shot of an arbitrary but existing function frame on the
    262284stack. It is up to the programmer to ensure the snap-shot is valid when it is
    263 reset and that all required clean-up from the unwound stacks is preformed.
    264 This approach is fragile and forces a work onto the surounding code.
    265 
    266 With respect to that work forced onto the surounding code,
     285reset and that all required clean-up from the unwound stacks is performed.
     286This approach is fragile and requires extra work in the surrounding code.
     287
     288With respect to the extra work in the surounding code,
    267289many languages define clean-up actions that must be taken when certain
    268290sections of the stack are removed. Such as when the storage for a variable
    269291is removed from the stack or when a try statement with a finally clause is
    270292(conceptually) popped from the stack.
    271 None of these should be handled by the user, that would contradict the
    272 intention of these features, so they need to be handled automatically.
    273 
    274 To safely remove sections of the stack the language must be able to find and
     293None of these should be handled by the user --- that would contradict the
     294intention of these features --- so they need to be handled automatically.
     295
     296To safely remove sections of the stack, the language must be able to find and
    275297run these clean-up actions even when removing multiple functions unknown at
    276298the beginning of the unwinding.
     
    294316current stack frame, and what handlers should be checked. Theoretically, the
    295317LSDA can contain any information but conventionally it is a table with entries
    296 representing regions of the function and what has to be done there during
     318representing regions of a function and what has to be done there during
    297319unwinding. These regions are bracketed by instruction addresses. If the
    298320instruction pointer is within a region's start/end, then execution is currently
     
    314336int avar __attribute__(( cleanup(clean_up) ));
    315337\end{cfa}
    316 The attribue is used on a variable and specifies a function,
     338The attribute is used on a variable and specifies a function,
    317339in this case @clean_up@, run when the variable goes out of scope.
    318 This is enough to mimic destructors, but not try statements which can effect
     340This feature is enough to mimic destructors,
     341but not try statements which can effect
    319342the unwinding.
    320343
    321 To get full unwinding support all of this has to be done directly with
    322 assembly and assembler directives. Partiularly the cfi directives
     344To get full unwinding support, all of these features must be handled directly
     345in assembly and assembler directives; partiularly the cfi directives
    323346\snake{.cfi_lsda} and \snake{.cfi_personality}.
    324347
     
    327350section covers some of the important parts of the interface.
    328351
    329 A personality function can preform different actions depending on how it is
     352A personality function can perform different actions depending on how it is
    330353called.
    331354\begin{lstlisting}
     
    364387
    365388The @exception_class@ argument is a copy of the
    366 \code{C}{exception}'s @exception_class@ field.
    367 This a number that identifies the exception handling mechanism that created
    368 the
    369 
    370 The \code{C}{exception} argument is a pointer to the user
     389\code{C}{exception}'s @exception_class@ field,
     390which is a number that identifies the exception handling mechanism
     391that created the exception.
     392
     393The \code{C}{exception} argument is a pointer to a user
    371394provided storage object. It has two public fields: the @exception_class@,
    372395which is described above, and the @exception_cleanup@ function.
    373 The clean-up function is used by the EHM to clean-up the exception if it
     396The clean-up function is used by the EHM to clean-up the exception, if it
    374397should need to be freed at an unusual time, it takes an argument that says
    375398why it had to be cleaned up.
     
    382405messages for special cases (some of which should never be used by the
    383406personality function) and error codes. However, unless otherwise noted, the
    384 personality function should always return @_URC_CONTINUE_UNWIND@.
     407personality function always returns @_URC_CONTINUE_UNWIND@.
    385408
    386409\subsection{Raise Exception}
    387 Raising an exception is the central function of libunwind and it performs a
     410Raising an exception is the central function of libunwind and it performs
    388411two-staged unwinding.
    389412\begin{cfa}
     
    472495% catches. Talk about GCC nested functions.
    473496
    474 \CFA termination exceptions use libunwind heavily because they match \Cpp
     497\CFA termination exceptions use libunwind heavily because they match
    475498\Cpp exceptions closely. The main complication for \CFA is that the
    476499compiler generates C code, making it very difficult to generate the assembly to
     
    485508
    486509\begin{figure}
     510\centering
    487511\input{exception-layout}
    488512\caption{Exception Layout}
    489513\label{f:ExceptionLayout}
    490514\end{figure}
    491 \todo*{Convert the exception layout to an actual diagram.}
    492 
    493 Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).
     515
     516Exceptions are stored in variable-sized blocks
     517(see \autoref{f:ExceptionLayout}).
    494518The first component is a fixed-sized data structure that contains the
    495519information for libunwind and the exception system. The second component is an
     
    498522@_Unwind_Exception@ to the entire node.
    499523
    500 Multipe exceptions can exist at the same time because exceptions can be
     524Multiple exceptions can exist at the same time because exceptions can be
    501525raised inside handlers, destructors and finally blocks.
    502526Figure~\vref{f:MultipleExceptions} shows a program that has multiple
    503527exceptions active at one time.
    504528Each time an exception is thrown and caught the stack unwinds and the finally
    505 clause runs. This will throw another exception (until @num_exceptions@ gets
    506 high enough) which must be allocated. The previous exceptions may not be
     529clause runs. This handler throws another exception (until @num_exceptions@ gets
     530high enough), which must be allocated. The previous exceptions may not be
    507531freed because the handler/catch clause has not been run.
    508 So the EHM must keep them alive while it allocates exceptions for new throws.
     532Therefore, the EHM must keep all unhandled exceptions alive
     533while it allocates exceptions for new throws.
    509534
    510535\begin{figure}
     
    559584\todo*{Work on multiple exceptions code sample.}
    560585
    561 All exceptions are stored in nodes which are then linked together in lists,
     586All exceptions are stored in nodes, which are then linked together in lists
    562587one list per stack, with the
    563588list head stored in the exception context. Within each linked list, the most
     
    566591exception is being handled. The exception at the head of the list is currently
    567592being handled, while other exceptions wait for the exceptions before them to be
    568 removed.
     593handled and removed.
    569594
    570595The virtual members in the exception's virtual table provide the size of the
     
    573598exception into managed memory. After the exception is handled, the free
    574599function is used to clean up the exception and then the entire node is
    575 passed to free so the memory can be given back to the heap.
     600passed to free, returning the memory back to the heap.
    576601
    577602\subsection{Try Statements and Catch Clauses}
    578603The try statement with termination handlers is complex because it must
    579 compensate for the lack of assembly-code generated from \CFA. Libunwind
     604compensate for the C code-generation versus
     605assembly-code generated from \CFA. Libunwind
    580606requires an LSDA and personality function for control to unwind across a
    581607function. The LSDA in particular is hard to mimic in generated C code.
     
    592618embedded assembly. This assembly code is handcrafted using C @asm@ statements
    593619and contains
    594 enough information for the single try statement the function repersents.
     620enough information for a single try statement the function repersents.
    595621
    596622The three functions passed to try terminate are:
    597623\begin{description}
    598 \item[try function:] This function is the try block, all the code inside the
    599 try block is placed inside the try function. It takes no parameters and has no
     624\item[try function:] This function is the try block, it is where all the code
     625from inside the try block is placed. It takes no parameters and has no
    600626return value. This function is called during regular execution to run the try
    601627block.
     
    609635handler that matches the exception.
    610636
    611 \item[handler function:] This function handles the exception. It takes a
     637\item[handler function:] This function handles the exception, and contains
     638all the code from the handlers in the try statement, joined with a switch
     639statement on the handler's id.
     640It takes a
    612641pointer to the exception and the handler's id and returns nothing. It is called
    613 after the cleanup phase. It is constructed by stitching together the bodies of
    614 each handler and dispatches to the selected handler.
     642after the cleanup phase.
    615643\end{description}
    616644All three functions are created with GCC nested functions. GCC nested functions
    617 can be used to create closures, functions that can refer to the state of other
     645can be used to create closures,
     646in other words functions that can refer to the state of other
    618647functions on the stack. This approach allows the functions to refer to all the
    619648variables in scope for the function containing the @try@ statement. These
     
    623652Using this pattern, \CFA implements destructors with the cleanup attribute.
    624653
     654\autoref{f:TerminationTransformation} shows the pattern used to transform
     655a \CFA try statement with catch clauses into the approprate C functions.
     656\todo{Explain the Termination Transformation figure.}
     657
    625658\begin{figure}
    626659\begin{cfa}
     
    633666}
    634667\end{cfa}
     668
     669\medskip
     670\hrule
     671\medskip
     672\todo*{Termination Transformation divider feels too strong.}
    635673
    636674\begin{cfa}
     
    683721% The stack-local data, the linked list of nodes.
    684722
    685 Resumption simpler to implement than termination
     723Resumption is simpler to implement than termination
    686724because there is no stack unwinding.
    687725Instead of storing the data in a special area using assembly,
     
    692730The nodes are stored in order, with the more recent try statements closer
    693731to the head of the list.
    694 Instead of traversing the stack resumption handling traverses the list.
    695 At each node the EHM checks to see if the try statement the node repersents
     732Instead of traversing the stack, resumption handling traverses the list.
     733At each node, the EHM checks to see if the try statement the node repersents
    696734can handle the exception. If it can, then the exception is handled and
    697735the operation finishes, otherwise the search continues to the next node.
    698736If the search reaches the end of the list without finding a try statement
    699 that can handle the exception the default handler is executed and the
     737that can handle the exception, the default handler is executed and the
    700738operation finishes.
    701739
    702 In each node is a handler function which does most of the work there.
    703 The handler function is passed the raised the exception and returns true
    704 if the exception is handled and false if it cannot be handled here.
    705 
    706 For each @catchResume@ clause the handler function will:
    707 check to see if the raised exception is a descendant type of the declared
    708 exception type, if it is and there is a conditional expression then it will
    709 run the test, if both checks pass the handling code for the clause is run
    710 and the function returns true, otherwise it moves onto the next clause.
    711 If this is the last @catchResume@ clause then instead of moving onto
    712 the next clause the function returns false as no handler could be found.
     740Each node has a handler function that does most of the work.
     741The handler function is passed the raised exception and returns true
     742if the exception is handled and false otherwise.
     743
     744The handler function checks each of its internal handlers in order,
     745top-to-bottom, until it funds a match. If a match is found that handler is
     746run, after which the function returns true, ignoring all remaining handlers.
     747If no match is found the function returns false.
     748The match is performed in two steps, first a virtual cast is used to see
     749if the thrown exception is an instance of the declared exception or one of
     750its descendant type, then check to see if passes the custom predicate if one
     751is defined. This ordering gives the type guarantee used in the predicate.
     752
     753\autoref{f:ResumptionTransformation} shows the pattern used to transform
     754a \CFA try statement with catch clauses into the approprate C functions.
     755\todo{Explain the Resumption Transformation figure.}
    713756
    714757\begin{figure}
     
    722765}
    723766\end{cfa}
     767
     768\medskip
     769\hrule
     770\medskip
     771\todo*{Resumption Transformation divider feels too strong.}
    724772
    725773\begin{cfa}
     
    753801
    754802% Recursive Resumption Stuff:
    755 Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of
     803\autoref{f:ResumptionMarking} shows search skipping
     804(see \vpageref{s:ResumptionMarking}), which ignores parts of
    756805the stack
    757806already examined, is accomplished by updating the front of the list as the
     
    759808is updated to the next node of the current node. After the search is complete,
    760809successful or not, the head of the list is reset.
    761 
     810% No paragraph?
    762811This mechanism means the current handler and every handler that has already
    763812been checked are not on the list while a handler is run. If a resumption is
    764 thrown during the handling of another resumption the active handlers and all
     813thrown during the handling of another resumption, the active handlers and all
    765814the other handler checked up to this point are not checked again.
    766 
    767 This structure also supports new handler added while the resumption is being
     815% No paragraph?
     816This structure also supports new handlers added while the resumption is being
    768817handled. These are added to the front of the list, pointing back along the
    769 stack -- the first one points over all the checked handlers -- and the ordering
    770 is maintained.
     818stack --- the first one points over all the checked handlers ---
     819and the ordering is maintained.
    771820
    772821\begin{figure}
     
    774823\caption{Resumption Marking}
    775824\label{f:ResumptionMarking}
    776 \todo*{Convert Resumption Marking into a line figure.}
     825\todo*{Label Resumption Marking to aid clarity.}
    777826\end{figure}
    778827
    779828\label{p:zero-cost}
    780 Note, the resumption implementation has a cost for entering/exiting a @try@
    781 statement with @catchResume@ clauses, whereas a @try@ statement with @catch@
     829Finally, the resumption implementation has a cost for entering/exiting a try
     830statement with @catchResume@ clauses, whereas a try statement with @catch@
    782831clauses has zero-cost entry/exit. While resumption does not need the stack
    783832unwinding and cleanup provided by libunwind, it could use the search phase to
     
    810859
    811860The first step of cancellation is to find the cancelled stack and its type:
    812 coroutine or thread. Fortunately, the thread library stores the main thread
    813 pointer and the current thread pointer, and every thread stores a pointer to
    814 its main coroutine and the coroutine it is currently executing.
    815 \todo*{Consider adding a description of how threads are coroutines.}
    816 
    817 If a the current thread's main and current coroutines are the same then the
    818 current stack is a thread stack. Furthermore it is easy to compare the
    819 current thread to the main thread to see if they are the same. And if this
    820 is not a thread stack then it must be a coroutine stack.
     861coroutine, thread or main thread.
     862In \CFA, a thread (the construct the user works with) is a user-level thread
     863(point of execution) paired with a coroutine, the thread's main coroutine.
     864The thread library also stores pointers to the main thread and the current
     865thread.
     866If the current thread's main and current coroutines are the same then the
     867current stack is a thread stack, otherwise it is a coroutine stack.
     868If the current stack is a thread stack, it is also the main thread stack
     869if and only if the main and current threads are the same.
    821870
    822871However, if the threading library is not linked, the sequential execution is on
    823872the main stack. Hence, the entire check is skipped because the weak-symbol
    824 function is loaded. Therefore, a main thread cancellation is unconditionally
     873function is loaded. Therefore, main thread cancellation is unconditionally
    825874performed.
    826875
    827876Regardless of how the stack is chosen, the stop function and parameter are
    828877passed to the forced-unwind function. The general pattern of all three stop
    829 functions is the same: they continue unwinding until the end of stack and
    830 then preform their transfer.
     878functions is the same: continue unwinding until the end of stack and
     879then preform the appropriate transfer.
    831880
    832881For main stack cancellation, the transfer is just a program abort.
     
    834883For coroutine cancellation, the exception is stored on the coroutine's stack,
    835884and the coroutine context switches to its last resumer. The rest is handled on
    836 the backside of the resume, which check if the resumed coroutine is
     885the backside of the resume, which checks if the resumed coroutine is
    837886cancelled. If cancelled, the exception is retrieved from the resumed coroutine,
    838887and a @CoroutineCancelled@ exception is constructed and loaded with the
Note: See TracChangeset for help on using the changeset viewer.