missplaced Lock fixed
[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  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include "runner.hxx"
14 #include "threadmanagement.hxx"
15 #include "configvariable.hxx"
16
17 extern "C"
18 {
19 #include "BrowseVarManager.h"
20 #include "FileBrowserChDir.h"
21 #include "scicurdir.h"
22 }
23
24 using namespace ast;
25
26 void *Runner::launch(void *args)
27 {
28     bool bdoUnlock = false;
29     //try to lock locker ( waiting parent thread register me )
30     ThreadManagement::LockRunner();
31     //just release locker
32     ThreadManagement::UnlockRunner();
33
34     __threadKey currentThreadKey = __GetCurrentThreadKey();
35     ThreadId* pThread = ConfigVariable::getThread(currentThreadKey);
36
37     //exec !
38     Runner *me = (Runner *)args;
39
40     try
41     {
42         me->getProgram()->accept(*(me->getVisitor()));
43         //ConfigVariable::clearLastError();
44     }
45     catch (const ast::ScilabException& se)
46     {
47         scilabErrorW(se.GetErrorMessage().c_str());
48         scilabErrorW(L"\n");
49         std::wostringstream ostr;
50         ConfigVariable::whereErrorToString(ostr);
51         scilabErrorW(ostr.str().c_str());
52         ConfigVariable::resetWhereError();
53     }
54
55     if (getScilabMode() != SCILAB_NWNI && getScilabMode() != SCILAB_API)
56     {
57         char *cwd = NULL;
58         int err = 0;
59
60         UpdateBrowseVar();
61         cwd = scigetcwd(&err);
62         if (cwd)
63         {
64             FileBrowserChDir(cwd);
65             FREE(cwd);
66         }
67     }
68
69     // reset error state when new prompt occurs
70     ConfigVariable::resetError();
71
72     //change thread status
73     if (pThread->getStatus() != ThreadId::Aborted)
74     {
75         pThread->setStatus(ThreadId::Done);
76         bdoUnlock = true;
77     }
78
79     if (pThread->getInterrupt()) // non-prioritary
80     {
81         // Unlock prioritary thread waiting for
82         // non-prioritary thread end this "SeqExp" execution.
83         // This case appear when error is throw or when
84         // non-prioritary execute this last SeqExp.
85         pThread->setInterrupt(false);
86         ThreadManagement::SendAstPendingSignal();
87     }
88
89     if (pThread->isConsoleCommand())
90     {
91         ThreadManagement::SendConsoleExecDoneSignal();
92     }
93
94     //unregister thread
95     ConfigVariable::deleteThread(currentThreadKey);
96
97     delete me;
98
99     if (bdoUnlock)
100     {
101         ThreadManagement::SendAwakeRunnerSignal();
102     }
103
104     return NULL;
105 }
106
107 void Runner::execAndWait(ast::Exp* _theProgram, ast::ExecVisitor *_visitor,
108                          bool _isPrioritaryThread, bool _isInterruptibleThread, bool _isConsoleCommand)
109 {
110     try
111     {
112         Runner *runMe = new Runner(_theProgram, _visitor);
113         __threadKey threadKey;
114         __threadId threadId;
115
116         types::ThreadId* pInterruptibleThread = ConfigVariable::getLastRunningThread();
117         if (_isPrioritaryThread)
118         {
119             if (pInterruptibleThread)
120             {
121                 if (pInterruptibleThread->isInterruptible())
122                 {
123                     pInterruptibleThread->setInterrupt(true);
124                     ThreadManagement::WaitForAstPendingSignal();
125                 }
126                 else
127                 {
128                     __WaitThreadDie(pInterruptibleThread->getThreadId());
129                     pInterruptibleThread = NULL;
130                 }
131             }
132         }
133         else if (pInterruptibleThread)
134         {
135             __WaitThreadDie(pInterruptibleThread->getThreadId());
136             pInterruptibleThread = NULL;
137         }
138
139         // Lock the thread "Runner::launch" to be sure that all
140         // stuff performed before the "WaitForAwakeRunnerSignal"
141         // are done.
142         ThreadManagement::LockRunner();
143
144         //launch thread but is can't really start since locker is locked
145         __CreateThreadWithParams(&threadId, &threadKey, &Runner::launch, runMe);
146         runMe->setThreadId(threadId);
147         runMe->setThreadKey(threadKey);
148
149         //register thread
150         types::ThreadId* pThread = new ThreadId(threadId, threadKey);
151         ConfigVariable::addThread(pThread);
152         pThread->setConsoleCommandFlag(_isConsoleCommand);
153         pThread->setInterruptible(_isInterruptibleThread);
154
155         //free locker to release thread && wait and of thread execution
156         ThreadManagement::WaitForAwakeRunnerSignal();
157
158         if (pInterruptibleThread && pInterruptibleThread->getInterrupt())
159         {
160             pInterruptibleThread->setInterrupt(false);
161             pInterruptibleThread->resume();
162         }
163
164         types::ThreadId* pExecThread = ConfigVariable::getThread(threadKey);
165         if (pExecThread == NULL)
166         {
167             //call pthread_join to clean stack allocation
168             __WaitThreadDie(threadId);
169         }
170     }
171     catch (const ast::ScilabException& se)
172     {
173         throw se;
174     }
175 }
176
177 void Runner::exec(ast::Exp* _theProgram, ast::ExecVisitor *_visitor)
178 {
179     m_theProgram = _theProgram;
180     m_visitor = _visitor;
181     __CreateThreadWithParams(&m_threadId, &m_threadKey, &Runner::launch, this);
182 }