c0b623b563b3400b2a68cfa5bb2a0e05c25316ce
[scilab.git] / scilab / modules / core / src / cpp / runner.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011-2011 - DIGITEO - Bruno JOFRET
4  *  Copyright (C) 2014-2015 - Scilab Enterprises - Cedric Delamarre
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 #include "runner.hxx"
15 #include "threadmanagement.hxx"
16 #include "configvariable.hxx"
17 #include "debugmanager.hxx"
18
19 extern "C"
20 {
21 #include "BrowseVarManager.h"
22 #include "FileBrowserChDir.h"
23 #include "scicurdir.h"
24 #include "Scierror.h"
25 }
26
27 std::atomic<Runner*> StaticRunner::m_RunMe(nullptr);
28 std::atomic<bool> StaticRunner::m_bInterruptibleCommand(true);
29
30 void StaticRunner::launch()
31 {
32     // get the runner to execute
33     std::unique_ptr<Runner> runMe(getRunner());
34     // set if the current comment is interruptible
35     setInterruptibleCommand(runMe->isInterruptible());
36     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
37
38     ConfigVariable::resetExecutionBreak();
39     int oldMode = ConfigVariable::getPromptMode();
40     symbol::Context* pCtx = symbol::Context::getInstance();
41     int scope = pCtx->getScopeLevel();
42
43     try
44     {
45         int level = ConfigVariable::getRecursionLevel();
46         try
47         {
48             runMe->getProgram()->accept(*(runMe->getVisitor()));
49         }
50         catch (const ast::RecursionException& re)
51         {
52             // management of pause
53             if (ConfigVariable::getPauseLevel())
54             {
55                 ConfigVariable::DecreasePauseLevel();
56                 throw re;
57             }
58
59             //close opened scope during try
60             while (pCtx->getScopeLevel() > scope)
61             {
62                 pCtx->scope_end();
63             }
64
65             //decrease recursion to init value and close where
66             while (ConfigVariable::getRecursionLevel() > level)
67             {
68                 ConfigVariable::where_end();
69                 ConfigVariable::decreaseRecursion();
70             }
71
72             ConfigVariable::resetWhereError();
73             ConfigVariable::setPromptMode(oldMode);
74
75             //print msg about recursion limit and trigger an error
76             wchar_t sz[1024];
77             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
78             throw ast::InternalError(sz);
79         }
80     }
81     catch (const ast::InternalError& se)
82     {
83         scilabErrorW(se.GetErrorMessage().c_str());
84         scilabErrorW(L"\n");
85         std::wostringstream ostr;
86         ConfigVariable::whereErrorToString(ostr);
87         scilabErrorW(ostr.str().c_str());
88         ConfigVariable::resetWhereError();
89     }
90     catch (const ast::InternalAbort& ia)
91     {
92         // management of pause
93         if (ConfigVariable::getPauseLevel())
94         {
95             ConfigVariable::DecreasePauseLevel();
96             throw ia;
97         }
98
99         // close all scope before return to console scope
100         symbol::Context* pCtx = symbol::Context::getInstance();
101         while (pCtx->getScopeLevel() > scope)
102         {
103             pCtx->scope_end();
104         }
105
106         if (runMe->isConsoleCommand())
107         {
108             ThreadManagement::SendConsoleExecDoneSignal();
109         }
110
111         //clean debugger step flag if debugger is not interrupted ( end of debug )
112         manager->resetStep();
113         throw ia;
114     }
115
116     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
117     {
118         char *cwd = NULL;
119         int err = 0;
120
121         UpdateBrowseVar();
122         cwd = scigetcwd(&err);
123         if (cwd)
124         {
125             FileBrowserChDir(cwd);
126             FREE(cwd);
127         }
128     }
129
130     // reset error state when new prompt occurs
131     ConfigVariable::resetError();
132
133     if (runMe->isConsoleCommand())
134     {
135         ThreadManagement::SendConsoleExecDoneSignal();
136     }
137
138     //clean debugger step flag if debugger is not interrupted ( end of debug )
139     manager->resetStep();
140 }
141
142 void StaticRunner::setRunner(Runner* _RunMe)
143 {
144     m_RunMe = _RunMe;
145 }
146
147 Runner* StaticRunner::getRunner(void)
148 {
149     Runner* tmp = m_RunMe.exchange(nullptr);
150     ThreadManagement::SendAvailableRunnerSignal();
151     return tmp;
152 }
153
154 // return true if a Runner is already set in m_RunMe.
155 bool StaticRunner::isRunnerAvailable(void)
156 {
157     return m_RunMe.load() != nullptr;
158 }
159
160 void StaticRunner::setInterruptibleCommand(bool _bInterruptibleCommand)
161 {
162     m_bInterruptibleCommand = _bInterruptibleCommand;
163 }
164
165 bool StaticRunner::isInterruptibleCommand()
166 {
167     return m_bInterruptibleCommand;
168 }
169
170 void StaticRunner::execAndWait(ast::Exp* _theProgram, ast::RunVisitor *_visitor,
171                                bool _isPrioritaryThread, bool _isInterruptible, bool _isConsoleCommand)
172 {
173     if (isRunnerAvailable())
174     {
175         // wait for managenement of last Runner
176         ThreadManagement::WaitForAvailableRunnerSignal();
177     }
178
179     // lock runner to be sure we are waiting for
180     // "AwakeRunner" signal before start execution
181     ThreadManagement::LockRunner();
182     Runner *runMe = new Runner(_theProgram, _visitor, _isConsoleCommand, _isInterruptible);
183     setRunner(runMe);
184
185     ThreadManagement::SendRunMeSignal();
186     ThreadManagement::WaitForAwakeRunnerSignal();
187 }
188
189 void StaticRunner::exec(ast::Exp* _theProgram, ast::RunVisitor *_visitor)
190 {
191     Runner *runMe = new Runner(_theProgram, _visitor);
192     setRunner(runMe);
193     launch();
194 }
195
196 void StaticRunner_launch(void)
197 {
198     StaticRunner::launch();
199 }
200
201 int StaticRunner_isRunnerAvailable(void)
202 {
203     return StaticRunner::isRunnerAvailable() ? 1 : 0;
204 }
205
206 int StaticRunner_isInterruptibleCommand(void)
207 {
208     return StaticRunner::isInterruptibleCommand() ? 1 : 0;
209 }
210
211 void StaticRunner_setInterruptibleCommand(int val)
212 {
213     StaticRunner::setInterruptibleCommand(val == 1);
214 }