b62a3b598e6843ef76df2feb7b70fa5acda816e8
[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     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                 delete runMe;
57                 throw re;
58             }
59
60             //close opened scope during try
61             while (pCtx->getScopeLevel() > scope)
62             {
63                 pCtx->scope_end();
64             }
65
66             //decrease recursion to init value and close where
67             while (ConfigVariable::getRecursionLevel() > level)
68             {
69                 ConfigVariable::where_end();
70                 ConfigVariable::decreaseRecursion();
71             }
72
73             ConfigVariable::resetWhereError();
74             ConfigVariable::setPromptMode(oldMode);
75
76             //print msg about recursion limit and trigger an error
77             wchar_t sz[1024];
78             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
79             throw ast::InternalError(sz);
80         }
81     }
82     catch (const ast::InternalError& se)
83     {
84         scilabErrorW(se.GetErrorMessage().c_str());
85         scilabErrorW(L"\n");
86         std::wostringstream ostr;
87         ConfigVariable::whereErrorToString(ostr);
88         scilabErrorW(ostr.str().c_str());
89         ConfigVariable::resetWhereError();
90     }
91     catch (const ast::InternalAbort& ia)
92     {
93         // management of pause
94         if (ConfigVariable::getPauseLevel())
95         {
96             ConfigVariable::DecreasePauseLevel();
97             delete runMe;
98             throw ia;
99         }
100
101         // close all scope before return to console scope
102         symbol::Context* pCtx = symbol::Context::getInstance();
103         while (pCtx->getScopeLevel() > scope)
104         {
105             pCtx->scope_end();
106         }
107
108         if (runMe->isConsoleCommand())
109         {
110             ThreadManagement::SendConsoleExecDoneSignal();
111         }
112
113         //clean debugger step flag if debugger is not interrupted ( end of debug )
114         manager->resetStep();
115         delete runMe;
116         throw ia;
117     }
118
119     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
120     {
121         char *cwd = NULL;
122         int err = 0;
123
124         UpdateBrowseVar();
125         cwd = scigetcwd(&err);
126         if (cwd)
127         {
128             FileBrowserChDir(cwd);
129             FREE(cwd);
130         }
131     }
132
133     // reset error state when new prompt occurs
134     ConfigVariable::resetError();
135
136     if (runMe->isConsoleCommand())
137     {
138         ThreadManagement::SendConsoleExecDoneSignal();
139     }
140
141     //clean debugger step flag if debugger is not interrupted ( end of debug )
142     manager->resetStep();
143     delete runMe;
144 }
145
146 void StaticRunner::setRunner(Runner* _RunMe)
147 {
148     m_RunMe = _RunMe;
149 }
150
151 Runner* StaticRunner::getRunner(void)
152 {
153     Runner* tmp = m_RunMe.exchange(nullptr);
154     ThreadManagement::SendAvailableRunnerSignal();
155     return tmp;
156 }
157
158 // return true if a Runner is already set in m_RunMe.
159 bool StaticRunner::isRunnerAvailable(void)
160 {
161     return m_RunMe.load() != nullptr;
162 }
163
164 void StaticRunner::setInterruptibleCommand(bool _bInterruptibleCommand)
165 {
166     m_bInterruptibleCommand = _bInterruptibleCommand;
167 }
168
169 bool StaticRunner::isInterruptibleCommand()
170 {
171     return m_bInterruptibleCommand;
172 }
173
174 void StaticRunner::execAndWait(ast::Exp* _theProgram, ast::RunVisitor *_visitor,
175                                bool _isPrioritaryThread, bool _isInterruptible, bool _isConsoleCommand)
176 {
177     if (isRunnerAvailable())
178     {
179         // wait for managenement of last Runner
180         ThreadManagement::WaitForAvailableRunnerSignal();
181     }
182
183     // lock runner to be sure we are waiting for
184     // "AwakeRunner" signal before start execution
185     ThreadManagement::LockRunner();
186     Runner *runMe = new Runner(_theProgram, _visitor, _isConsoleCommand, _isInterruptible);
187     setRunner(runMe);
188
189     ThreadManagement::SendRunMeSignal();
190     ThreadManagement::WaitForAwakeRunnerSignal();
191 }
192
193 void StaticRunner::exec(ast::Exp* _theProgram, ast::RunVisitor *_visitor)
194 {
195     Runner *runMe = new Runner(_theProgram, _visitor);
196     setRunner(runMe);
197     launch();
198 }
199
200 void StaticRunner_launch(void)
201 {
202     StaticRunner::launch();
203 }
204
205 int StaticRunner_isRunnerAvailable(void)
206 {
207     return StaticRunner::isRunnerAvailable() ? 1 : 0;
208 }
209
210 int StaticRunner_isInterruptibleCommand(void)
211 {
212     return StaticRunner::isInterruptibleCommand() ? 1 : 0;
213 }
214
215 void StaticRunner_setInterruptibleCommand(int val)
216 {
217     StaticRunner::setInterruptibleCommand(val == 1);
218 }