Logo Search packages:      
Sourcecode: u++ version File versions

uBaseCoroutine.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Peter A. Buhr 1997
// 
// uBaseCoroutine.cc -- 
// 
// Author           : Peter A. Buhr
// Created On       : Sat Sep 27 16:46:37 1997
// Last Modified By : Peter A. Buhr
// Last Modified On : Tue Aug 31 22:35:46 2004
// Update Count     : 302
//
// This  library is free  software; you  can redistribute  it and/or  modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
// option) any later version.
// 
// This library is distributed in the  hope that it will be useful, but WITHOUT
// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
// 
// You should  have received a  copy of the  GNU Lesser General  Public License
// along  with this library.
// 

#define __U_KERNEL__
#define __U_PROFILE__
#define __U_PROFILEABLE_ONLY__


#include <uC++.h>
#include <uProfiler.h>
//#include <uDebug.h>

#include <cstring>                              // strncpy


//######################### uBaseCoroutine #########################


void uBaseCoroutine::uCreateCoroutine() {
#ifdef __U_DEBUG__
    uLast = NULL;                         // for error checking
    uCurrSerialOwner = NULL;
    uCurrSerialCount = 0;
#endif // __U_DEBUG__
    uNotHalted = true;                          // must be a non-zero value so detectable after memory is scrubbed
    uState = uInActive;

    // exception handling

    uHandlerStackTop = uHandlerStackVisualTop = NULL;
    RaisedObj = NULL;
    uDAEStack = NULL;
    uUnexpectedRtn = uEHM::uUnexpected;               // initialize default unexpected routine

    // profiling

    uProfileSamplerInstance = NULL;
} // uBaseCoroutine::uCreateCoroutine


uBaseCoroutine::uBaseCoroutine() : uMachContext( uThisCluster().uGetStackSize() ) {
    uCreateCoroutine();
} // uBaseCoroutine::uBaseCoroutine


uBaseCoroutine::uBaseCoroutine( unsigned int stacksize ) : uMachContext( stacksize ) {
    uCreateCoroutine();
} // uBaseCoroutine::uBaseCoroutine


void uBaseCoroutine::uContextSw() {             // switch between a task and the kernel
    uBaseCoroutine &uCurrCor = uThisCoroutine();      // optimization
    uBaseTask &uCurrTask = uThisTask();

    if ( uCurrTask.uProfileActive && uProfiler::uProfiler_BuiltInRegisterTaskBlock ) { // uninterruptable hooks
      (*uProfiler::uProfiler_BuiltInRegisterTaskBlock)( uProfiler::uProfilerInstance, uCurrTask );
    } // if

    uCurrCor.uSetState( uInActive );                  // set state of current coroutine to inactive
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uBaseCoroutine &)0x%p.uContextSw, uCurrCor:0x%p, uCurrCor.uSP:0x%p, uCurrCor.uStorage:0x%p, uStorage:0x%p\n",
             this, &uCurrCor, uCurrCor.uStackPointer(), uCurrCor.uStorage, uStorage );
#endif // __U_DEBUG_H__
    uCurrCor.uSave();                           // save user specified contexts

    uSwitch( uCurrCor.uStorage, uStorage );           // context switch to kernel
    uCurrCor.uRestore();                        // restore user specified contexts
    uCurrCor.uSetState( uActive );              // set state of new coroutine to active

    uCurrTask.uSetState( uBaseTask::uRunning );

    if ( uCurrTask.uProfileActive && uProfiler::uProfiler_BuiltInRegisterTaskUnblock ) { // uninterruptable hooks
      (*uProfiler::uProfiler_BuiltInRegisterTaskUnblock)( uProfiler::uProfilerInstance, uCurrTask );
    } // if
} // uBaseCoroutine::uContextSw


