ParseRunnables.cpp

// ParseRunnables.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2009

@import "Ceda/cxCedaScript/cxCedaScript.h"
@import "Ceda/cxPersistStore/pref.h"
@import "Ceda/cxPersistStore/IPrefVisitor.h"
@import "Ceda/cxPersistStore/xmap.h"
@import "Ceda/cxObject/Object.h"
@import "Ceda/cxObject/IObjectVisitor.h"
@import "Ceda/cxObject/WCSpace.h"
@import "Ceda/cxObject/PrintReflectedVariable.h"
#include "Ceda/cxUtils/Tracer.h"
#include "Ceda/cxUtils/xdeque.h"
#include "Ceda/cxUtils/MsWindows.h"
#include "Ceda/cxUtils/HPTime.h"
#include <assert.h>

namespace ceda
{
    $interface+ IRunnable : IObject
    {
        void Start();
        void Stop();
    };
    
    void ParseRunnables(ExpressionParser& parser)
    {
        xdeque< ptr<IRunnable> > L;
        parser.ParseGivenToken(TOKEN_LEFT_CURLY, "{");
        while(1)
        {
            if (parser.GetTokenType() == TOKEN_LEFT_CURLY)
            {
                ParseRunnables(parser);
            }
            else if (parser.GetTokenType() == TOKEN_RIGHT_CURLY)
            {
                parser.ReadNextToken();
                break;
            }
            else
            {
                ptr<IRunnable> r;
                {
                    CSpaceLock lock;
                    ptr<IObject> p = ParseDataSource(parser);
                    r = qicast<IRunnable>(p);
                    cxAssert(r);
                    AddGcRoot(r);
                }
                L.push_back(r);
                r->Start();
            }
        }
        
        while(!L.empty())
        {
            ptr<IRunnable> r = L.back();
            L.pop_back();
            r->Stop();
            {
                CSpaceLock lock;
                RemoveGcRoot(r);
            }
        }
    }

} // namespace ceda


namespace ParseRunnableEx
{
    const int MAGIC = 0x0138fe5d;

    $struct+ X isa ceda::IRunnable :
        model
        {
            string8 name;
        }
    {
        X() : magic(MAGIC), prevcspace(NULL), cspace(NULL) {}
        ~X()
        {
            cxAssert(magic == MAGIC);
            magic = 0;
        }
    
        void Start()
        {
            cxAssert(magic == MAGIC);
            Tracer() << "Start " << name << '\n';
            ceda::IndentTrace(2);
            
            Sleep(50);
            
            prevcspace = ceda::GetThreadPtr<ceda::CSpace>();
            cspace = ceda::CreateCSpace(10);
            ceda::SetThreadPtr<ceda::CSpace>(cspace);
        }
        void Stop()
        {
            cxAssert(cspace == ceda::GetThreadPtr<ceda::CSpace>());
            ceda::Destroy(cspace);
            ceda::SetThreadPtr<ceda::CSpace>(prevcspace);

            Sleep(50);

            ceda::IndentTrace(-2);
            Tracer() << "Stop " << name << '\n';
            cxAssert(magic == MAGIC);
        }
        
        int magic; // Used to check for destruction while object is still being used. 
        ceda::CSpace* prevcspace;
        ceda::CSpace* cspace;
    };
    
    /*
    Output is:

      Start a
        Start b
          Start c
            Start d
            Stop d
          Stop c
          Start e
          Stop e
        Stop b
      Stop a
    */
    void Run()
    {
        Tracer() << "ParseRunnableEx\n";
        ceda::TraceIndenter indent;
        
        ceda::xstring s = @str
        (
            {
                ParseRunnableEx.X("a")
                ParseRunnableEx.X("b")
                {
                    ParseRunnableEx.X("c")
                    ParseRunnableEx.X("d")
                }
                ParseRunnableEx.X("e")
            }
        );        

        ceda::CSpaceCreator cspace(10); // 10 msec per GC

        ceda::ExpressionParser parser;
        try
        {
            parser.Init(s);

            // todo: this fails with assertion in DGS, which checks that CSpace has been locked when invoke 
            // write barrier on indep variables.
            //ceda::ParseRunnables(parser);
        }
        catch(ceda::LexScannerException& e)
        {
            Tracer() << "Error : " << e << '\n';
        }
    }
}