reset debugger aborted flag
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 #include "runner.hxx"
18 #include "threadmanagement.hxx"
19 #include "configvariable.hxx"
20 #include "debugmanager.hxx"
21
22 extern "C"
23 {
24 #include "HistoryManager.h"
25 #include "BrowseVarManager.h"
26 #include "FileBrowserChDir.h"
27 #include "scicurdir.h"
28 #include "Scierror.h"
29 #include "InitializeJVM.h"
30 }
31
32 std::atomic<Runner*> StaticRunner::m_RunMe(nullptr);
33 std::atomic<Runner*> StaticRunner::m_CurrentRunner(nullptr);
34
35 static bool initialJavaHooks = false;
36
37 void StaticRunner::sendExecDoneSignal()
38 {
39     switch (m_CurrentRunner.load()->getCommandOrigin())
40     {
41         case DEBUGGER :
42         {
43             ThreadManagement::SendDebuggerExecDoneSignal();
44             break;
45         }
46         case CONSOLE :
47         {
48             ThreadManagement::SendConsoleExecDoneSignal();
49             break;
50         }
51         case TCLSCI :
52         case NONE :
53         default : {}
54     }
55 }
56
57 int StaticRunner::launch()
58 {
59     //set execution thread in java
60     if (!initialJavaHooks && getScilabMode() != SCILAB_NWNI)
61     {
62         initialJavaHooks = true;
63         // Execute the initial hooks registered in Scilab.java
64         ExecuteInitialHooks();
65     }
66
67     int iRet = 0;
68
69     // save current runner
70     Runner* pRunSave = m_CurrentRunner.load();
71
72     // get the runner to execute
73     std::unique_ptr<Runner> runMe(getRunner());
74
75     debugger::DebuggerManager* manager = debugger::DebuggerManager::getInstance();
76     manager->resetAborted();
77
78     ConfigVariable::resetExecutionBreak();
79
80     int oldMode = ConfigVariable::getPromptMode();
81     symbol::Context* pCtx = symbol::Context::getInstance();
82     int scope = pCtx->getScopeLevel();
83
84     // a TCL command display nothing
85     int iOldPromptMode = 0;
86     if (runMe->getCommandOrigin() == TCLSCI)
87     {
88         iOldPromptMode = ConfigVariable::getPromptMode();
89         ConfigVariable::setPromptMode(-1);
90     }
91
92     try
93     {
94         int level = ConfigVariable::getRecursionLevel();
95         try
96         {
97             runMe->getProgram()->accept(*(runMe->getVisitor()));
98         }
99         catch (const ast::RecursionException& re)
100         {
101             // management of pause
102             if (ConfigVariable::getPauseLevel())
103             {
104                 ConfigVariable::DecreasePauseLevel();
105                 throw re;
106             }
107
108             //close opened scope during try
109             while (pCtx->getScopeLevel() > scope)
110             {
111                 pCtx->scope_end();
112             }
113
114             //decrease recursion to init value and close where
115             while (ConfigVariable::getRecursionLevel() > level)
116             {
117                 ConfigVariable::where_end();
118                 ConfigVariable::decreaseRecursion();
119             }
120
121             ConfigVariable::resetWhereError();
122             ConfigVariable::setPromptMode(oldMode);
123
124             //print msg about recursion limit and trigger an error
125             wchar_t sz[1024];
126             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
127             throw ast::InternalError(sz);
128         }
129     }
130     catch (const ast::InternalError& se)
131     {
132         if (runMe->getCommandOrigin() == TCLSCI)
133         {
134             ConfigVariable::setPromptMode(iOldPromptMode);
135         }
136
137         std::wostringstream ostr;
138         ConfigVariable::whereErrorToString(ostr);
139         scilabErrorW(ostr.str().c_str());
140         scilabErrorW(se.GetErrorMessage().c_str());
141         ConfigVariable::resetWhereError();
142         iRet = 1;
143     }
144     catch (const ast::InternalAbort& ia)
145     {
146         if (runMe->getCommandOrigin() == TCLSCI)
147         {
148             ConfigVariable::setPromptMode(iOldPromptMode);
149         }
150
151         // management of pause
152         if (ConfigVariable::getPauseLevel())
153         {
154             ConfigVariable::DecreasePauseLevel();
155             // set back the runner wich have been overwritten in StaticRunner::getRunner
156             m_CurrentRunner.store(pRunSave);
157             throw ia;
158         }
159
160         // close all scope before return to console scope
161         symbol::Context* pCtx = symbol::Context::getInstance();
162         while (pCtx->getScopeLevel() > scope)
163         {
164             pCtx->scope_end();
165         }
166
167         // debugger leave with abort state
168         manager->setAborted();
169
170         // send the good signal about the end of execution
171         sendExecDoneSignal();
172
173         // set back the runner wich have been overwritten in StaticRunner::getRunner
174         m_CurrentRunner.store(pRunSave);
175         throw ia;
176     }
177
178     if (runMe->getCommandOrigin() == TCLSCI)
179     {
180         ConfigVariable::setPromptMode(iOldPromptMode);
181     }
182
183     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
184     {
185         char *cwd = NULL;
186         int err = 0;
187
188         UpdateBrowseVar();
189         saveScilabHistoryToFile();
190         cwd = scigetcwd(&err);
191         if (cwd)
192         {
193             FileBrowserChDir(cwd);
194             FREE(cwd);
195         }
196     }
197
198     // reset error state when new prompt occurs
199     ConfigVariable::resetError();
200
201     // send the good signal about the end of execution
202     sendExecDoneSignal();
203
204     //clean debugger step flag if debugger is not interrupted ( end of debug )
205     manager->resetStep();
206
207     // set back the runner wich have been overwritten in StaticRunner::getRunner
208     m_CurrentRunner.store(pRunSave);
209
210     return iRet;
211 }
212
213 void StaticRunner::setRunner(Runner* _RunMe)
214 {
215     m_RunMe = _RunMe;
216 }
217
218 Runner* StaticRunner::getRunner(void)
219 {
220     m_CurrentRunner.store(m_RunMe.exchange(nullptr));
221     ThreadManagement::SendAvailableRunnerSignal();
222     return m_CurrentRunner.load();
223 }
224
225 // return true if a Runner is already set in m_RunMe.
226 bool StaticRunner::isRunnerAvailable(void)
227 {
228     return m_RunMe.load() != nullptr;
229 }
230
231 bool StaticRunner::isInterruptibleCommand()
232 {
233     return m_CurrentRunner.load()->isInterruptible();
234 }
235
236 command_origin_t StaticRunner::getCommandOrigin()
237 {
238     return m_RunMe.load()->getCommandOrigin();
239 }
240
241 void StaticRunner::setCommandOrigin(command_origin_t _origin)
242 {
243     m_CurrentRunner.load()->setCommandOrigin(_origin);
244 }
245
246 void StaticRunner::execAndWait(ast::Exp* _theProgram, ast::RunVisitor *_visitor,
247                                bool /*_isPrioritaryThread*/, bool _isInterruptible, command_origin_t _iCommandOrigin)
248 {
249     if (isRunnerAvailable())
250     {
251         // wait for managenement of last Runner
252         ThreadManagement::WaitForAvailableRunnerSignal();
253     }
254
255     // lock runner to be sure we are waiting for
256     // "AwakeRunner" signal before start execution
257     ThreadManagement::LockRunner();
258     Runner *runMe = new Runner(_theProgram, _visitor, _iCommandOrigin, _isInterruptible);
259     setRunner(runMe);
260
261     ThreadManagement::SendRunMeSignal();
262     ThreadManagement::WaitForAwakeRunnerSignal();
263 }
264
265 bool StaticRunner::exec(ast::Exp* _theProgram, ast::RunVisitor *_visitor)
266 {
267     Runner *runMe = new Runner(_theProgram, _visitor);
268     setRunner(runMe);
269
270     try
271     {
272         launch();
273     }
274     catch (const ast::InternalAbort& /*ia*/)
275     {
276         //catch exit command in .start or .quit
277         return false;
278     }
279
280     return true;
281 }
282
283 void StaticRunner_launch(void)
284 {
285     StaticRunner::launch();
286 }
287
288 int StaticRunner_isRunnerAvailable(void)
289 {
290     return StaticRunner::isRunnerAvailable() ? 1 : 0;
291 }
292
293 int StaticRunner_isInterruptibleCommand(void)
294 {
295     return StaticRunner::isInterruptibleCommand() ? 1 : 0;
296 }
297
298 command_origin_t StaticRunner_getCommandOrigin(void)
299 {
300     return StaticRunner::getCommandOrigin();
301 }
302
303 void StaticRunner_setCommandOrigin(command_origin_t _origin)
304 {
305     StaticRunner::setCommandOrigin(_origin);
306 }