void uBaseCoroutine::uContextSw2() {                  // switch between two coroutine contexts
    uBaseCoroutine &uCurrCor = uThisCoroutine();      // optimization
    uBaseTask &uCurrTask = uThisTask();

#ifdef __U_DEBUG__
    // reset task in current coroutine?
    if ( uCurrCor.uCurrSerialCount == uCurrTask.uCurrSerialLevel ) {
      uCurrCor.uCurrSerialOwner = NULL;
    } // if
    
    // check and set for new owner
    if ( uCurrSerialOwner != &uCurrTask ) {
      if ( uCurrSerialOwner != NULL  ) {
          if ( &uCurrSerialOwner->uGetCoroutine() != this ) {
            uAbort( ": attempt by task %.256s (0x%p) to activate coroutine %.256s (0x%p) currently executing in a mutex object owned by task %.256s (0x%p).\n"
                  "Possible cause is task attempting to logically change ownership of a mutex object via a coroutine.",
                  uCurrTask.uGetName(), &uCurrTask, this->uGetName(), this, uCurrSerialOwner->uGetName(), uCurrSerialOwner );
          } else {
            uAbort( ": attempt by task %.256s (0x%p) to resume coroutine %.256s (0x%p) currently being executed by task %.256s (0x%p).\n"
                  "Possible cause is two tasks attempting simultaneous execution of the same coroutine.",
                  uCurrTask.uGetName(), &uCurrTask, this->uGetName(), this, uCurrSerialOwner->uGetName(), uCurrSerialOwner );
          } // if
      }  else {
          uCurrSerialOwner = &uCurrTask;
          uCurrSerialCount = uCurrTask.uCurrSerialLevel;
      } // if
    } // if
#endif // __U_DEBUG__

    if ( uCurrTask.uProfileActive && uProfiler::uProfiler_RegisterCoroutineBlock ) {
      (*uProfiler::uProfiler_RegisterCoroutineBlock)( uProfiler::uProfilerInstance, uCurrTask, *this );
    } // if

    THREAD_GETMEM( uSelf )->uDisableInterrupts();

    uCurrCor.uSetState( uInActive );                  // set state of current coroutine to inactive
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uBaseCoroutine &)0x%p.uContextSw2, uCurrCor:0x%p, uCurrCor.uSP:0x%p\n",
             this, &uCurrCor, uCurrCor.uStackPointer() );
#endif // __U_DEBUG_H__
    uCurrCor.uSave();                           // save user specified contexts
    uCurrTask.uCurrCoroutine = this;                  // set new coroutine that task is executing

#if defined( __U_MULTI__ ) && defined( __U_SWAPCONTEXT__ )
#if defined( __linux__ ) && defined( __i386__ )
    ((ucontext_t *)(uStorage))->uc_mcontext.gregs[REG_GS] = THREAD_GETMEM( ldtValue );
#elif defined( __linux__ ) && defined( __ia64__ )
    ((ucontext_t *)(uStorage))->uc_mcontext.sc_gr[13] = (unsigned long)THREAD_GETMEM( threadPointer );
#elif defined( __solaris__ ) && defined( __sparc__ )
    ((ucontext_t *)(uStorage))->uc_mcontext.gregs[REG_G7] = (int)(THREAD_GETMEM( uSelf ) );
#elif defined( __irix__ ) && defined( __mips__ )
    // No thread register => nothing needs to be set in the mcontext
#else
    #error uC++ internal error : unsupported architecture
#endif
#endif // __U_MULTI__ && __U_SWAPCONTEXT__

    uSwitch( uCurrCor.uStorage, uStorage );           // context switch to specified coroutine
    uCurrCor.uRestore();                        // restore user specified contexts
    uCurrCor.uSetState( uActive );              // set state of new coroutine to active

    THREAD_GETMEM( uSelf )->uEnableInterrupts();

    // also appears in uCoroutineMain::uCoroutineMain
    if ( uCurrTask.uProfileActive && uProfiler::uProfiler_RegisterCoroutineUnblock ) {
      (*uProfiler::uProfiler_RegisterCoroutineUnblock)( uProfiler::uProfilerInstance, uCurrTask );
    } // if
} // uBaseCoroutine::uContextSw2


void uBaseCoroutine::uCoStarter() {             // remembers who started a coroutine
    uStart = uLast;
} // uBaseCoroutine::uCoStarter


void uBaseCoroutine::uCoFinish() {              // resumes the coroutine that first resumed this coroutine
    uNotHalted = false;
    uStart->uContextSw2();
    uAbort( "(uBaseCoroutine &)0x%p.uCoFinish() : internal error, CONTROL NEVER REACHES HERE!", this );
} // uBaseCoroutine::uCoFinish


const char *uBaseCoroutine::uGetName() const {
    // storage might be scrubbed
    return ( uName == NULL || uName == (const char *)-1 ) ? "*unknown*" : uName;
} // uBaseCoroutine::uGetName


