f17511cf1a103ffa650d4ce699fa606793148ad4
[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
15 __threadLock Runner::m_lock;
16
17 __threadSignal Runner::m_awakeScilab;
18 __threadSignalLock Runner::m_awakeScilabLock;
19
20 __threadSignal Runner::m_AstPending;
21 __threadSignalLock Runner::m_AstPendingLock;
22
23
24 using namespace ast;
25
26 __threadSignal* getAstPendingSignal(void)
27 {
28     return Runner::getAstPendingSignal();
29 }
30
31
32 void Runner::init()
33 {
34     __InitSignal(&m_awakeScilab);
35     __InitSignalLock(&m_awakeScilabLock);
36
37     __InitSignal(&m_AstPending);
38     __InitSignalLock(&m_AstPendingLock);
39 }
40
41 void *Runner::launch(void *args)
42 {
43     bool bdoUnlock = false;
44     //try to lock locker ( waiting parent thread register me )
45     __Lock(&m_lock);
46     //just release locker
47     __UnLock(&m_lock);
48
49     //exec !
50     Runner *me = (Runner *)args;
51
52     try
53     {
54         me->getProgram()->accept(*(me->getVisitor()));
55         //ConfigVariable::clearLastError();
56     }
57     catch (const ast::ScilabException& se)
58     {
59         scilabErrorW(se.GetErrorMessage().c_str());
60     }
61
62     // reset error state when new prompt occurs
63     ConfigVariable::resetError();
64
65     __threadKey currentThreadKey = __GetCurrentThreadKey();
66
67     //change thread status
68     ThreadId* pThread = ConfigVariable::getThread(currentThreadKey);
69     if (pThread->getStatus() != ThreadId::Aborted)
70     {
71         pThread->setStatus(ThreadId::Done);
72         bdoUnlock = true;
73     }
74
75     if (pThread->isInterruptible()) // non-prioritary
76     {
77         // Unlock prioritary thread waiting for
78         // non-prioritary thread end this "SeqExp" execution.
79         // This case appear when error is throw or when
80         // non-prioritary execute this last SeqExp.
81         __Signal(&Runner::m_AstPending);
82     }
83
84     //unregister thread
85     ConfigVariable::deleteThread(currentThreadKey);
86
87     delete me;
88
89     if (bdoUnlock)
90     {
91         UnlockPrompt();
92     }
93
94     return NULL;
95 }
96
97 void Runner::LockPrompt()
98 {
99     __LockSignal(&m_awakeScilabLock);
100     //free locker to release thread
101     __UnLock(&m_lock);
102     __Wait(&m_awakeScilab, &m_awakeScilabLock);
103     __UnLockSignal(&m_awakeScilabLock);
104 }
105
106 void Runner::UnlockPrompt()
107 {
108     __LockSignal(&m_awakeScilabLock);
109     __Signal(&m_awakeScilab);
110     __UnLockSignal(&m_awakeScilabLock);
111 }
112
113
114 void Runner::execAndWait(ast::Exp* _theProgram, ast::ExecVisitor *_visitor, bool _isPrioritaryThread)
115 {
116     try
117     {
118         Runner *runMe = new Runner(_theProgram, _visitor);
119         __threadKey threadKey;
120         __threadId threadId;
121
122         //init locker
123         __InitLock(&m_lock);
124         //lock locker
125         __Lock(&m_lock);
126
127         types::ThreadId* pInterruptibleThread = ConfigVariable::getLastRunningThread();
128         if (_isPrioritaryThread)
129         {
130             if (pInterruptibleThread)
131             {
132                 if (pInterruptibleThread->isInterruptible())
133                 {
134                     pInterruptibleThread->setInterrupt(true);
135
136                     __LockSignal(&m_AstPendingLock);
137                     __Wait(&m_AstPending, &m_AstPendingLock);
138                     __UnLockSignal(&m_AstPendingLock);
139                 }
140                 else
141                 {
142                     __WaitThreadDie(pInterruptibleThread->getThreadId());
143                     pInterruptibleThread = NULL;
144                 }
145             }
146         }
147         else if (pInterruptibleThread)
148         {
149             __WaitThreadDie(pInterruptibleThread->getThreadId());
150             pInterruptibleThread = NULL;
151         }
152
153         //launch thread but is can't really start since locker is locked
154         __CreateThreadWithParams(&threadId, &threadKey, &Runner::launch, runMe);
155         runMe->setThreadId(threadId);
156         runMe->setThreadKey(threadKey);
157
158         //register thread
159         types::ThreadId* pThread = new ThreadId(threadId, threadKey);
160         ConfigVariable::addThread(pThread);
161         if (_isPrioritaryThread)
162         {
163             pThread->setInterruptible(false);
164         }
165
166         //free locker to release thread && wait and of thread execution
167         LockPrompt();
168
169         if (pInterruptibleThread)
170         {
171             pInterruptibleThread->setInterrupt(false);
172             pInterruptibleThread->resume();
173         }
174
175         types::ThreadId* pExecThread = ConfigVariable::getThread(threadKey);
176         if (pExecThread == NULL)
177         {
178             //call pthread_join to clean stack allocation
179             __WaitThreadDie(threadId);
180         }
181     }
182     catch (const ast::ScilabException& se)
183     {
184         throw se;
185     }
186 }
187
188 void Runner::exec(ast::Exp* _theProgram, ast::ExecVisitor *_visitor)
189 {
190     m_theProgram = _theProgram;
191     m_visitor = _visitor;
192     __CreateThreadWithParams(&m_threadId, &m_threadKey, &Runner::launch, this);
193 }