Scilab debugger updates
[scilab.git] / scilab / modules / ast / src / cpp / system_env / threadmanagement.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2015 - Scilab Enterprises - Cedric DELAMARRE
4 *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13 *
14 */
15
16 #include "threadmanagement.hxx"
17 #include "runner.hxx"
18
19 #ifdef DEBUG_THREAD
20 #include <iostream>
21 #include <iomanip>
22
23 #define PRINT_COL_SIZE 32
24
25 __threadKey ThreadManagement::m_tkMain;
26 __threadKey ThreadManagement::m_tkReadAndExec;
27 __threadKey ThreadManagement::m_tkConsole;
28 #endif // DEBUG_THREAD
29
30 __threadLock ThreadManagement::m_RunnerLock;
31 __threadLock ThreadManagement::m_ParseLock;
32 __threadLock ThreadManagement::m_StoreCommandLock;
33 __threadLock ThreadManagement::m_ScilabReadLock;
34
35 __threadSignal ThreadManagement::m_ConsoleExecDone;
36 __threadSignalLock ThreadManagement::m_ConsoleExecDoneLock;
37
38 __threadSignal ThreadManagement::m_DebuggerExecDone;
39 __threadSignalLock ThreadManagement::m_DebuggerExecDoneLock;
40
41 __threadSignal ThreadManagement::m_AwakeRunner;
42 __threadSignalLock ThreadManagement::m_AwakeRunnerLock;
43
44 __threadSignal ThreadManagement::m_AvailableRunner;
45 __threadSignalLock ThreadManagement::m_AvailableRunnerLock;
46
47 __threadSignal ThreadManagement::m_StartPending;
48 __threadSignalLock ThreadManagement::m_StartPendingLock;
49
50 __threadSignal ThreadManagement::m_CommandStored;
51 __threadSignalLock ThreadManagement::m_CommandStoredLock;
52
53 __threadSignal ThreadManagement::m_RunMe;
54 __threadSignalLock ThreadManagement::m_RunMeLock;
55
56 bool ThreadManagement::m_AvailableRunnerWasSignalled    = false;
57 bool ThreadManagement::m_ConsoleExecDoneWasSignalled    = false;
58 bool ThreadManagement::m_DebuggerExecDoneWasSignalled   = false;
59 bool ThreadManagement::m_AwakeRunnerWasSignalled        = false;
60 bool ThreadManagement::m_StartPendingWasSignalled       = false;
61 bool ThreadManagement::m_CommandStoredWasSignalled      = false;
62 bool ThreadManagement::m_RunMeWasSignalled              = false;
63
64 void ThreadManagement::initialize()
65 {
66     __InitLock(&m_RunnerLock);
67     __InitLock(&m_ParseLock);
68     __InitLock(&m_StoreCommandLock);
69     __InitLock(&m_ScilabReadLock);
70
71     __InitSignal(&m_AwakeRunner);
72     __InitSignalLock(&m_AwakeRunnerLock);
73
74     __InitSignal(&m_ConsoleExecDone);
75     __InitSignalLock(&m_ConsoleExecDoneLock);
76
77     __InitSignal(&m_DebuggerExecDone);
78     __InitSignalLock(&m_DebuggerExecDoneLock);
79
80     __InitSignal(&m_AvailableRunner);
81     __InitSignalLock(&m_AvailableRunnerLock);
82
83     __InitSignal(&m_StartPending);
84     __InitSignalLock(&m_StartPendingLock);
85
86     __InitSignal(&m_CommandStored);
87     __InitSignalLock(&m_CommandStoredLock);
88
89     __InitSignal(&m_RunMe);
90     __InitSignalLock(&m_RunMeLock);
91 }
92
93 /***
94     [Runner Lock]
95     Used when we want to access to the Parser.
96 ***/
97 void ThreadManagement::LockParser(void)
98 {
99 #ifdef DEBUG_THREAD
100     PrintDebug("LockParser");
101 #endif // DEBUG_THREAD
102     __Lock(&m_ParseLock);
103 }
104
105 void ThreadManagement::UnlockParser(void)
106 {
107 #ifdef DEBUG_THREAD
108     PrintDebug("UnlockParser");
109 #endif // DEBUG_THREAD
110     __UnLock(&m_ParseLock);
111 }
112
113 /***
114     [Runner Lock]
115     Used when we want to access to the Store Command.
116 ***/
117 void ThreadManagement::LockStoreCommand(void)
118 {
119 #ifdef DEBUG_THREAD
120     PrintDebug("LockStoreCommand");
121 #endif // DEBUG_THREAD
122     __Lock(&m_StoreCommandLock);
123 }
124
125 void ThreadManagement::UnlockStoreCommand(void)
126 {
127 #ifdef DEBUG_THREAD
128     PrintDebug("UnlockStoreCommand");
129 #endif // DEBUG_THREAD
130     __UnLock(&m_StoreCommandLock);
131 }
132
133 /***
134     [Runner Lock]
135     Used when we want to access to the global Runner.
136 ***/
137 void ThreadManagement::LockRunner(void)
138 {
139 #ifdef DEBUG_THREAD
140     PrintDebug("LockRunner");
141 #endif // DEBUG_THREAD
142     __Lock(&m_RunnerLock);
143 }
144
145 void ThreadManagement::UnlockRunner(void)
146 {
147 #ifdef DEBUG_THREAD
148     PrintDebug("UnlockRunner");
149 #endif // DEBUG_THREAD
150     __UnLock(&m_RunnerLock);
151 }
152
153 /***
154     [ScilabRead Lock]
155     Used to manage scilabRead output wich can be used by Console thread or
156     main thread through mscanf function.
157 ***/
158 void ThreadManagement::LockScilabRead(void)
159 {
160 #ifdef DEBUG_THREAD
161     PrintDebug("LockScilabRead");
162 #endif // DEBUG_THREAD
163     __Lock(&m_ScilabReadLock);
164 }
165
166 void ThreadManagement::UnlockScilabRead(void)
167 {
168 #ifdef DEBUG_THREAD
169     PrintDebug("UnlockScilabRead");
170 #endif // DEBUG_THREAD
171     __UnLock(&m_ScilabReadLock);
172 }
173
174 /***
175     [AvailableRunner Signal]
176
177     Send : The global Runner is available to store a new one.
178     Wait : This happens when the last Runner is not yet in execution.
179
180     This signal can be sent without any threads are waiting for,
181     so we have to perform the Wait for each call to WaitForConsoleExecDoneSignal.
182
183     The loop while is used to avoid spurious wakeup of __Wait.
184 ***/
185 void ThreadManagement::SendAvailableRunnerSignal(void)
186 {
187     __LockSignal(&m_AvailableRunnerLock);
188     m_AvailableRunnerWasSignalled = true;
189 #ifdef DEBUG_THREAD
190     PrintDebug("SendAvailableRunnerSignal");
191 #endif // DEBUG_THREAD
192     __Signal(&m_AvailableRunner);
193     __UnLockSignal(&m_AvailableRunnerLock);
194 }
195
196 void ThreadManagement::WaitForAvailableRunnerSignal(void)
197 {
198     __LockSignal(&m_AvailableRunnerLock);
199     m_AvailableRunnerWasSignalled = false;
200     while (m_AvailableRunnerWasSignalled == false)
201     {
202 #ifdef DEBUG_THREAD
203         PrintDebug("WaitForAvailableRunnerSignal");
204 #endif // DEBUG_THREAD
205         __Wait(&m_AvailableRunner, &m_AvailableRunnerLock);
206     }
207     __UnLockSignal(&m_AvailableRunnerLock);
208 }
209
210 /***
211     [ConsoleExecDone Signal]
212
213     Send : A console command is excuted.
214     Wait : Wait for the last console command ends.
215
216     This signal can be sent without any threads are waiting for,
217     so we have to perform the Wait for each call to WaitForConsoleExecDoneSignal.
218     (in case of "pause", we send this signal in sci_pause and in Runner::launch)
219
220     The loop while is used to avoid spurious wakeup of __Wait.
221 ***/
222 void ThreadManagement::SendConsoleExecDoneSignal(void)
223 {
224 #ifdef DEBUG_THREAD
225     PrintDebug("SendConsoleExecDoneSignal");
226 #endif // DEBUG_THREAD
227     __LockSignal(&m_ConsoleExecDoneLock);
228     m_ConsoleExecDoneWasSignalled = true;
229     __Signal(&m_ConsoleExecDone);
230     __UnLockSignal(&m_ConsoleExecDoneLock);
231 }
232
233 void ThreadManagement::WaitForConsoleExecDoneSignal(void)
234 {
235 # ifdef __DEBUG_SIGNAL
236     std::cout << "WaitForConsoleExecDoneSignal" << std::endl;
237 # endif // __DEBUG_SIGNAL
238     __LockSignal(&m_ConsoleExecDoneLock);
239     ThreadManagement::UnlockStoreCommand();
240     m_ConsoleExecDoneWasSignalled = false;
241     while (m_ConsoleExecDoneWasSignalled == false)
242     {
243 #ifdef DEBUG_THREAD
244         PrintDebug("WaitForConsoleExecDoneSignal");
245 #endif // DEBUG_THREAD
246         __Wait(&m_ConsoleExecDone, &m_ConsoleExecDoneLock);
247     }
248     __UnLockSignal(&m_ConsoleExecDoneLock);
249 }
250
251 /***
252     [DebuggerExecDone Signal]
253
254     Send : A debugger command is excuted.
255     Wait : Wait for its execution.
256
257     This signal can be sent without any threads are waiting for,
258     so we have to perform the Wait for each call to WaitForDebuggerExecDoneSignal.
259     (in case of "pause", we send this signal in sci_pause and in Runner::launch)
260
261     The loop while is used to avoid spurious wakeup of __Wait.
262 ***/
263 void ThreadManagement::SendDebuggerExecDoneSignal(void)
264 {
265 #ifdef DEBUG_THREAD
266     PrintDebug("SendDebuggerExecDoneSignal");
267 #endif // DEBUG_THREAD
268     __LockSignal(&m_DebuggerExecDoneLock);
269     m_DebuggerExecDoneWasSignalled = true;
270     __Signal(&m_DebuggerExecDone);
271     __UnLockSignal(&m_DebuggerExecDoneLock);
272 }
273
274 // bResume: resume execution before wait for its end
275 void ThreadManagement::WaitForDebuggerExecDoneSignal(bool bResume)
276 {
277 # ifdef __DEBUG_SIGNAL
278     std::cout << "WaitForDebuggerExecDoneSignal" << std::endl;
279 # endif // __DEBUG_SIGNAL
280     __LockSignal(&m_DebuggerExecDoneLock);
281     if(bResume)
282     {
283         // release execution there in case of pause
284         // because a released execution can be finished
285         // before we are waiting for.
286         // we avoid this by the lock of "m_DebuggerExecDoneLock"
287         // This signal is sent only in pause case because a runner already exists
288         ThreadManagement::SendRunMeSignal();
289     }
290
291     ThreadManagement::UnlockStoreCommand();
292     m_DebuggerExecDoneWasSignalled = false;
293     while (m_DebuggerExecDoneWasSignalled == false)
294     {
295 #ifdef DEBUG_THREAD
296         PrintDebug("WaitForDebuggerExecDoneSignal");
297 #endif // DEBUG_THREAD
298         __Wait(&m_DebuggerExecDone, &m_DebuggerExecDoneLock);
299     }
300     __UnLockSignal(&m_DebuggerExecDoneLock);
301 }
302
303 /***
304     [AwakeRunner Signal]
305
306     Send : Wakeup the runner when:
307     Wait : Runner is waiting for:
308             - a new prioritary command have to be execute.
309             - a pause is executed, to allow a new console command.
310             - the last execution is made.
311
312     This signal can be sent without any threads are waiting for,
313     so we have to perform the Wait for each call to WaitForAwakeRunnerSignal.
314
315     The loop while is used to avoid spurious wakeup of __Wait.
316 ***/
317
318 void ThreadManagement::SendAwakeRunnerSignal(void)
319 {
320 # ifdef __DEBUG_SIGNAL
321     std::cout << "SendAwakeRunnerSignal" << std::endl;
322 # endif // __DEBUG_SIGNAL
323     __LockSignal(&m_AwakeRunnerLock);
324     m_AwakeRunnerWasSignalled = true;
325 #ifdef DEBUG_THREAD
326     PrintDebug("SendAwakeRunnerSignal");
327 #endif // DEBUG_THREAD
328     __Signal(&m_AwakeRunner);
329     __UnLockSignal(&m_AwakeRunnerLock);
330 }
331
332 void ThreadManagement::WaitForAwakeRunnerSignal(void)
333 {
334 # ifdef __DEBUG_SIGNAL
335     std::cout << "WaitForAwakeRunnerSignal" << std::endl;
336 # endif // __DEBUG_SIGNAL
337     __LockSignal(&m_AwakeRunnerLock);
338     ThreadManagement::UnlockRunner();
339     m_AwakeRunnerWasSignalled = false;
340     while (m_AwakeRunnerWasSignalled == false)
341     {
342 #ifdef DEBUG_THREAD
343         PrintDebug("WaitForAwakeRunnerSignal");
344 #endif // DEBUG_THREAD
345         __Wait(&m_AwakeRunner, &m_AwakeRunnerLock);
346     }
347     __UnLockSignal(&m_AwakeRunnerLock);
348 }
349
350 /***
351     [StartPending Signal]
352
353     This signal is used in case where we have a console thread and a command to execute passed by -f argument.
354     We have to waiting for the "-f" execution before lets users to enter a new command through the console.
355
356     Send : The console thread (scilabReadAndStore) is ready.
357     Wait : The main thread can create the read and exec command thread (scilabReadAndExecCommand).
358
359     To avoid non-expected lost signal, we have to check if the signal was
360     already sent to know if we have to waiting for or not.
361
362     The loop while is used to avoid spurious wakeup of __Wait.
363 ***/
364 void ThreadManagement::SendStartPendingSignal(void)
365 {
366 # ifdef __DEBUG_SIGNAL
367     std::cout << "SendStartPendingSignal" << std::endl;
368 # endif // __DEBUG_SIGNAL
369     __LockSignal(&m_StartPendingLock);
370     m_StartPendingWasSignalled = true;
371 #ifdef DEBUG_THREAD
372     PrintDebug("SendStartPendingSignal");
373 #endif // DEBUG_THREAD
374     __Signal(&m_StartPending);
375     __UnLockSignal(&m_StartPendingLock);
376 }
377
378 void ThreadManagement::WaitForStartPendingSignal(void)
379 {
380 # ifdef __DEBUG_SIGNAL
381     std::cout << "WaitForStartPendingSignal" << std::endl;
382 # endif // __DEBUG_SIGNAL
383     __LockSignal(&m_StartPendingLock);
384     while (m_StartPendingWasSignalled == false)
385     {
386 #ifdef DEBUG_THREAD
387         PrintDebug("WaitForStartPendingSignal");
388 #endif // DEBUG_THREAD
389         __Wait(&m_StartPending, &m_StartPendingLock);
390     }
391     m_StartPendingWasSignalled = false;
392     __UnLockSignal(&m_StartPendingLock);
393 }
394
395 /***
396     [CommandStored Signal]
397
398     Send : A new command is available in the store command.
399     Wait : Wait for a new command.
400
401     To avoid non-expected lost signal, we have to check if the signal was
402     already sent to know if we have to waiting for or not.
403
404     The loop while is used to avoid spurious wakeup of __Wait.
405 ***/
406 void ThreadManagement::SendCommandStoredSignal(void)
407 {
408     __LockSignal(&m_CommandStoredLock);
409     m_CommandStoredWasSignalled = true;
410 #ifdef DEBUG_THREAD
411     PrintDebug("SendCommandStoredSignal");
412 #endif // DEBUG_THREAD
413     __Signal(&m_CommandStored);
414     __UnLockSignal(&m_CommandStoredLock);
415 }
416
417 void ThreadManagement::WaitForCommandStoredSignal(void)
418 {
419     __LockSignal(&m_CommandStoredLock);
420     while (m_CommandStoredWasSignalled == false)
421     {
422 #ifdef DEBUG_THREAD
423         PrintDebug("WaitForCommandStoredSignal");
424 #endif // DEBUG_THREAD
425         __Wait(&m_CommandStored, &m_CommandStoredLock);
426     }
427     m_CommandStoredWasSignalled = false;
428     __UnLockSignal(&m_CommandStoredLock);
429 }
430
431 /***
432     [RunMe Signal]
433
434     Send : A new runner is available for execution.
435     Wait : Wait for an available Runner.
436
437     This signal can be sent without any threads are waiting for,
438     so we have to perform the Wait for each call to WaitForRunMeSignal.
439     (This can happends when an execution is interrupted by another one.
440      This signal is sent but the main thread is not waiting for.)
441
442     The loop while is used to avoid spurious wakeup of __Wait.
443 ***/
444 void ThreadManagement::SendRunMeSignal(void)
445 {
446     __LockSignal(&m_RunMeLock);
447     m_RunMeWasSignalled = true;
448 #ifdef DEBUG_THREAD
449     PrintDebug("SendRunMeSignal");
450 #endif // DEBUG_THREAD
451     __Signal(&m_RunMe);
452     __UnLockSignal(&m_RunMeLock);
453 }
454
455 void ThreadManagement::WaitForRunMeSignal(void)
456 {
457     __LockSignal(&m_RunMeLock);
458     m_RunMeWasSignalled = false;
459     // Some times, the signal "SendRunMeSignal" can be sent before the main thread is waiting for.
460     // If a Runner is available do not perform this wait.
461     bool bWait = StaticRunner_isRunnerAvailable() == false;
462     while (m_RunMeWasSignalled == false && bWait)
463     {
464 #ifdef DEBUG_THREAD
465         PrintDebug("WaitForRunMeSignal");
466 #endif // DEBUG_THREAD
467         __Wait(&m_RunMe, &m_RunMeLock);
468     }
469     __UnLockSignal(&m_RunMeLock);
470 }
471
472 #ifdef DEBUG_THREAD
473 void ThreadManagement::SetThreadKey(__threadKey tkMain, __threadKey tkReadAndExec, __threadKey tkConsole)
474 {
475     m_tkMain = tkMain;
476     m_tkReadAndExec = tkReadAndExec;
477     m_tkConsole = tkConsole;
478 }
479
480 void ThreadManagement::PrintDebug(const char* pcfunName)
481 {
482     if (__GetCurrentThreadKey() == m_tkConsole)
483     {
484         std::cout.width(2 * PRINT_COL_SIZE);
485         std::cout << " ";
486     }
487
488     if (__GetCurrentThreadKey() == m_tkReadAndExec)
489     {
490         std::cout.width(PRINT_COL_SIZE);
491         std::cout << " ";
492     }
493
494     std::cout << pcfunName << std::endl;
495 }
496
497 void ThreadManagement::PrintDebugHead()
498 {
499     std::cout << std::endl;
500     std::cout.fill('-');
501     std::cout.width(3 * PRINT_COL_SIZE);
502     std::cout << "-";
503
504     std::cout.fill(' ');
505     std::cout << std::endl;
506     std::cout << std::left;
507     std::cout.width(PRINT_COL_SIZE);
508     std::cout << "Main Thread";
509     std::cout.width(PRINT_COL_SIZE);
510     std::cout << "ReadAndExec Thread";
511     std::cout.width(PRINT_COL_SIZE);
512     std::cout << "Console Thread";
513     std::cout << std::endl << std::endl;
514 }
515 #endif // DEBUG_THREAD