fix non handled exception if error occurs in scilab.start
[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 static void sendExecDoneSignal(Runner* _pRunner)
31 {
32     switch (_pRunner->getCommandOrigin())
33     {
34         case CONSOLE :
35         {
36             ThreadManagement::SendConsoleExecDoneSignal();
37             break;
38         }
39         case TCLSCI :
40         case NONE :
41         default :
42         {}
43     }
44 }
45
46 void StaticRunner::launch()
47 {
48     // get the runner to execute
49     std::unique_ptr<Runner> runMe(getRunner());
50     // set if the current comment is interruptible
51     setInterruptibleCommand(runMe->isInterruptible());
52     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
53
54     ConfigVariable::resetExecutionBreak();
55
56     int oldMode = ConfigVariable::getPromptMode();
57     symbol::Context* pCtx = symbol::Context::getInstance();
58     int scope = pCtx->getScopeLevel();
59
60     // a TCL command display nothing
61     int iOldPromptMode = 0;
62     if (runMe->getCommandOrigin() == TCLSCI)
63     {
64         iOldPromptMode = ConfigVariable::getPromptMode();
65         ConfigVariable::setPromptMode(-1);
66     }
67
68     try
69     {
70         int level = ConfigVariable::getRecursionLevel();
71         try
72         {
73             runMe->getProgram()->accept(*(runMe->getVisitor()));
74         }
75         catch (const ast::RecursionException& re)
76         {
77             // management of pause
78             if (ConfigVariable::getPauseLevel())
79             {
80                 ConfigVariable::DecreasePauseLevel();
81                 throw re;
82             }
83
84             //close opened scope during try
85             while (pCtx->getScopeLevel() > scope)
86             {
87                 pCtx->scope_end();
88             }
89
90             //decrease recursion to init value and close where
91             while (ConfigVariable::getRecursionLevel() > level)
92             {
93                 ConfigVariable::where_end();
94                 ConfigVariable::decreaseRecursion();
95             }
96
97             ConfigVariable::resetWhereError();
98             ConfigVariable::setPromptMode(oldMode);
99
100             //print msg about recursion limit and trigger an error
101             wchar_t sz[1024];
102             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
103             throw ast::InternalError(sz);
104         }
105     }
106     catch (const ast::InternalError& se)
107     {
108         if (runMe->getCommandOrigin() == TCLSCI)
109         {
110             ConfigVariable::setPromptMode(iOldPromptMode);
111         }
112
113         scilabErrorW(se.GetErrorMessage().c_str());
114         scilabErrorW(L"\n");
115         std::wostringstream ostr;
116         ConfigVariable::whereErrorToString(ostr);
117         scilabErrorW(ostr.str().c_str());
118         ConfigVariable::resetWhereError();
119     }
120     catch (const ast::InternalAbort& ia)
121     {
122         if (runMe->getCommandOrigin() == TCLSCI)
123         {
124             ConfigVariable::setPromptMode(iOldPromptMode);
125         }
126
127         // management of pause
128         if (ConfigVariable::getPauseLevel())
129         {
130             ConfigVariable::DecreasePauseLevel();
131             throw ia;
132         }
133
134         // close all scope before return to console scope
135         symbol::Context* pCtx = symbol::Context::getInstance();
136         while (pCtx->getScopeLevel() > scope)
137         {
138             pCtx->scope_end();
139         }
140
141         // send the good signal about the end of execution
142         sendExecDoneSignal(runMe.get());
143
144         //clean debugger step flag if debugger is not interrupted ( end of debug )
145         manager->resetStep();
146         throw ia;
147     }
148
149     if (runMe->getCommandOrigin() == TCLSCI)
150     {
151         ConfigVariable::setPromptMode(iOldPromptMode);
152     }
153
154     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
155     {
156         char *cwd = NULL;
157         int err = 0;
158
159         UpdateBrowseVar();
160         cwd = scigetcwd(&err);
161         if (cwd)
162         {
163             FileBrowserChDir(cwd);
164             FREE(cwd);
165         }
166     }
167
168     // reset error state when new prompt occurs
169     ConfigVariable::resetError();
170
171     // send the good signal about the end of execution
172     sendExecDoneSignal(runMe.get());
173
174     //clean debugger step flag if debugger is not interrupted ( end of debug )
175     manager->resetStep();
176 }
177
178 void StaticRunner::setRunner(Runner* _RunMe)
179 {
180     m_RunMe = _RunMe;
181 }
182
183 Runner* StaticRunner::getRunner(void)
184 {
185     Runner* tmp = m_RunMe.exchange(nullptr);
186     ThreadManagement::SendAvailableRunnerSignal();
187     return tmp;
188 }
189
190 // return true if a Runner is already set in m_RunMe.
191 bool StaticRunner::isRunnerAvailable(void)
192 {
193     return m_RunMe.load() != nullptr;
194 }
195
196 void StaticRunner::setInterruptibleCommand(bool _bInterruptibleCommand)
197 {
198     m_bInterruptibleCommand = _bInterruptibleCommand;
199 }
200
201 bool StaticRunner::isInterruptibleCommand()
202 {
203     return m_bInterruptibleCommand;
204 }
205
206 command_origin_t StaticRunner::getCommandOrigin()
207 {
208     return m_RunMe.load()->getCommandOrigin();
209 }
210
211 void StaticRunner::execAndWait(ast::Exp* _theProgram, ast::RunVisitor *_visitor,
212                                bool /*_isPrioritaryThread*/, bool _isInterruptible, command_origin_t _iCommandOrigin)
213 {
214     if (isRunnerAvailable())
215     {
216         // wait for managenement of last Runner
217         ThreadManagement::WaitForAvailableRunnerSignal();
218     }
219
220     // lock runner to be sure we are waiting for
221     // "AwakeRunner" signal before start execution
222     ThreadManagement::LockRunner();
223     Runner *runMe = new Runner(_theProgram, _visitor, _iCommandOrigin, _isInterruptible);
224     setRunner(runMe);
225
226     ThreadManagement::SendRunMeSignal();
227     ThreadManagement::WaitForAwakeRunnerSignal();
228 }
229
230 bool StaticRunner::exec(ast::Exp* _theProgram, ast::RunVisitor *_visitor)
231 {
232     Runner *runMe = new Runner(_theProgram, _visitor);
233     setRunner(runMe);
234
235     try
236     {
237         launch();
238     }
239     catch (const ast::InternalAbort& /*ia*/)
240     {
241         //catch exit command in .start or .quit
242         return false;
243     }
244
245     return true;
246 }
247
248 void StaticRunner_launch(void)
249 {
250     StaticRunner::launch();
251 }
252
253 int StaticRunner_isRunnerAvailable(void)
254 {
255     return StaticRunner::isRunnerAvailable() ? 1 : 0;
256 }
257
258 int StaticRunner_isInterruptibleCommand(void)
259 {
260     return StaticRunner::isInterruptibleCommand() ? 1 : 0;
261 }
262
263 void StaticRunner_setInterruptibleCommand(int val)
264 {
265     StaticRunner::setInterruptibleCommand(val == 1);
266 }
267
268 command_origin_t StaticRunner_getCommandOrigin(void)
269 {
270     return StaticRunner::getCommandOrigin();
271 }