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