Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/coroutine.cfa

    r58b6d1b r76e069f  
    2222#include <string.h>
    2323#include <unistd.h>
     24// use this define to make unwind.h play nice, definetely a hack
     25#define HIDE_EXPORTS
     26#include <unwind.h>
     27#undef HIDE_EXPORTS
    2428#include <sys/mman.h>
    2529}
     
    2933#define __CFA_INVOKE_PRIVATE__
    3034#include "invoke.h"
     35
     36extern "C" {
     37      void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
     38      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
     39      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
     40            abort();
     41      }
     42}
    3143
    3244//-----------------------------------------------------------------------------
     
    6779      starter = NULL;
    6880      last = NULL;
    69 }
    70 
    71 void ^?{}(coroutine_desc& this) {}
     81      cancellation = NULL;
     82}
     83
     84void ^?{}(coroutine_desc& this) {
     85      if(this.state != Halted) {
     86            coroutine_desc * src = TL_GET( this_coroutine );
     87            coroutine_desc * dst = &this;
     88
     89            struct _Unwind_Exception storage;
     90            storage.exception_class = -1;
     91            storage.exception_cleanup = _CtxCoroutine_UnwindCleanup;
     92            this.cancellation = &storage;
     93            this.last = src;
     94
     95              // not resuming self ?
     96              if ( src == dst ) {
     97                      abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src );
     98            }
     99
     100              CoroutineCtxSwitch( src, dst );
     101      }
     102}
    72103
    73104// Part of the Public API
     
    105136      // Safety note : This could cause some false positives due to preemption
    106137      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     138
     139      if( unlikely(src->cancellation != NULL) ) {
     140            _CtxCoroutine_Unwind(src->cancellation);
     141      }
    107142} //ctxSwitchDirect
    108143
     
    162197      }
    163198
    164       void __leave_coroutine(void) {
     199      void __leave_coroutine() {
    165200            coroutine_desc * src = TL_GET( this_coroutine ); // optimization
    166 
    167             assertf( src->starter != 0,
     201            coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
     202
     203            src->state = Halted;
     204
     205            assertf( starter != 0,
    168206                  "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"
    169207                  "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    170208                  src->name, src );
    171             assertf( src->starter->state != Halted,
     209            assertf( starter->state != Halted,
    172210                  "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"
    173211                  "Possible cause is terminated coroutine's main routine has already returned.",
    174                   src->name, src, src->starter->name, src->starter );
    175 
    176             CoroutineCtxSwitch( src, src->starter );
     212                  src->name, src, starter->name, starter );
     213
     214            CoroutineCtxSwitch( src, starter );
    177215      }
    178216}
Note: See TracChangeset for help on using the changeset viewer.