- Timestamp:
- Jun 21, 2021, 4:48:11 PM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 33e1c91
- Parents:
- 029cbc0
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/implement.tex
r029cbc0 r5a4f1a8 2 2 \label{c:implement} 3 3 4 The implementation work for this thesis covers t wo components: thevirtual4 The implementation work for this thesis covers the two components: virtual 5 5 system and exceptions. Each component is discussed in detail. 6 6 … … 21 21 \todo{Talk about constructors for virtual types (after they are working).} 22 22 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 23 The virtual table pointer binds an instance of a virtual type 24 to a virtual table. 25 The pointer is also the table's id and how the system accesses the 25 26 virtual table and the virtual members there. 26 27 27 28 \subsection{Type Id} 28 29 Every virtual type has a unique id. 29 Type ids can be compared for equality (the types reperented are the same) 30 Type ids can be compared for equality, 31 which checks if the types reperented are the same, 30 32 or used to access the type's type information. 31 33 The type information currently is only the parent's type id or, if the 32 type has no parent, zero.34 type has no parent, the null pointer. 33 35 34 36 The id's are implemented as pointers to the type's type information instance. 35 Derefe ncing 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 alsopushes the issue of creating a unique value (for37 Dereferencing the pointer gets the type information. 38 The ancestors of a virtual type are found by traversing type ids through 39 the type information. 40 The information pushes the issue of creating a unique value (for 39 41 the 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 42 information), which the linker can solve. 43 44 The advanced linker support is used here to avoid having to create 45 a new declaration to attach this data to. 46 With C/\CFA's header/implementation file divide for something to appear 47 exactly once it must come from a declaration that appears in exactly one 48 implementation file; the declarations in header files may exist only once 49 they can be included in many different translation units. 50 Therefore, structure's declaration will not work. 51 Neither will attaching the type information to the virtual table -- although 52 a vtable declarations are in implemention files they are not unique, see 53 \autoref{ss:VirtualTable}. 54 Instead the same type information is generated multiple times and then 55 the new attribute \snake{cfa_linkone} is used to removed duplicates. 56 57 Type information is constructed as follows: 58 \begin{enumerate} 59 \item 60 Use the type's name to generate a name for the type information structure. 61 This is saved so it may be reused. 62 \item 63 Generate a new structure definition to store the type 53 64 information. 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, and56 the type of the parent's type id.65 but the types used change from instance to instance. 66 The generated name is used for both this structure and, if relivant, the 67 parent pointer. 57 68 If the virtual type is polymorphic then the type information structure is 58 69 polymorphic 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 71 A seperate name for instances is generated from the type's name. 72 \item 73 The definition is generated and initialised. 74 The parent id is set to the null pointer or to the address of the parent's 75 type information instance. Name resolution handles the rest. 76 \item 77 \CFA's name mangler does its regular name mangling encoding the type of 78 the declaration into the instance name. This gives a completely unique name 79 including 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 83 Writing that code manually, with helper macros for the early name mangling, 84 would look like this: 85 \begin{cfa} 86 struct INFO_TYPE(TYPE) { 87 INFO_TYPE(PARENT) const * parent; 75 88 }; 76 89 77 90 __attribute__((cfa_linkonce)) 78 TYPE_ID_TYPE const TYPE_ID_NAME= {79 & PARENT_ID_NAME,91 INFO_TYPE(TYPE) const INFO_NAME(TYPE) = { 92 &INFO_NAME(PARENT), 80 93 }; 81 94 \end{cfa} 82 95 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. 84 99 Another 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 100 This attribute is attached to an object or function definition 101 (any global declaration with a name and a type) 102 allowing it to be defined multiple times. 103 All matching definitions mush have the link-once attribute 104 and their implementations should be identical as well. 105 106 A single definition with the attribute can be included in a header 107 file as if it was a forward declaration, except no definition is required. 108 109 This technique is used for type-id instances. A link-once definition is 110 generated each time the structure is seen. This will result in multiple 111 copies but the link-once attribute ensures all but one are removed for a 112 unique instance. 113 114 Internally, @cfa_linkonce@ is replaced with 99 115 @section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the 100 116 mangled name of the object. 117 Any other @section@ attributes are removed from the declaration. 101 118 The prefix \texttt{.gnu.linkonce} in section names is recognized by the 102 linker. If two of these sections with the same name, including everything103 that comes after the special prefix, then only one will be used and the other 104 will bediscarded.119 linker. If two of these sections appear with the same name, including 120 everything that comes after the special prefix, then only one is used 121 and the other is discarded. 105 122 106 123 \subsection{Virtual Table} 124 \label{ss:VirtualTable} 107 125 Each virtual type has a virtual table type that stores its type id and 108 126 virtual members. … … 113 131 114 132 The layout always comes in three parts. 133 \todo{Add labels to the virtual table layout figure.} 115 134 The first section is just the type id at the head of the table. It is always 116 there to ensure that 135 there to ensure that it can be found even when the accessing code does not 136 know which virtual type it has. 117 137 The second section are all the virtual members of the parent, in the same 118 138 order as they appear in the parent's virtual table. Note that the type may … … 133 153 prefix that has the same layout and types as its parent virtual table. 134 154 This, 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 155 for any virtual type, it is always safe to access its virtual table and, 156 from there, it is safe to check the type id to identify the exact type of the 139 157 underlying object, access any of the virtual members and pass the object to 140 158 any of the method-like virtual members. 141 159 142 When a virtual table is declared the user decides where to declare it and its160 When a virtual table is declared, the user decides where to declare it and its 143 161 name. The initialization of the virtual table is entirely automatic based on 144 162 the context of the declaration. 145 163 146 The type id is always fixed , each virtual table type will always have one164 The type id is always fixed; with each virtual table type having 147 165 exactly one possible type id. 148 The virtual members are usually filled in by resolution. The best match for149 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 size151 and is set to the result of a @sizeof@ expression, the @align@ field isthe152 type's alignment and similarly usesan @alignof@ expression.166 The virtual members are usually filled in by type resolution. 167 The best match for a given name and type at the declaration site is used. 168 There are two exceptions to that rule: the @size@ field, the type's size, 169 is set using a @sizeof@ expression and the @align@ field, the 170 type's alignment, is set using an @alignof@ expression. 153 171 154 172 \subsubsection{Concurrency Integration} 155 173 Coroutines and threads need instances of @CoroutineCancelled@ and 156 174 @ThreadCancelled@ respectively to use all of their functionality. When a new 157 data type is declared with @coroutine@ or @thread@ theforward declaration for175 data type is declared with @coroutine@ or @thread@, a forward declaration for 158 176 the instance is created as well. The definition of the virtual table is created 159 177 at the definition of the main function. 178 179 This is showned through code re-writing in 180 \autoref{f:ConcurrencyTransformations}. 160 181 161 182 \begin{figure} … … 211 232 the cast target is passed in as @child@. 212 233 213 For C generation both arguments and the result are wrappedwith type casts.214 There is also an internal storeinside the compiler to make sure that the234 For generated C code wraps both arguments and the result with type casts. 235 There is also an internal check inside the compiler to make sure that the 215 236 target type is a virtual type. 216 237 % It also checks for conflicting definitions. 217 238 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. 239 The virtual cast either returns the original pointer or the null pointer 240 as the new type. 241 So the function does the parent check and returns the appropriate value. 220 242 The parent check is a simple linear search of child's ancestors using the 221 243 type information. … … 229 251 % resumption doesn't as well. 230 252 231 % Many modern languages work with an inter al stack that function push and pop253 % Many modern languages work with an internal stack that function push and pop 232 254 % their local data to. Stack unwinding removes large sections of the stack, 233 255 % often across functions. … … 236 258 stack. On function entry and return, unwinding is handled directly by the 237 259 call/return code embedded in the function. 238 In many cases the position of the instruction pointer (relative to parameter260 In many cases, the position of the instruction pointer (relative to parameter 239 261 and local declarations) is enough to know the current size of the stack 240 262 frame. 241 263 242 264 Usually, the stack-frame size is known statically based on parameter and 243 local variable declarations. Even with dynamic stack-size the information244 to determ ainhow much of the stack has to be removed is still contained265 local variable declarations. Even with dynamic stack-size, the information 266 to determine how much of the stack has to be removed is still contained 245 267 within the function. 246 268 Allocating/deallocating stack space is usually an $O(1)$ operation achieved by 247 269 bumping the hardware stack-pointer up or down as needed. 248 Constructing/destructing values on the stack takes longer put in terms of249 figuring out what needs to be done is of similar complexity.270 Constructing/destructing values within a stack frame has 271 a similar complexity but can add additional work and take longer. 250 272 251 273 Unwinding across multiple stack frames is more complex because that … … 261 283 reseting to a snap-shot of an arbitrary but existing function frame on the 262 284 stack. 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 p reformed.264 This approach is fragile and forces a work onto the surounding code.265 266 With respect to th at work forced ontothe surounding code,285 reset and that all required clean-up from the unwound stacks is performed. 286 This approach is fragile and requires extra work in the surrounding code. 287 288 With respect to the extra work in the surounding code, 267 289 many languages define clean-up actions that must be taken when certain 268 290 sections of the stack are removed. Such as when the storage for a variable 269 291 is removed from the stack or when a try statement with a finally clause is 270 292 (conceptually) popped from the stack. 271 None of these should be handled by the user ,that would contradict the272 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 and293 None of these should be handled by the user --- that would contradict the 294 intention of these features --- so they need to be handled automatically. 295 296 To safely remove sections of the stack, the language must be able to find and 275 297 run these clean-up actions even when removing multiple functions unknown at 276 298 the beginning of the unwinding. … … 294 316 current stack frame, and what handlers should be checked. Theoretically, the 295 317 LSDA can contain any information but conventionally it is a table with entries 296 representing regions of thefunction and what has to be done there during318 representing regions of a function and what has to be done there during 297 319 unwinding. These regions are bracketed by instruction addresses. If the 298 320 instruction pointer is within a region's start/end, then execution is currently … … 314 336 int avar __attribute__(( cleanup(clean_up) )); 315 337 \end{cfa} 316 The attribu e is used on a variable and specifies a function,338 The attribute is used on a variable and specifies a function, 317 339 in 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 340 This feature is enough to mimic destructors, 341 but not try statements which can effect 319 342 the unwinding. 320 343 321 To get full unwinding support all of this has to be done directly with322 assembly and assembler directives. Partiularly the cfi directives344 To get full unwinding support, all of these features must be handled directly 345 in assembly and assembler directives; partiularly the cfi directives 323 346 \snake{.cfi_lsda} and \snake{.cfi_personality}. 324 347 … … 327 350 section covers some of the important parts of the interface. 328 351 329 A personality function can p reform different actions depending on how it is352 A personality function can perform different actions depending on how it is 330 353 called. 331 354 \begin{lstlisting} … … 364 387 365 388 The @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 th e369 370 The \code{C}{exception} argument is a pointer to theuser389 \code{C}{exception}'s @exception_class@ field, 390 which is a number that identifies the exception handling mechanism 391 that created the exception. 392 393 The \code{C}{exception} argument is a pointer to a user 371 394 provided storage object. It has two public fields: the @exception_class@, 372 395 which is described above, and the @exception_cleanup@ function. 373 The clean-up function is used by the EHM to clean-up the exception if it396 The clean-up function is used by the EHM to clean-up the exception, if it 374 397 should need to be freed at an unusual time, it takes an argument that says 375 398 why it had to be cleaned up. … … 382 405 messages for special cases (some of which should never be used by the 383 406 personality function) and error codes. However, unless otherwise noted, the 384 personality function should always return@_URC_CONTINUE_UNWIND@.407 personality function always returns @_URC_CONTINUE_UNWIND@. 385 408 386 409 \subsection{Raise Exception} 387 Raising an exception is the central function of libunwind and it performs a410 Raising an exception is the central function of libunwind and it performs 388 411 two-staged unwinding. 389 412 \begin{cfa} … … 472 495 % catches. Talk about GCC nested functions. 473 496 474 \CFA termination exceptions use libunwind heavily because they match \Cpp497 \CFA termination exceptions use libunwind heavily because they match 475 498 \Cpp exceptions closely. The main complication for \CFA is that the 476 499 compiler generates C code, making it very difficult to generate the assembly to … … 485 508 486 509 \begin{figure} 510 \centering 487 511 \input{exception-layout} 488 512 \caption{Exception Layout} 489 513 \label{f:ExceptionLayout} 490 514 \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 516 Exceptions are stored in variable-sized blocks 517 (see \autoref{f:ExceptionLayout}). 494 518 The first component is a fixed-sized data structure that contains the 495 519 information for libunwind and the exception system. The second component is an … … 498 522 @_Unwind_Exception@ to the entire node. 499 523 500 Multip e exceptions can exist at the same time because exceptions can be524 Multiple exceptions can exist at the same time because exceptions can be 501 525 raised inside handlers, destructors and finally blocks. 502 526 Figure~\vref{f:MultipleExceptions} shows a program that has multiple 503 527 exceptions active at one time. 504 528 Each time an exception is thrown and caught the stack unwinds and the finally 505 clause runs. This will throwanother exception (until @num_exceptions@ gets506 high enough) which must be allocated. The previous exceptions may not be529 clause runs. This handler throws another exception (until @num_exceptions@ gets 530 high enough), which must be allocated. The previous exceptions may not be 507 531 freed because the handler/catch clause has not been run. 508 So the EHM must keep them alive while it allocates exceptions for new throws. 532 Therefore, the EHM must keep all unhandled exceptions alive 533 while it allocates exceptions for new throws. 509 534 510 535 \begin{figure} … … 559 584 \todo*{Work on multiple exceptions code sample.} 560 585 561 All exceptions are stored in nodes which are then linked together in lists,586 All exceptions are stored in nodes, which are then linked together in lists 562 587 one list per stack, with the 563 588 list head stored in the exception context. Within each linked list, the most … … 566 591 exception is being handled. The exception at the head of the list is currently 567 592 being handled, while other exceptions wait for the exceptions before them to be 568 removed.593 handled and removed. 569 594 570 595 The virtual members in the exception's virtual table provide the size of the … … 573 598 exception into managed memory. After the exception is handled, the free 574 599 function is used to clean up the exception and then the entire node is 575 passed to free so the memory can be givenback to the heap.600 passed to free, returning the memory back to the heap. 576 601 577 602 \subsection{Try Statements and Catch Clauses} 578 603 The try statement with termination handlers is complex because it must 579 compensate for the lack of assembly-code generated from \CFA. Libunwind 604 compensate for the C code-generation versus 605 assembly-code generated from \CFA. Libunwind 580 606 requires an LSDA and personality function for control to unwind across a 581 607 function. The LSDA in particular is hard to mimic in generated C code. … … 592 618 embedded assembly. This assembly code is handcrafted using C @asm@ statements 593 619 and contains 594 enough information for thesingle try statement the function repersents.620 enough information for a single try statement the function repersents. 595 621 596 622 The three functions passed to try terminate are: 597 623 \begin{description} 598 \item[try function:] This function is the try block, all the code inside the599 try block is placed inside the try function. It takes no parameters and has no624 \item[try function:] This function is the try block, it is where all the code 625 from inside the try block is placed. It takes no parameters and has no 600 626 return value. This function is called during regular execution to run the try 601 627 block. … … 609 635 handler that matches the exception. 610 636 611 \item[handler function:] This function handles the exception. It takes a 637 \item[handler function:] This function handles the exception, and contains 638 all the code from the handlers in the try statement, joined with a switch 639 statement on the handler's id. 640 It takes a 612 641 pointer 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. 642 after the cleanup phase. 615 643 \end{description} 616 644 All 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 645 can be used to create closures, 646 in other words functions that can refer to the state of other 618 647 functions on the stack. This approach allows the functions to refer to all the 619 648 variables in scope for the function containing the @try@ statement. These … … 623 652 Using this pattern, \CFA implements destructors with the cleanup attribute. 624 653 654 \autoref{f:TerminationTransformation} shows the pattern used to transform 655 a \CFA try statement with catch clauses into the approprate C functions. 656 \todo{Explain the Termination Transformation figure.} 657 625 658 \begin{figure} 626 659 \begin{cfa} … … 633 666 } 634 667 \end{cfa} 668 669 \medskip 670 \hrule 671 \medskip 672 \todo*{Termination Transformation divider feels too strong.} 635 673 636 674 \begin{cfa} … … 683 721 % The stack-local data, the linked list of nodes. 684 722 685 Resumption simpler to implement than termination723 Resumption is simpler to implement than termination 686 724 because there is no stack unwinding. 687 725 Instead of storing the data in a special area using assembly, … … 692 730 The nodes are stored in order, with the more recent try statements closer 693 731 to 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 repersents732 Instead of traversing the stack, resumption handling traverses the list. 733 At each node, the EHM checks to see if the try statement the node repersents 696 734 can handle the exception. If it can, then the exception is handled and 697 735 the operation finishes, otherwise the search continues to the next node. 698 736 If 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 the737 that can handle the exception, the default handler is executed and the 700 738 operation finishes. 701 739 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. 740 Each node has a handler function that does most of the work. 741 The handler function is passed the raised exception and returns true 742 if the exception is handled and false otherwise. 743 744 The handler function checks each of its internal handlers in order, 745 top-to-bottom, until it funds a match. If a match is found that handler is 746 run, after which the function returns true, ignoring all remaining handlers. 747 If no match is found the function returns false. 748 The match is performed in two steps, first a virtual cast is used to see 749 if the thrown exception is an instance of the declared exception or one of 750 its descendant type, then check to see if passes the custom predicate if one 751 is defined. This ordering gives the type guarantee used in the predicate. 752 753 \autoref{f:ResumptionTransformation} shows the pattern used to transform 754 a \CFA try statement with catch clauses into the approprate C functions. 755 \todo{Explain the Resumption Transformation figure.} 713 756 714 757 \begin{figure} … … 722 765 } 723 766 \end{cfa} 767 768 \medskip 769 \hrule 770 \medskip 771 \todo*{Resumption Transformation divider feels too strong.} 724 772 725 773 \begin{cfa} … … 753 801 754 802 % 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 756 805 the stack 757 806 already examined, is accomplished by updating the front of the list as the … … 759 808 is updated to the next node of the current node. After the search is complete, 760 809 successful or not, the head of the list is reset. 761 810 % No paragraph? 762 811 This mechanism means the current handler and every handler that has already 763 812 been 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 all813 thrown during the handling of another resumption, the active handlers and all 765 814 the other handler checked up to this point are not checked again. 766 767 This structure also supports new handler added while the resumption is being815 % No paragraph? 816 This structure also supports new handlers added while the resumption is being 768 817 handled. 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 ordering770 is maintained.818 stack --- the first one points over all the checked handlers --- 819 and the ordering is maintained. 771 820 772 821 \begin{figure} … … 774 823 \caption{Resumption Marking} 775 824 \label{f:ResumptionMarking} 776 \todo*{ Convert Resumption Marking into a line figure.}825 \todo*{Label Resumption Marking to aid clarity.} 777 826 \end{figure} 778 827 779 828 \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@829 Finally, the resumption implementation has a cost for entering/exiting a try 830 statement with @catchResume@ clauses, whereas a try statement with @catch@ 782 831 clauses has zero-cost entry/exit. While resumption does not need the stack 783 832 unwinding and cleanup provided by libunwind, it could use the search phase to … … 810 859 811 860 The first step of cancellation is to find the cancelled stack and its type: 812 coroutine or thread. Fortunately, the thread library stores the main thread813 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 athe current thread's main and current coroutines are the same then the818 current stack is a thread stack . Furthermore it is easy to compare the819 current thread to the main thread to see if they are the same. And if this 820 i s not a thread stack then it must be a coroutine stack.861 coroutine, thread or main thread. 862 In \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. 864 The thread library also stores pointers to the main thread and the current 865 thread. 866 If the current thread's main and current coroutines are the same then the 867 current stack is a thread stack, otherwise it is a coroutine stack. 868 If the current stack is a thread stack, it is also the main thread stack 869 if and only if the main and current threads are the same. 821 870 822 871 However, if the threading library is not linked, the sequential execution is on 823 872 the main stack. Hence, the entire check is skipped because the weak-symbol 824 function is loaded. Therefore, amain thread cancellation is unconditionally873 function is loaded. Therefore, main thread cancellation is unconditionally 825 874 performed. 826 875 827 876 Regardless of how the stack is chosen, the stop function and parameter are 828 877 passed to the forced-unwind function. The general pattern of all three stop 829 functions is the same: theycontinue unwinding until the end of stack and830 then preform the irtransfer.878 functions is the same: continue unwinding until the end of stack and 879 then preform the appropriate transfer. 831 880 832 881 For main stack cancellation, the transfer is just a program abort. … … 834 883 For coroutine cancellation, the exception is stored on the coroutine's stack, 835 884 and 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 is885 the backside of the resume, which checks if the resumed coroutine is 837 886 cancelled. If cancelled, the exception is retrieved from the resumed coroutine, 838 887 and a @CoroutineCancelled@ exception is constructed and loaded with the
Note: See TracChangeset
for help on using the changeset viewer.