const char *uBaseCoroutine::uSetName( const char *name ) {
    const char *prev = uName;
    uName = name;

    if ( uThisTask().uProfileActive && uProfiler::uProfiler_RegisterSetName ) { 
      (*uProfiler::uProfiler_RegisterSetName)( uProfiler::uProfilerInstance, *this, name); 
    } // if
    return prev;
} // uBaseCoroutine::uSetName


void uBaseCoroutine::uCoResume() {              // restarts the coroutine's main where last suspended
    uBaseCoroutine &c = uThisCoroutine();       // optimization

    if ( &c != this ) {                         // resume to oneself ?
#ifdef __U_DEBUG__
        if ( ! uNotHalted ) {                   // check if terminated
          uAbort( ": attempt by coroutine %.256s (0x%p) to resume terminated coroutine %.256s (0x%p).\n"
                "Possible cause is terminated coroutine's main routine has already returned.",
                c.uGetName(), &c, uGetName(), this );
      } // if
#endif // __U_DEBUG__
      uLast = &c;
      uContextSw2();
    } // if
    uEnable <uBaseCoroutine::uFailure> {
      uEHM::uPoll();
    } // uEnable
} // uBaseCoroutine::uCoResume


void uBaseCoroutine::uCoSuspend() {             // restarts the coroutine that most recently resumed this coroutine
#ifdef __U_DEBUG__
    if ( uLast == NULL ) {
      uAbort( ": attempt to suspend coroutine %.256s (0x%p), which has never been resumed.\n"
            "Possible cause is a uSuspend statement executed in a member called by a coroutine user rather than by the coroutine main.",
            uGetName(), this );
    } // if
    if ( ! uLast->uNotHalted ) {                // check if terminated
          uAbort( ": attempt by coroutine %.256s (0x%p) to suspend back to terminated coroutine %.256s (0x%p).\n"
                "Possible cause is terminated coroutine's main routine has already returned.",
                uThisCoroutine().uGetName(), &uThisCoroutine(), uLast->uGetName(), uLast );
    } // if
#endif // __U_DEBUG__
    uLast->uContextSw2();
    uEnable <uBaseCoroutine::uFailure> {
      uEHM::uPoll();
    } // uEnable
} // uBaseCoroutine::uCoSuspend


uBaseCoroutine &uBaseCoroutine::uLastResume() const {
    return *uLast;
} // uBaseCoroutine::uLastResume


void uBaseCoroutine::uFailure::uCreateFailure() {
    // coroutine name is copied because its storage can be freed and scrubbed before handler starts
    strncpy( uName, cor.uGetName(), uEHMMaxName );
    if ( strlen( cor.uGetName() ) > uEHMMaxName ) {   // name too long ?
      strcpy( &uName[uEHMMaxName], "..." );           // add 4 character ...
    } // if
} // uBaseCoroutine::uFailure::uFailure

uBaseCoroutine::uFailure::uFailure( const uBaseCoroutine &cor, const char *const msg ) : uKernelFailure( msg ), cor( cor ) {
    uCreateFailure();
} // uBaseCoroutine::uFailure::uFailure

uBaseCoroutine::uFailure::uFailure( const char *const msg ) : uKernelFailure( msg ), cor( uThisCoroutine() ) {
    uCreateFailure();
} // uBaseCoroutine::uFailure::uFailure

uBaseCoroutine::uFailure::~uFailure() {
} // uBaseCoroutine::uFailure::~uFailure

const uBaseCoroutine &uBaseCoroutine::uFailure::uDst() const { return cor; }

const char *uBaseCoroutine::uFailure::uGetName() const { return uName; }

void uBaseCoroutine::uFailure::defaultTerminate() const {
    uAbort( "Unhandled exception of type uBaseCoroutine::uFailure : %s coroutine %.256s (0x%p) from coroutine %.256s (0x%p).",
          message(), uThisCoroutine().uGetName(), &uThisCoroutine(), sourceName(), &source() );
} // uBaseCoroutine::uFailure::defaultTerminate


uInitEvent(uBaseCoroutine::uFailure);


// Local Variables: //
// compile-command: "gmake install" //
// End: //

Generated by  Doxygen 1.6.0   Back to index