Changes in / [a76da32:1717b12]
- Files:
-
- 6 edited
-
doc/theses/andrew_beach_MMath/implement.tex (modified) (21 diffs)
-
libcfa/src/concurrency/coroutine.cfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/ready_queue.cfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/implement.tex
ra76da32 r1717b12 13 13 library. 14 14 15 \subsection{Virtual Type}16 Virtual types only have one change to their structure, the addition of a17 pointer to the virtual table. This is always the first field so that18 if it is cast to a supertype the field's location is still known.19 20 This field is set as part of all new generated constructors.21 \todo{They only come as part exceptions and don't work.}22 After the object is created the field is constant.23 24 However it can be read from, internally it is just a regular field called25 @virtual_table@. Dereferencing it gives the virtual table and access to the26 type's virtual members.27 28 15 \subsection{Virtual Table} 29 Every time a virtual type is defined the new virtual table type must also be30 defined.31 32 The unique instance is important because the address of the virtual table33 instance is used as the identifier for the virtual type. So a pointer to the34 virtual table and the ID for the virtual type are interchangable.35 \todo{Unique instances might be going so we will have to talk about the new36 system instead.}37 38 The first step in putting it all together is to create the virtual table type.39 The virtual table type is just a structure and can be described in terms of40 its fields. The first field is always the parent type ID (or a pointer to41 the parent virtual table) or 0 (the null pointer).42 Next are other fields on the parent virtual table are repeated.43 Finally are the fields used to store any new virtual members of the new44 The virtual type45 46 16 The virtual system is accessed through a private constant field inserted at the 47 17 beginning of every virtual type, called the virtual-table pointer. This field 48 18 points at a type's virtual table and is assigned during the object's 49 construction. The address of a virtual table acts as the unique identifier for19 construction. The address of a virtual table acts as the unique identifier for 50 20 the virtual type, and the first field of a virtual table is a pointer to the 51 parent virtual-table or @0p@. The remaining fields are duplicated from the21 parent virtual-table or @0p@. The remaining fields are duplicated from the 52 22 parent tables in this type's inheritance chain, followed by any fields this type 53 introduces. Parent fields are duplicated so they can be changed ( all virtual54 members are overridable), so that references to the dispatched type23 introduces. Parent fields are duplicated so they can be changed (\CC 24 \lstinline[language=c++]|override|), so that references to the dispatched type 55 25 are replaced with the current virtual type. 26 \PAB{Can you create a simple diagram of the layout?} 56 27 % These are always taken by pointer or reference. 57 58 % Simple ascii diragram:59 \begin{verbatim}60 parent_pointer \61 parent_field0 |62 ... | Same layout as parent.63 parent_fieldN /64 child_field065 ...66 child_fieldN67 \end{verbatim}68 \todo{Refine the diagram}69 28 70 29 % For each virtual type, a virtual table is constructed. This is both a new type … … 75 34 A virtual table is created when the virtual type is created. The name of the 76 35 type is created by mangling the name of the base type. The name of the instance 77 is also generated by name mangling. The fields are initialized automatically.36 is also generated by name mangling. The fields are initialized automatically. 78 37 The parent field is initialized by getting the type of the parent field and 79 38 using that to calculate the mangled name of the parent's virtual table type. … … 108 67 \begin{sloppypar} 109 68 Coroutines and threads need instances of @CoroutineCancelled@ and 110 @ThreadCancelled@ respectively to use all of their functionality. When a new69 @ThreadCancelled@ respectively to use all of their functionality. When a new 111 70 data type is declared with @coroutine@ or @thread@ the forward declaration for 112 71 the instance is created as well. The definition of the virtual table is created … … 121 80 The function is 122 81 \begin{cfa} 123 void * __cfa__virtual_cast( 124 struct __cfa__parent_vtable const * parent, 82 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 125 83 struct __cfa__parent_vtable const * const * child ); 84 } 126 85 \end{cfa} 127 and it is implemented in the standard library. The structure reperents the 128 head of a vtable which is the pointer to the parent virtual table. The 129 @parent@ points directly at the parent type virtual table while the @child@ 130 points at the object of the (possibe) child type. 131 132 In terms of the virtual cast expression, @parent@ comes from looking up the 133 type being cast to and @child@ is the result of the expression being cast. 134 Because the complier outputs C code, some type C type casts are also used. 135 The last bit of glue is an map that saves every virtual type the compiler 136 sees. This is used to check the type used in a virtual cast is a virtual 137 type and to get its virtual table. 138 (It also checks for conflicting definitions.) 139 140 Inside the function it is a simple conditional. If the type repersented by 141 @parent@ is or is an ancestor of the type repersented by @*child@ (it 142 requires one more level of derefence to pass through the object) then @child@ 143 is returned, otherwise the null pointer is returned. 144 145 The check itself is preformed is a simple linear search. If the child 146 virtual table or any of its ancestors (which are retreved through the first 147 field of every virtual table) are the same as the parent virtual table then 148 the cast succeeds. 86 and it is implemented in the standard library. It takes a pointer to the target 87 type's virtual table and the object pointer being cast. The function performs a 88 linear search starting at the object's virtual-table and walking through the 89 the parent pointers, checking to if it or any of its ancestors are the same as 90 the target-type virtual table-pointer. 91 92 For the generated code, a forward declaration of the virtual works as follows. 93 There is a forward declaration of @__cfa__virtual_cast@ in every \CFA file so 94 it can just be used. The object argument is the expression being cast so that 95 is just placed in the argument list. 96 97 To build the target type parameter, the compiler creates a mapping from 98 concrete type-name -- so for polymorphic types the parameters are filled in -- 99 to virtual table address. Every virtual table declaration is added to the this 100 table; repeats are ignored unless they have conflicting definitions. Note, 101 these declarations do not have to be in scope, but they should usually be 102 introduced as part of the type definition. 103 104 \PAB{I do not understood all of \VRef{s:VirtualSystem}. I think you need to 105 write more to make it clear.} 106 149 107 150 108 \section{Exceptions} … … 163 121 stack. On function entry and return, unwinding is handled directly by the code 164 122 embedded in the function. Usually, the stack-frame size is known statically 165 based on parameter and local variable declarations. For dynamically-sized123 based on parameter and local variable declarations. For dynamically-sized 166 124 local variables, a runtime computation is necessary to know the frame 167 125 size. Finally, a function's frame-size may change during execution as local … … 221 179 222 180 To use libunwind, each function must have a personality function and a Language 223 Specific Data Area (LSDA). The LSDA has the unique information for each181 Specific Data Area (LSDA). The LSDA has the unique information for each 224 182 function to tell the personality function where a function is executing, its 225 current stack frame, and what handlers should be checked. Theoretically, the183 current stack frame, and what handlers should be checked. Theoretically, the 226 184 LSDA can contain any information but conventionally it is a table with entries 227 185 representing regions of the function and what has to be done there during … … 238 196 239 197 The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and 240 attaches its personality function. However, this 241 flag only handles the cleanup attribute: 242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive 243 and that's all I know.} 198 attaches its personality function. \PAB{to what is it attached?} However, this 199 flag only handles the cleanup attribute 244 200 \begin{cfa} 245 201 void clean_up( int * var ) { ... } 246 int avar __attribute__(( cleanup(clean_up) ));202 int avar __attribute__(( __cleanup(clean_up) )); 247 203 \end{cfa} 248 which is used on a variable and specifies a function, in this case @clean_up@, 249 run when the variable goes out of scope. 250 The function is passed a pointer to the object being removed from the stack 251 so it can be used to mimic destructors. 252 However, this feature cannot be used to mimic @try@ statements as it cannot 253 control the unwinding. 204 which is used on a variable and specifies a function, \eg @clean_up@, run when 205 the variable goes out of scope. The function is passed a pointer to the object 206 so it can be used to mimic destructors. However, this feature cannot be used to 207 mimic @try@ statements. 254 208 255 209 \subsection{Personality Functions} 256 Personality functions have a complex interface specified by libunwind. This210 Personality functions have a complex interface specified by libunwind. This 257 211 section covers some of the important parts of the interface. 258 212 259 A personality function can preform different actions depending on how it is260 called.213 A personality function performs four tasks, although not all have to be 214 present. 261 215 \begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}] 262 216 typedef _Unwind_Reason_Code (*@_Unwind_Personality_Fn@) ( … … 271 225 \item 272 226 @_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function 273 to check for handlers. If there is a handler in a stack frame, as defined by227 to check for handlers. If there is a handler in a stack frame, as defined by 274 228 the language, the personality function returns @_URC_HANDLER_FOUND@; otherwise 275 229 it return @_URC_CONTINUE_UNWIND@. … … 342 296 \end{cfa} 343 297 It also unwinds the stack but it does not use the search phase. Instead another 344 function, the stop function, is used to stop searching. The exception is the298 function, the stop function, is used to stop searching. The exception is the 345 299 same as the one passed to raise exception. The extra arguments are the stop 346 300 function and the stop parameter. The stop function has a similar interface as a … … 364 318 365 319 \begin{sloppypar} 366 Its arguments are the same as the paired personality function. The actions320 Its arguments are the same as the paired personality function. The actions 367 321 @_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always set when it is 368 322 called. Beyond the libunwind standard, both GCC and Clang add an extra action … … 389 343 strong symbol replacing the sequential version. 390 344 391 The sequential @this_exception_context@ returns a hard-coded pointer to the 392 global execption context. 393 The concurrent version adds the exception context to the data stored at the 394 base of each stack. When @this_exception_context@ is called it retrieves the 395 active stack and returns the address of the context saved there. 345 % The version of the function defined in @libcfa@ is very simple. It returns a 346 % pointer to a global static variable. With only one stack this global instance 347 % is associated with the only stack. 348 349 For coroutines, @this_exception_context@ accesses the exception context stored 350 at the base of the stack. For threads, @this_exception_context@ uses the 351 concurrency library to access the current stack of the thread or coroutine 352 being executed by the thread, and then accesses the exception context stored at 353 the base of this stack. 396 354 397 355 \section{Termination} … … 411 369 per-exception storage. 412 370 413 [Quick ASCII diagram to get started.] 414 \begin{verbatim} 415 Fixed Header | _Unwind_Exception <- pointer target 416 | 417 | Cforall storage 418 | 419 Variable Body | the exception <- fixed offset 420 V ... 421 \end{verbatim} 422 423 Exceptions are stored in variable-sized blocks. 424 The first component is a fixed sized data structure that contains the 371 Exceptions are stored in variable-sized blocks. \PAB{Show a memory layout 372 figure.} The first component is a fixed sized data structure that contains the 425 373 information for libunwind and the exception system. The second component is an 426 374 area of memory big enough to store the exception. Macros with pointer arthritic … … 440 388 exception type. The size and copy function are used immediately to copy an 441 389 exception into managed memory. After the exception is handled the free function 442 is used to clean up the exception and then the entire node is passed to free 443 so the memory can be given back to the heap. 390 is used to clean up the exception and then the entire node is passed to free. 444 391 445 392 \subsection{Try Statements and Catch Clauses} … … 452 399 library. The contents of a try block and the termination handlers are converted 453 400 into functions. These are then passed to the try terminate function and it 454 calls them. 455 Because this function is known and fixed (and not an arbitrary function that 456 happens to contain a try statement) this means the LSDA can be generated ahead 457 of time. 458 459 Both the LSDA and the personality function are set ahead of time using 460 embedded assembly. This is handcrafted using C @asm@ statements and contains 461 enough information for the single try statement the function repersents. 401 calls them. This approach puts a try statement in its own functions so that no 402 function has to deal with both termination handlers and destructors. \PAB{I do 403 not understand the previous sentence.} 404 405 This function has some custom embedded assembly that defines \emph{its} 406 personality function and LSDA. The assembly is created with handcrafted C @asm@ 407 statements, which is why there is only one version of it. The personality 408 function is structured so that it can be expanded, but currently it only 409 handles this one function. Notably, it does not handle any destructors so the 410 function is constructed so that it does need to run it. \PAB{I do not 411 understand the previous sentence.} 462 412 463 413 The three functions passed to try terminate are: … … 469 419 470 420 \item[match function:] This function is called during the search phase and 471 decides if a catch clause matches the termination exception. It is constructed421 decides if a catch clause matches the termination exception. It is constructed 472 422 from the conditional part of each handler and runs each check, top to bottom, 473 423 in turn, first checking to see if the exception type matches and then if the … … 478 428 \item[handler function:] This function handles the exception. It takes a 479 429 pointer to the exception and the handler's id and returns nothing. It is called 480 after the cleanup phase. It is constructed by stitching together the bodies of430 after the cleanup phase. It is constructed by stitching together the bodies of 481 431 each handler and dispatches to the selected handler. 482 432 \end{description} … … 484 434 can be used to create closures, functions that can refer to the state of other 485 435 functions on the stack. This approach allows the functions to refer to all the 486 variables in scope for the function containing the @try@ statement. These436 variables in scope for the function containing the @try@ statement. These 487 437 nested functions and all other functions besides @__cfaehm_try_terminate@ in 488 438 \CFA use the GCC personality function and the @-fexceptions@ flag to generate … … 505 455 handler that matches. If no handler matches then the function returns 506 456 false. Otherwise the matching handler is run; if it completes successfully, the 507 function returns true. Re throwing, through the @throwResume;@ statement,508 causesthe function to return true.457 function returns true. Reresume, through the @throwResume;@ statement, cause 458 the function to return true. 509 459 510 460 % Recursive Resumption Stuff: … … 532 482 providing zero-cost enter/exit using the LSDA. Unfortunately, there is no way 533 483 to return from a libunwind search without installing a handler or raising an 534 error. Although workarounds might be possible, they are beyond the scope of484 error. Although workarounds might be possible, they are beyond the scope of 535 485 this thesis. The current resumption implementation has simplicity in its 536 486 favour. … … 553 503 554 504 Cancellation also uses libunwind to do its stack traversal and unwinding, 555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details505 however it uses a different primary function @_Unwind_ForcedUnwind@. Details 556 506 of its interface can be found in the \VRef{s:ForcedUnwind}. 557 507 … … 561 511 its main coroutine and the coroutine it is currently executing. 562 512 563 So if the active thread's main and current coroutine are the same. If they 564 are then the current stack is a thread stack, otherwise it is a coroutine 565 stack. If it is a thread stack then an equality check with the stored main 566 thread pointer and current thread pointer is enough to tell if the current 567 thread is the main thread or not. 513 The first check is if the current thread's main and current coroutine do not 514 match, implying a coroutine cancellation; otherwise, it is a thread 515 cancellation. Otherwise it is a main thread cancellation. \PAB{Previous 516 sentence does not make sense.} 568 517 569 518 However, if the threading library is not linked, the sequential execution is on -
libcfa/src/concurrency/coroutine.cfa
ra76da32 r1717b12 196 196 197 197 void __stack_clean ( __stack_info_t * this ) { 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t); 198 199 void * storage = this->storage->limit; 199 200 200 201 #if CFA_COROUTINE_USE_MMAP 201 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);202 202 storage = (void *)(((intptr_t)storage) - __page_size); 203 203 if(munmap(storage, size + __page_size) == -1) { -
libcfa/src/concurrency/kernel.cfa
ra76da32 r1717b12 109 109 static void __run_thread(processor * this, $thread * dst); 110 110 static void __wake_one(cluster * cltr); 111 static void wait(__bin_sem_t & this);112 111 113 112 static void push (__cluster_idles & idles, processor & proc); … … 549 548 // Kernel Idle Sleep 550 549 //============================================================================================= 551 extern "C" {552 char * strerror(int);553 }554 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }555 556 static void wait(__bin_sem_t & this) with( this ) {557 verify(__cfaabi_dbg_in_kernel());558 CHECKED( pthread_mutex_lock(&lock) );559 while(val < 1) {560 pthread_cond_wait(&cond, &lock);561 }562 val -= 1;563 CHECKED( pthread_mutex_unlock(&lock) );564 }565 566 static bool post(__bin_sem_t & this) with( this ) {567 bool needs_signal = false;568 569 CHECKED( pthread_mutex_lock(&lock) );570 if(val < 1) {571 val += 1;572 pthread_cond_signal(&cond);573 needs_signal = true;574 }575 CHECKED( pthread_mutex_unlock(&lock) );576 577 return needs_signal;578 }579 580 #undef CHECKED581 582 550 // Wake a thread from the front if there are any 583 551 static void __wake_one(cluster * this) { -
libcfa/src/concurrency/kernel.hfa
ra76da32 r1717b12 34 34 #endif 35 35 36 extern "C" { 37 char * strerror(int); 38 } 39 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); } 40 36 41 struct __bin_sem_t { 37 42 pthread_mutex_t lock; … … 39 44 int val; 40 45 }; 46 47 static inline void ?{}(__bin_sem_t & this) with( this ) { 48 // Create the mutex with error checking 49 pthread_mutexattr_t mattr; 50 pthread_mutexattr_init( &mattr ); 51 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP); 52 pthread_mutex_init(&lock, &mattr); 53 54 pthread_cond_init (&cond, (const pthread_condattr_t *)0p); // workaround trac#208: cast should not be required 55 val = 0; 56 } 57 58 static inline void ^?{}(__bin_sem_t & this) with( this ) { 59 CHECKED( pthread_mutex_destroy(&lock) ); 60 CHECKED( pthread_cond_destroy (&cond) ); 61 } 62 63 static inline void wait(__bin_sem_t & this) with( this ) { 64 verify(__cfaabi_dbg_in_kernel()); 65 CHECKED( pthread_mutex_lock(&lock) ); 66 while(val < 1) { 67 pthread_cond_wait(&cond, &lock); 68 } 69 val -= 1; 70 CHECKED( pthread_mutex_unlock(&lock) ); 71 } 72 73 static inline bool post(__bin_sem_t & this) with( this ) { 74 bool needs_signal = false; 75 76 CHECKED( pthread_mutex_lock(&lock) ); 77 if(val < 1) { 78 val += 1; 79 pthread_cond_signal(&cond); 80 needs_signal = true; 81 } 82 CHECKED( pthread_mutex_unlock(&lock) ); 83 84 return needs_signal; 85 } 86 87 #undef CHECKED 88 41 89 42 90 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/kernel/startup.cfa
ra76da32 r1717b12 80 80 static void ?{}(processorCtx_t & this) {} 81 81 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info); 82 static void ?{}(__bin_sem_t & this);83 static void ^?{}(__bin_sem_t & this);84 82 85 83 #if defined(__CFA_WITH_VERIFY__) … … 738 736 } 739 737 740 extern "C" {741 char * strerror(int);742 }743 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }744 745 static void ?{}(__bin_sem_t & this) with( this ) {746 // Create the mutex with error checking747 pthread_mutexattr_t mattr;748 pthread_mutexattr_init( &mattr );749 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);750 pthread_mutex_init(&lock, &mattr);751 752 pthread_cond_init (&cond, (const pthread_condattr_t *)0p); // workaround trac#208: cast should not be required753 val = 0;754 }755 756 static void ^?{}(__bin_sem_t & this) with( this ) {757 CHECKED( pthread_mutex_destroy(&lock) );758 CHECKED( pthread_cond_destroy (&cond) );759 }760 761 #undef CHECKED762 738 763 739 #if defined(__CFA_WITH_VERIFY__) -
libcfa/src/concurrency/ready_queue.cfa
ra76da32 r1717b12 330 330 #if defined(BIAS) 331 331 // Don't bother trying locally too much 332 int local_tries = 8; 332 333 preferred = kernelTLS().this_processor->id * 4; 333 334 #endif
Note:
See TracChangeset
for help on using the changeset viewer.