[26ca815] | 1 | \chapter{Implementation}
|
---|
| 2 | % Goes over how all the features are implemented.
|
---|
| 3 |
|
---|
| 4 | \section{Virtual System}
|
---|
| 5 | % Virtual table rules. Virtual tables, the pointer to them and the cast.
|
---|
| 6 | The \CFA virtual system only has one public facing feature: virtual casts.
|
---|
| 7 | However there is a lot of structure to support that and provide some other
|
---|
| 8 | features for the standard library.
|
---|
| 9 |
|
---|
| 10 | All of this is accessed through a field inserted at the beginning of every
|
---|
[f28fdee] | 11 | virtual type. Currently it is called @virtual_table@ but it is not
|
---|
[26ca815] | 12 | ment to be accessed by the user. This field is a pointer to the type's
|
---|
| 13 | virtual table instance. It is assigned once during the object's construction
|
---|
| 14 | and left alone after that.
|
---|
| 15 |
|
---|
| 16 | \subsection{Virtual Table Construction}
|
---|
| 17 | For each virtual type a virtual table is constructed. This is both a new type
|
---|
| 18 | and an instance of that type. Other instances of the type could be created
|
---|
| 19 | but the system doesn't use them. So this section will go over the creation of
|
---|
| 20 | the type and the instance.
|
---|
| 21 |
|
---|
| 22 | Creating the single instance is actually very important. The address of the
|
---|
| 23 | table acts as the unique identifier for the virtual type. Similarly the first
|
---|
| 24 | field in every virtual table is the parent's id; a pointer to the parent
|
---|
| 25 | virtual table instance.
|
---|
| 26 |
|
---|
| 27 | The remaining fields contain the type's virtual members. First come the ones
|
---|
| 28 | present on the parent type, in the same order as they were the parent, and
|
---|
| 29 | then any that this type introduces. The types of the ones inherited from the
|
---|
| 30 | parent may have a slightly modified type, in that references to the
|
---|
| 31 | dispatched type are replaced with the current virtual type. These are always
|
---|
| 32 | taken by pointer or reference.
|
---|
| 33 |
|
---|
| 34 | The structure itself is created where the virtual type is created. The name
|
---|
| 35 | of the type is created by mangling the name of the base type. The name of the
|
---|
| 36 | instance is also generated by name mangling.
|
---|
| 37 |
|
---|
| 38 | The fields are initialized automatically.
|
---|
| 39 | The parent field is initialized by getting the type of the parent field and
|
---|
| 40 | using that to calculate the mangled name of the parent's virtual table type.
|
---|
| 41 | There are two special fields that are included like normal fields but have
|
---|
[f28fdee] | 42 | special initialization rules: the @size@ field is the type's size and is
|
---|
| 43 | initialized with a sizeof expression, the @align@ field is the type's
|
---|
[26ca815] | 44 | alignment and uses an alignof expression. The remaining fields are resolved
|
---|
| 45 | to a name matching the field's name and type using the normal visibility
|
---|
| 46 | and overload resolution rules of the type system.
|
---|
| 47 |
|
---|
| 48 | These operations are split up into several groups depending on where they
|
---|
| 49 | take place which can vary for monomorphic and polymorphic types. The first
|
---|
| 50 | devision is between the declarations and the definitions. Declarations, such
|
---|
| 51 | as a function signature or a structure's name, must always be visible but may
|
---|
| 52 | be repeated so they go in headers. Definitions, such as function bodies and a
|
---|
| 53 | structure's layout, don't have to be visible on use but must occur exactly
|
---|
| 54 | once and go into source files.
|
---|
| 55 |
|
---|
| 56 | The declarations include the virtual type definition and forward declarations
|
---|
| 57 | of the virtual table instance, constructor, message function and
|
---|
[f28fdee] | 58 | @get_exception_vtable@. The definition includes the storage and
|
---|
[26ca815] | 59 | initialization of the virtual table instance and the bodies of the three
|
---|
| 60 | functions.
|
---|
| 61 |
|
---|
| 62 | Monomorphic instances put all of these two groups in one place each.
|
---|
| 63 |
|
---|
| 64 | Polymorphic instances also split out the core declarations and definitions
|
---|
| 65 | from the per-instance information. The virtual table type and most of the
|
---|
| 66 | functions are polymorphic so they are all part of the core. The virtual table
|
---|
[f28fdee] | 67 | instance and the @get_exception_vtable@ function.
|
---|
[26ca815] | 68 |
|
---|
[f28fdee] | 69 | Coroutines and threads need instances of @CoroutineCancelled@ and
|
---|
| 70 | @ThreadCancelled@ respectively to use all of their functionality.
|
---|
| 71 | When a new data type is declared with @coroutine@ or @thread@
|
---|
[26ca815] | 72 | the forward declaration for the instance is created as well. The definition
|
---|
| 73 | of the virtual table is created at the definition of the main function.
|
---|
| 74 |
|
---|
| 75 | \subsection{Virtual Cast}
|
---|
| 76 | Virtual casts are implemented as a function call that does the check and a
|
---|
| 77 | old C-style cast to do the type conversion. The C-cast is just to make sure
|
---|
| 78 | the generated code is correct so the rest of the section is about that
|
---|
| 79 | function.
|
---|
| 80 |
|
---|
[f28fdee] | 81 | The function is @__cfa__virtual_cast@ and it is implemented in the
|
---|
[26ca815] | 82 | standard library. It takes a pointer to the target type's virtual table and
|
---|
| 83 | the object pointer being cast. The function is very simple, getting the
|
---|
| 84 | object's virtual table pointer and then checking to see if it or any of
|
---|
| 85 | its ancestors, by using the parent pointers, are the same as the target type
|
---|
| 86 | virtual table pointer. It does this in a simple loop.
|
---|
| 87 |
|
---|
| 88 | For the generated code a forward decaration of the virtual works as follows.
|
---|
[f28fdee] | 89 | There is a forward declaration of @__cfa__virtual_cast@ in every cfa
|
---|
[26ca815] | 90 | file so it can just be used. The object argument is the expression being cast
|
---|
| 91 | so that is just placed in the argument list.
|
---|
| 92 |
|
---|
| 93 | To build the target type parameter the compiler will create a mapping from
|
---|
| 94 | concrete type-name -- so for polymorphic types the parameters are filled in
|
---|
| 95 | -- to virtual table address. Every virtual table declaraction is added to the
|
---|
| 96 | this table; repeats are ignored unless they have conflicting definitions.
|
---|
| 97 | This does mean the declaractions have to be in scope, but they should usually
|
---|
| 98 | be introduced as part of the type definition.
|
---|
| 99 |
|
---|
| 100 | \section{Exceptions}
|
---|
| 101 | % Anything about exception construction.
|
---|
| 102 |
|
---|
| 103 | \section{Unwinding}
|
---|
| 104 | % Adapt the unwind chapter, just describe the sections of libunwind used.
|
---|
| 105 | % Mention that termination and cancellation use it. Maybe go into why
|
---|
| 106 | % resumption doesn't as well.
|
---|
| 107 |
|
---|
| 108 | Many modern languages work with an interal stack that function push and pop
|
---|
| 109 | their local data to. Stack unwinding removes large sections of the stack,
|
---|
| 110 | often across functions.
|
---|
| 111 |
|
---|
[f28fdee] | 112 | At a very basic level this can be done with @setjmp@ \& @longjmp@
|
---|
[26ca815] | 113 | which simply move the top of the stack, discarding everything on the stack
|
---|
| 114 | above a certain point. However this ignores all the clean-up code that should
|
---|
| 115 | be run when certain sections of the stack are removed (for \CFA these are from
|
---|
| 116 | destructors and finally clauses) and also requires that the point to which the
|
---|
| 117 | stack is being unwound is known ahead of time. libunwind is used to address
|
---|
| 118 | both of these problems.
|
---|
| 119 |
|
---|
[f28fdee] | 120 | Libunwind, provided in @unwind.h@ on most platorms, is a C library
|
---|
[26ca815] | 121 | that provides \CPP style stack unwinding. Its operation is divided into two
|
---|
| 122 | phases. The search phase -- phase 1 -- is used to scan the stack and decide
|
---|
| 123 | where the unwinding will stop, this allows for a dynamic target. The clean-up
|
---|
| 124 | phase -- phase 2 -- does the actual unwinding and also runs any clean-up code
|
---|
| 125 | as it goes.
|
---|
| 126 |
|
---|
| 127 | To use the libunwind each function must have a personality function and an
|
---|
| 128 | LSDA (Language Specific Data Area). Libunwind actually does very little, it
|
---|
| 129 | simply moves down the stack from function to function. Most of the actions are
|
---|
| 130 | implemented by the personality function which libunwind calls on every
|
---|
| 131 | function. Since this is shared across many functions or even every function in
|
---|
| 132 | a language it will need a bit more information. This is provided by the LSDA
|
---|
| 133 | which has the unique information for each function.
|
---|
| 134 |
|
---|
| 135 | Theoretically the LSDA can contain anything but conventionally it is a table
|
---|
| 136 | with entries reperenting areas of the function and what has to be done there
|
---|
| 137 | during unwinding. These areas are described in terms of where the instruction
|
---|
| 138 | pointer is. If the current value of the instruction pointer is between two
|
---|
| 139 | values reperenting the beginning and end of a region then execution is
|
---|
| 140 | currently being executed. These are used to mark out try blocks and the
|
---|
| 141 | scopes of objects with destructors to run.
|
---|
| 142 |
|
---|
| 143 | GCC will generate an LSDA and attach its personality function with the
|
---|
[f28fdee] | 144 | @-fexceptions@ flag. However this only handles the cleanup attribute.
|
---|
[26ca815] | 145 | This attribute is used on a variable and specifies a function that should be
|
---|
| 146 | run when the variable goes out of scope. The function is passed a pointer to
|
---|
| 147 | the object as well so it can be used to mimic destructors. It however cannot
|
---|
| 148 | be used to mimic try statements.
|
---|
| 149 |
|
---|
| 150 | \subsection{Implementing Personality Functions}
|
---|
| 151 | Personality functions have a complex interface specified by libunwind.
|
---|
| 152 | This section will cover some of the important parts of that interface.
|
---|
| 153 |
|
---|
| 154 | \begin{lstlisting}
|
---|
| 155 | typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
|
---|
| 156 | int version,
|
---|
| 157 | _Unwind_Action action,
|
---|
| 158 | _Unwind_Exception_Class exception_class,
|
---|
| 159 | _Unwind_Exception * exception,
|
---|
| 160 | struct _Unwind_Context * context);
|
---|
| 161 | \end{lstlisting}
|
---|
| 162 |
|
---|
| 163 | The return value, the reason code, is an enumeration of possible messages
|
---|
| 164 | that can be passed several places in libunwind. It includes a number of
|
---|
| 165 | messages for special cases (some of which should never be used by the
|
---|
| 166 | personality function) and error codes but unless otherwise noted the
|
---|
[f28fdee] | 167 | personality function should always return @_URC_CONTINUE_UNWIND@.
|
---|
[26ca815] | 168 |
|
---|
[f28fdee] | 169 | The @version@ argument is the verson of the implementation that is
|
---|
[26ca815] | 170 | calling the personality function. At this point it appears to always be 1 and
|
---|
| 171 | it will likely stay that way until a new version of the API is updated.
|
---|
| 172 |
|
---|
[f28fdee] | 173 | The @action@ argument is set of flags that tell the personality
|
---|
[26ca815] | 174 | function when it is being called and what it must do on this invocation.
|
---|
| 175 | The flags are as follows:
|
---|
| 176 | \begin{itemize}
|
---|
[f28fdee] | 177 | \item@_UA_SEARCH_PHASE@: This flag is set whenever the personality
|
---|
[26ca815] | 178 | function is called during the search phase. The personality function should
|
---|
| 179 | decide if unwinding will stop in this function or not. If it does then the
|
---|
[f28fdee] | 180 | personality function should return @_URC_HANDLER_FOUND@.
|
---|
| 181 | \item@_UA_CLEANUP_PHASE@: This flag is set whenever the personality
|
---|
[26ca815] | 182 | function is called during the cleanup phase. If no other flags are set this
|
---|
| 183 | means the entire frame will be unwound and all cleanup code should be run.
|
---|
[f28fdee] | 184 | \item@_UA_HANDLER_FRAME@: This flag is set during the cleanup phase
|
---|
[26ca815] | 185 | on the function frame that found the handler. The personality function must
|
---|
| 186 | prepare to return to normal code execution and return
|
---|
[f28fdee] | 187 | @_URC_INSTALL_CONTEXT@.
|
---|
| 188 | \item@_UA_FORCE_UNWIND@: This flag is set if the personality function
|
---|
[26ca815] | 189 | is called through a forced unwind call. Forced unwind only performs the
|
---|
| 190 | cleanup phase and uses a different means to decide when to stop. See its
|
---|
| 191 | section below.
|
---|
| 192 | \end{itemize}
|
---|
| 193 |
|
---|
[f28fdee] | 194 | The @exception_class@ argument is a copy of the @exception@'s
|
---|
| 195 | @exception_class@ field.
|
---|
[26ca815] | 196 |
|
---|
[f28fdee] | 197 | The @exception@ argument is a pointer to the user provided storage
|
---|
[26ca815] | 198 | object. It has two public fields, the exception class which is actually just
|
---|
| 199 | a number that identifies the exception handling mechanism that created it and
|
---|
| 200 | the other is the clean-up function. The clean-up function is called if the
|
---|
| 201 | exception needs to
|
---|
| 202 |
|
---|
[f28fdee] | 203 | The @context@ argument is a pointer to an opaque type. This is passed
|
---|
[26ca815] | 204 | to the many helper functions that can be called inside the personality
|
---|
| 205 | function.
|
---|
| 206 |
|
---|
| 207 | \subsection{Raise Exception}
|
---|
| 208 | This could be considered the central function of libunwind. It preforms the
|
---|
| 209 | two staged unwinding the library is built around and most of the rest of the
|
---|
| 210 | interface of libunwind is here to support it. It's signature is as follows:
|
---|
| 211 |
|
---|
| 212 | \begin{lstlisting}
|
---|
| 213 | _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *);
|
---|
| 214 | \end{lstlisting}
|
---|
| 215 |
|
---|
| 216 | When called the function begins the search phase, calling the personality
|
---|
| 217 | function of the most recent stack frame. It will continue to call personality
|
---|
| 218 | functions traversing the stack new-to-old until a function finds a handler or
|
---|
| 219 | the end of the stack is reached. In the latter case raise exception will
|
---|
[f28fdee] | 220 | return with @_URC_END_OF_STACK@.
|
---|
[26ca815] | 221 |
|
---|
| 222 | Once a handler has been found raise exception continues onto the the cleanup
|
---|
| 223 | phase. Once again it will call the personality functins of each stack frame
|
---|
| 224 | from newest to oldest. This pass will stop at the stack frame that found the
|
---|
| 225 | handler last time, if that personality function does not install the handler
|
---|
| 226 | it is an error.
|
---|
| 227 |
|
---|
| 228 | If an error is encountered raise exception will return either
|
---|
[f28fdee] | 229 | @_URC_FATAL_PHASE1_ERROR@ or @_URC_FATAL_PHASE2_ERROR@ depending
|
---|
[26ca815] | 230 | on when the error occured.
|
---|
| 231 |
|
---|
| 232 | \subsection{Forced Unwind}
|
---|
| 233 | This is the second big function in libunwind. It also unwinds a stack but it
|
---|
| 234 | does not use the search phase. Instead another function, the stop function,
|
---|
| 235 | is used to decide when to stop.
|
---|
| 236 |
|
---|
| 237 | \begin{lstlisting}
|
---|
| 238 | _Unwind_Reason_Code _Unwind_ForcedUnwind(
|
---|
| 239 | _Unwind_Exception *, _Unwind_Stop_Fn, void *);
|
---|
| 240 | \end{lstlisting}
|
---|
| 241 |
|
---|
| 242 | The exception is the same as the one passed to raise exception. The extra
|
---|
| 243 | arguments are the stop function and the stop parameter. The stop function has
|
---|
| 244 | a similar interface as a personality function, except it is also passed the
|
---|
| 245 | stop parameter.
|
---|
| 246 |
|
---|
| 247 | \begin{lstlisting}
|
---|
| 248 | typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(
|
---|
| 249 | int version,
|
---|
| 250 | _Unwind_Action action,
|
---|
| 251 | _Unwind_Exception_Class exception_class,
|
---|
| 252 | _Unwind_Exception * exception,
|
---|
| 253 | struct _Unwind_Context * context,
|
---|
| 254 | void * stop_parameter);
|
---|
| 255 | \end{lstlisting}
|
---|
| 256 |
|
---|
| 257 | The stop function is called at every stack frame before the personality
|
---|
| 258 | function is called and then once more once after all frames of the stack have
|
---|
| 259 | been unwound.
|
---|
| 260 |
|
---|
[f28fdee] | 261 | Each time it is called the stop function should return @_URC_NO_REASON@
|
---|
[26ca815] | 262 | or transfer control directly to other code outside of libunwind. The
|
---|
| 263 | framework does not provide any assistance here.
|
---|
| 264 |
|
---|
| 265 | Its arguments are the same as the paired personality function.
|
---|
[f28fdee] | 266 | The actions @_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always
|
---|
[26ca815] | 267 | set when it is called. By the official standard that is all but both GCC and
|
---|
| 268 | Clang add an extra action on the last call at the end of the stack:
|
---|
[f28fdee] | 269 | @_UA_END_OF_STACK@.
|
---|
[26ca815] | 270 |
|
---|
| 271 | \section{Exception Context}
|
---|
| 272 | % Should I have another independent section?
|
---|
| 273 | % There are only two things in it, top_resume and current_exception. How it is
|
---|
| 274 | % stored changes depending on wheither or not the thread-library is linked.
|
---|
| 275 |
|
---|
| 276 | The exception context is a piece of global storage used to maintain data
|
---|
| 277 | across different exception operations and to communicate between different
|
---|
| 278 | components.
|
---|
| 279 |
|
---|
| 280 | Each stack has its own exception context. In a purely sequental program, using
|
---|
| 281 | only core Cforall, there is only one stack and the context is global. However
|
---|
[f28fdee] | 282 | if the library @libcfathread@ is linked then there can be multiple
|
---|
[26ca815] | 283 | stacks so they will each need their own.
|
---|
| 284 |
|
---|
| 285 | To handle this code always gets the exception context from the function
|
---|
[f28fdee] | 286 | @this_exception_context@. The main exception handling code is in
|
---|
| 287 | @libcfa@ and that library also defines the function as a weak symbol
|
---|
| 288 | so it acts as a default. Meanwhile in @libcfathread@ the function is
|
---|
[26ca815] | 289 | defined as a strong symbol that replaces it when the libraries are linked
|
---|
| 290 | together.
|
---|
| 291 |
|
---|
[f28fdee] | 292 | The version of the function defined in @libcfa@ is very simple. It
|
---|
[26ca815] | 293 | returns a pointer to a global static variable. With only one stack this
|
---|
| 294 | global instance is associated with the only stack.
|
---|
| 295 |
|
---|
[f28fdee] | 296 | The version of the function defined in @libcfathread@ has to handle
|
---|
[26ca815] | 297 | more as there are multiple stacks. The exception context is included as
|
---|
| 298 | part of the per-stack data stored as part of coroutines. In the cold data
|
---|
| 299 | section, stored at the base of each stack, is the exception context for that
|
---|
[f28fdee] | 300 | stack. The @this_exception_context@ uses the concurrency library to get
|
---|
[26ca815] | 301 | the current coroutine and through it the cold data section and the exception
|
---|
| 302 | context.
|
---|
| 303 |
|
---|
| 304 | \section{Termination}
|
---|
| 305 | % Memory management & extra information, the custom function used to implement
|
---|
| 306 | % catches. Talk about GCC nested functions.
|
---|
| 307 |
|
---|
| 308 | Termination exceptions use libunwind quite heavily because it matches the
|
---|
| 309 | intended use from \CPP exceptions very closely. The main complication is that
|
---|
| 310 | since the \CFA compiler works by translating to C code it cannot generate the
|
---|
| 311 | assembly to form the LSDA for try blocks or destructors.
|
---|
| 312 |
|
---|
| 313 | \subsection{Memory Management}
|
---|
| 314 | The first step of termination is to copy the exception into memory managed by
|
---|
| 315 | the exception system. Currently the system just uses malloc, without reserved
|
---|
| 316 | memory or and ``small allocation" optimizations. The exception handling
|
---|
| 317 | mechanism manages memory for the exception as well as memory for libunwind
|
---|
| 318 | and the system's own per-exception storage.
|
---|
| 319 |
|
---|
| 320 | Exceptions are stored in variable sized block. The first component is a fixed
|
---|
| 321 | sized data structure that contains the information for libunwind and the
|
---|
| 322 | exception system. The second component is a blob of memory that is big enough
|
---|
| 323 | to store the exception. Macros with pointer arthritic and type cast are
|
---|
| 324 | used to move between the components or go from the embedded
|
---|
[f28fdee] | 325 | @_Unwind_Exception@ to the entire node.
|
---|
[26ca815] | 326 |
|
---|
| 327 | All of these nodes are strung together in a linked list. One linked list per
|
---|
| 328 | stack, with the head stored in the exception context. Within each linked list
|
---|
| 329 | the most recently thrown exception is at the head and the older exceptions
|
---|
| 330 | are further down the list. This list format allows exceptions to be thrown
|
---|
| 331 | while a different exception is being handled. Only the exception at the head
|
---|
| 332 | of the list is currently being handled, the other will wait for the
|
---|
| 333 | exceptions before them to be removed.
|
---|
| 334 |
|
---|
| 335 | The virtual members in the exception's virtual table. The size of the
|
---|
| 336 | exception, the copy function and the free function are all in the virtual
|
---|
| 337 | table so they are decided per-exception type. The size and copy function are
|
---|
| 338 | used right away when the exception is copied in to managed memory. After the
|
---|
| 339 | exception is handled the free function is used to clean up the exception and
|
---|
| 340 | then the entire node is passed to free.
|
---|
| 341 |
|
---|
| 342 | \subsection{Try Statements \& Catch Clauses}
|
---|
| 343 | The try statements with termination handlers have a pretty complex conversion
|
---|
| 344 | to compensate for the lack of assembly generation. Libunwind requires an LSDA
|
---|
| 345 | (Language Specific Data Area) and personality function for a function to
|
---|
| 346 | unwind across it. The LSDA in particular is hard to generate at the level of
|
---|
| 347 | C which is what the \CFA compiler outputs so a work-around is used.
|
---|
| 348 |
|
---|
[f28fdee] | 349 | This work around is a function called @__cfaehm_try_terminate@ in the
|
---|
[26ca815] | 350 | standard library. The contents of a try block and the termination handlers
|
---|
| 351 | are converted into functions. These are then passed to the try terminate
|
---|
| 352 | function and it calls them. This puts the try statements in their own
|
---|
| 353 | functions so that no function has to deal with both termination handlers and
|
---|
| 354 | destructors.
|
---|
| 355 |
|
---|
| 356 | This function has some custom embedded assembly that defines its personality
|
---|
| 357 | function and LSDA. This is hand coded in C which is why there is only one
|
---|
| 358 | version of it, the compiler has no capability to generate it. The personality
|
---|
| 359 | function is structured so that it may be expanded, but really it only handles
|
---|
| 360 | this one function. Notably it does not handle any destructors so the function
|
---|
| 361 | is constructed so that it does need to run it.
|
---|
| 362 |
|
---|
| 363 | The three functions passed to try terminate are:
|
---|
| 364 | \begin{itemize}
|
---|
| 365 | \item The try function: This function is the try block, all the code inside
|
---|
| 366 | the try block is placed inside the try function. It takes no parameters and
|
---|
| 367 | has no return value. This function is called during regular execution to run
|
---|
| 368 | the try block.
|
---|
| 369 | \item The match function: This function decides if this try statement should
|
---|
| 370 | handle any given termination exception. It takes a pointer to the exception
|
---|
| 371 | and returns 0 if the exception is not handled here. Otherwise the return value
|
---|
| 372 | is the id of the handler that should handle the exception. It is called
|
---|
| 373 | during the search phase.
|
---|
| 374 | It is constructed from the conditional part of each handler. It runs each
|
---|
| 375 | check in turn, first checking to see if the object
|
---|
| 376 | \item The catch function: This function handles the exception. It takes a
|
---|
| 377 | pointer to the exception and the handler's id and returns nothing. It is
|
---|
| 378 | called after the clean-up phase.
|
---|
| 379 | It is constructed by stitching together the bodies of each handler
|
---|
| 380 | \end{itemize}
|
---|
| 381 | All three are created with GCC nested functions. GCC nested functions can be
|
---|
| 382 | used to create closures, functions that can refer to the state of other
|
---|
| 383 | functions on the stack. This allows the functions to refer to the main
|
---|
| 384 | function and all the variables in scope.
|
---|
| 385 |
|
---|
| 386 | These nested functions and all other functions besides
|
---|
[f28fdee] | 387 | @__cfaehm_try_terminate@ in \CFA use the GCC personality function and
|
---|
| 388 | the @-fexceptions@ flag to generate the LSDA. This allows destructors
|
---|
[26ca815] | 389 | to be implemented with the cleanup attribute.
|
---|
| 390 |
|
---|
| 391 | \section{Resumption}
|
---|
| 392 | % The stack-local data, the linked list of nodes.
|
---|
| 393 |
|
---|
| 394 | Resumption uses a list of nodes for its stack traversal. The head of the list
|
---|
| 395 | is stored in the exception context. The nodes in the list just have a pointer
|
---|
| 396 | to the next node and a pointer to the handler function.
|
---|
| 397 |
|
---|
| 398 | The on a resumption throw the this list is traversed. At each node the
|
---|
| 399 | handler function is called and is passed the exception by pointer. It returns
|
---|
| 400 | true if the exception was handled and false otherwise.
|
---|
| 401 |
|
---|
| 402 | The handler function does both the matching and catching. It tries each
|
---|
[f28fdee] | 403 | the condition of @catchResume@ in order, top-to-bottom and until it
|
---|
[26ca815] | 404 | finds a handler that matches. If no handler matches then the function returns
|
---|
| 405 | false. Otherwise the matching handler is run, if it completes successfully
|
---|
[f28fdee] | 406 | the function returns true. Rethrows, through the @throwResume;@
|
---|
[26ca815] | 407 | statement, cause the function to return true.
|
---|
| 408 |
|
---|
[12b4ab4] | 409 | % Recursive Resumption Stuff:
|
---|
| 410 | Blocking out part of the stack is accomplished by updating the front of the
|
---|
| 411 | list as the search continues. Before the handler at a node is called the head
|
---|
| 412 | of the list is updated to the next node of the current node. After the search
|
---|
| 413 | is complete, successful or not, the head of the list is reset.
|
---|
| 414 |
|
---|
| 415 | This means the current handler and every handler that has already been
|
---|
| 416 | checked are not on the list while a handler is run. If a resumption is thrown
|
---|
| 417 | during the handling of another resumption the active handlers and all the
|
---|
| 418 | other handler checked up to this point will not be checked again.
|
---|
| 419 |
|
---|
| 420 | This structure also supports new handler added while the resumption is being
|
---|
| 421 | handled. These are added to the front of the list, pointing back along the
|
---|
| 422 | stack -- the first one will point over all the checked handlers -- and the
|
---|
| 423 | ordering is maintained.
|
---|
| 424 |
|
---|
[26ca815] | 425 | \subsection{Libunwind Compatibility}
|
---|
| 426 | Resumption does not use libunwind for two simple reasons. The first is that
|
---|
| 427 | it does not have to unwind anything so would never need to use the clean-up
|
---|
| 428 | phase. Still the search phase could be used to make it free to enter or exit
|
---|
| 429 | a try statement with resumption handlers in the same way termination handlers
|
---|
| 430 | are for the same trade off in the cost of the throw. This is where the second
|
---|
| 431 | reason comes in, there is no way to return from a search without installing
|
---|
| 432 | a handler or raising an error.
|
---|
| 433 |
|
---|
| 434 | Although work arounds could be created none seemed to be worth it for the
|
---|
| 435 | prototype. This implementation has no difference in behaviour and is much
|
---|
| 436 | simpler.
|
---|
| 437 | % Seriously, just compare the size of the two chapters and then consider
|
---|
| 438 | % that unwind is required knowledge for that chapter.
|
---|
| 439 |
|
---|
| 440 | \section{Finally}
|
---|
| 441 | % Uses destructors and GCC nested functions.
|
---|
| 442 | Finally clauses are a simple decomposition to some of the existing features.
|
---|
| 443 | The code in the block is placed into a GCC nested function with a unique name,
|
---|
| 444 | no arguments or return values. This nested function is then set as the
|
---|
| 445 | clean-up function of an empty object that is declared at the beginning of a
|
---|
| 446 | block placed around the contexts of the try statement.
|
---|
| 447 |
|
---|
| 448 | The rest is handled by GCC. The try block and all handlers are inside the
|
---|
| 449 | block. When they are complete control exits the block and the empty object
|
---|
| 450 | is cleaned up, which runs the function that contains the finally code.
|
---|
| 451 |
|
---|
| 452 | \section{Cancellation}
|
---|
| 453 | % Stack selections, the three internal unwind functions.
|
---|
| 454 |
|
---|
| 455 | Cancellation also uses libunwind to do its stack traversal and unwinding,
|
---|
[f28fdee] | 456 | however it uses a different primary function @_Unwind_ForcedUnwind@.
|
---|
[26ca815] | 457 | Details of its interface can be found in the unwind section.
|
---|
| 458 |
|
---|
| 459 | The first step of cancellation is to find the stack was cancelled and which
|
---|
| 460 | type of stack it is. Luckily the threads library stores the main thread
|
---|
| 461 | pointer and the current thread pointer and every thread stores a pointer to
|
---|
| 462 | its main coroutine and the coroutine it is currently executing.
|
---|
| 463 |
|
---|
| 464 | So if the the current thread's main and current coroutine do not match, it is
|
---|
| 465 | a coroutine cancellation. Otherwise if the main and current thread do not
|
---|
| 466 | match, it is a thread cancellation. Otherwise it is a main thread
|
---|
| 467 | cancellation.
|
---|
| 468 |
|
---|
| 469 | However if the threading library is not linked then execution must be on the
|
---|
| 470 | main stack as that is the only one that exists. So the entire check is skipped
|
---|
| 471 | using the linker and weak symbols. Instead the main thread cancellation is
|
---|
| 472 | unconditionally preformed.
|
---|
| 473 |
|
---|
| 474 | Regardless of how they are choosen afterwords the stop function and the stop
|
---|
| 475 | parameter are passed to the forced unwind functon. The general pattern of all
|
---|
| 476 | three stop functions is the same, they continue unwinding until the end of
|
---|
| 477 | stack when they do there primary work.
|
---|
| 478 |
|
---|
| 479 | Main stack cancellation it is very simple. The ``transfer" is just an abort,
|
---|
| 480 | the program stops executing.
|
---|
| 481 |
|
---|
| 482 | The coroutine cancellation stores the exception on the coroutine and then
|
---|
| 483 | does a coroutine context switch. The rest is handled inside resume. Every time
|
---|
| 484 | control returns from a resumed thread there is a check to see if it is
|
---|
| 485 | cancelled. If it is the exception is retrieved and the CoroutineCancelled
|
---|
| 486 | exception is constructed and loaded. It is then thrown as a regular exception
|
---|
| 487 | with the default handler coming from the context of the resumption call.
|
---|
| 488 |
|
---|
| 489 | The thread cancellation stores the exception on the thread's main stack and
|
---|
| 490 | then returns to the scheduler. The rest is handled by the joiner. The wait
|
---|
| 491 | for the joined thread to finish works the same but after that it checks
|
---|
| 492 | to see if there was a cancellation. If there was the exception is retrieved
|
---|
| 493 | and the ThreadCancelled exception is constructed. The default handler is
|
---|
| 494 | passed in as a function pointer. If it is null (as it is for the
|
---|
| 495 | auto-generated joins on destructor call) it a default is used that simply
|
---|
| 496 | calls abort; which gives the required handling on implicate join.
|
---|