Scilab debugger updates
[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 std::atomic<bool> StaticRunner::m_bInterruptibleCommand(true);
35
36 static bool initialJavaHooks = false;
37
38 void StaticRunner::sendExecDoneSignal()
39 {
40     switch (getCurrentRunner()->getCommandOrigin())
41     {
42         case CONSOLE :
43         {
44             ThreadManagement::SendConsoleExecDoneSignal();
45             break;
46         }
47         case DEBUGGER :
48         {
49             ThreadManagement::SendDebuggerExecDoneSignal();
50             break;
51         }
52         case TCLSCI :
53         case NONE :
54         default :
55         {}
56     }
57 }
58
59 int StaticRunner::launch()
60 {
61     //set execution thread in java
62     if (!initialJavaHooks && getScilabMode() != SCILAB_NWNI)
63     {
64         initialJavaHooks = true;
65         // Execute the initial hooks registered in Scilab.java
66         ExecuteInitialHooks();
67     }
68
69     int iRet = 0;
70     // get the runner to execute
71     std::unique_ptr<Runner> runMe(getRunner());
72     // set if the current command is interruptible
73     setInterruptibleCommand(runMe->isInterruptible());
74     debugger::DebuggerManager* manager = debugger::DebuggerManager::getInstance();
75
76     ConfigVariable::resetExecutionBreak();
77
78     int oldMode = ConfigVariable::getPromptMode();
79     symbol::Context* pCtx = symbol::Context::getInstance();
80     int scope = pCtx->getScopeLevel();
81
82     // a TCL command display nothing
83     int iOldPromptMode = 0;
84     if (runMe->getCommandOrigin() == TCLSCI)
85     {
86         iOldPromptMode = ConfigVariable::getPromptMode();
87         ConfigVariable::setPromptMode(-1);
88     }
89
90     try
91     {
92         int level = ConfigVariable::getRecursionLevel();
93         try
94         {
95             runMe->getProgram()->accept(*(runMe->getVisitor()));
96         }
97         catch (const ast::RecursionException& re)
98         {
99             // management of pause
100             if (ConfigVariable::getPauseLevel())
101             {
102                 ConfigVariable::DecreasePauseLevel();
103                 throw re;
104             }
105
106             //close opened scope during try
107             while (pCtx->getScopeLevel() > scope)
108             {
109                 pCtx->scope_end();
110             }
111
112             //decrease recursion to init value and close where
113             while (ConfigVariable::getRecursionLevel() > level)
114             {
115                 ConfigVariable::where_end();
116                 ConfigVariable::decreaseRecursion();
117             }
118
119             ConfigVariable::resetWhereError();
120             ConfigVariable::setPromptMode(oldMode);
121
122             //print msg about recursion limit and trigger an error
123             wchar_t sz[1024];
124             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
125             throw ast::InternalError(sz);
126         }
127     }
128     catch (const ast::InternalError& se)
129     {
130         if (runMe->getCommandOrigin() == TCLSCI)
131         {
132             ConfigVariable::setPromptMode(iOldPromptMode);
133         }
134
135         std::wostringstream ostr;
136         ConfigVariable::whereErrorToString(ostr);
137         scilabErrorW(ostr.str().c_str());
138         scilabErrorW(se.GetErrorMessage().c_str());
139         ConfigVariable::resetWhereError();
140         iRet = 1;
141     }
142     catch (const ast::InternalAbort& ia)
143     {
144         if (runMe->getCommandOrigin() == TCLSCI)
145         {
146             ConfigVariable::setPromptMode(iOldPromptMode);
147         }
148
149         // management of pause
150         if (ConfigVariable::getPauseLevel())
151         {
152             ConfigVariable::DecreasePauseLevel();
153             throw ia;
154         }
155
156         // close all scope before return to console scope
157         symbol::Context* pCtx = symbol::Context::getInstance();
158         while (pCtx->getScopeLevel() > scope)
159         {
160             pCtx->scope_end();
161         }
162
163         // send the good signal about the end of execution
164         sendExecDoneSignal();
165
166         // debugger leave with abort state
167         manager->setAborted();
168         throw ia;
169     }
170
171     if (runMe->getCommandOrigin() == TCLSCI)
172     {
173         ConfigVariable::setPromptMode(iOldPromptMode);
174     }
175
176     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
177     {
178         char *cwd = NULL;
179         int err = 0;
180
181         UpdateBrowseVar();
182         saveScilabHistoryToFile();
183         cwd = scigetcwd(&err);
184         if (cwd)
185         {
186             FileBrowserChDir(cwd);
187             FREE(cwd);
188         }
189     }
190
191     // reset error state when new prompt occurs
192     ConfigVariable::resetError();
193
194     // send the good signal about the end of execution
195     sendExecDoneSignal();
196
197     //clean debugger step flag if debugger is not interrupted ( end of debug )
198     manager->resetStep();
199     return iRet;
200 }
201
202 void StaticRunner::setRunner(Runner* _RunMe)
203 {
204     m_RunMe = _RunMe;
205 }
206
207 void StaticRunner::setCurrentRunner(Runner* _RunMe)
208 {
209     m_CurrentRunner = _RunMe;
210 }
211
212 Runner* StaticRunner::getRunner(void)
213 {
214     Runner* tmp = m_RunMe.exchange(nullptr);
215     setCurrentRunner(tmp);
216     ThreadManagement::SendAvailableRunnerSignal();
217     return tmp;
218 }
219
220 Runner* StaticRunner::getCurrentRunner(void)
221 {
222     return m_CurrentRunner;
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 void StaticRunner::setInterruptibleCommand(bool _bInterruptibleCommand)
232 {
233     m_bInterruptibleCommand = _bInterruptibleCommand;
234 }
235
236 bool StaticRunner::isInterruptibleCommand()
237 {
238     return m_bInterruptibleCommand;
239 }
240
241 command_origin_t StaticRunner::getCommandOrigin()
242 {
243     return m_RunMe.load()->getCommandOrigin();
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 void StaticRunner_setInterruptibleCommand(int val)
299 {
300     StaticRunner::setInterruptibleCommand(val == 1);
301 }
302
303 command_origin_t StaticRunner_getCommandOrigin(void)
304 {
305     return StaticRunner::getCommandOrigin();
306 }