r598: no message
[ctsim.git] / src / backgroundsupr.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          BackgroundSupr.cpp
5 **   Purpose:       Background Supervisor classes
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  February 2001
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: backgroundsupr.cpp,v 1.10 2001/03/02 21:11:50 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "wx/wxprec.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/wx.h"
32 #endif
33
34 #include "ct.h"
35 #include "ctsim.h"
36 #include "docs.h"
37 #include "views.h"
38 #include "backgroundsupr.h"
39 #include "backgroundmgr.h"
40
41 #ifdef HAVE_WXTHREADS
42
43 ////////////////////////////////////////////////////////////////////////////
44 //
45 // Class BackgroundSupervisor -- An event handler run by a SupervisorThread
46 //
47 ////////////////////////////////////////////////////////////////////////////
48
49 IMPLEMENT_DYNAMIC_CLASS(BackgroundSupervisor, wxEvtHandler)
50 BEGIN_EVENT_TABLE(BackgroundSupervisor, BackgroundSupervisor)
51 EVT_MENU(MSG_BACKGROUND_SUPERVISOR_CANCEL, BackgroundSupervisor::OnCancel)
52 EVT_MENU(MSG_WORKER_THREAD_FAIL, BackgroundSupervisor::OnWorkerFail)
53 EVT_MENU(MSG_WORKER_THREAD_DONE, BackgroundSupervisor::OnWorkerDone)
54 EVT_MENU(MSG_WORKER_THREAD_UNIT_TICK, BackgroundSupervisor::OnWorkerUnitTick)
55 EVT_MENU(MSG_DOCUMENT_ACK_REMOVE, BackgroundSupervisor::OnAckDocumentRemove)
56 END_EVENT_TABLE()
57
58 // Static function
59 void 
60 BackgroundSupervisor::cancelSupervisor (BackgroundSupervisor* pSupervisor)
61 {
62   wxCommandEvent cancelEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_CANCEL);
63   wxPostEvent (pSupervisor, cancelEvent);
64 }
65
66
67 BackgroundSupervisor::BackgroundSupervisor (SupervisorThread* pMyThread, wxFrame* pParentFrame, wxDocument* pDocument, const char* const pszProcessTitle, int iTotalUnits)
68     : m_pMyThread(pMyThread), m_pParentFrame(pParentFrame), m_pDocument(pDocument), m_strProcessTitle(pszProcessTitle), 
69     m_iTotalUnits(iTotalUnits), m_iNumThreads(0), m_bDone(false), m_bFail(false), m_bCancelled(false), 
70     m_pTimer(NULL), m_bBackgroundTaskAdded(false), m_bWorkersDeleted(false),
71     wxEvtHandler()
72 {
73   m_iNumThreads = theApp->getNumberCPU();
74     ++m_iNumThreads;
75
76   m_vecpThreads.reserve (m_iNumThreads);
77   for (int iThread = 0; iThread < m_iNumThreads; iThread++)
78     m_vecpThreads[iThread] = NULL;
79
80 }
81
82 BackgroundSupervisor::~BackgroundSupervisor()
83 {
84   if (m_bBackgroundTaskAdded) {
85     wxCommandEvent doneEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_REMOVE);
86     doneEvent.SetClientData (this);
87     wxPostEvent (theApp->getBackgroundManager(), doneEvent);
88     wxPostEvent (m_pDocument, doneEvent);
89   }
90
91   while (m_bBackgroundTaskAdded) {
92     m_pMyThread->Sleep(50);
93     ProcessPendingEvents();
94   }
95
96   delete m_pTimer;
97 }
98
99 void
100 BackgroundSupervisor::deleteWorkers()
101 {
102   wxCriticalSectionLocker lock (m_critsectThreads);
103   if (m_bWorkersDeleted)
104     return;
105
106   for (int i = 0; i < m_iNumThreads; i++) 
107     if (m_vecpThreads[i]) {
108       m_vecpThreads[i]->Delete(); // sends Destroy message to workers
109   }
110
111   while (m_iRunning > 0) {
112     m_pMyThread->Sleep(50);
113     ProcessPendingEvents();
114   }
115   m_iRunning = 0;
116   m_bWorkersDeleted = true;
117 }
118
119 bool
120 BackgroundSupervisor::start()
121 {
122   int iBaseUnits = m_iTotalUnits / m_iNumThreads;
123   int iExtraUnits = m_iTotalUnits % m_iNumThreads;
124   int iStartUnit = 0;
125   for (int iThread = 0; iThread < m_iNumThreads; iThread++) {
126     int iNumUnits = iBaseUnits;
127     if (iThread < iExtraUnits)
128       ++iNumUnits;
129     m_vecpThreads[iThread] = createWorker (iThread, iStartUnit, iNumUnits);
130     if (! m_vecpThreads[iThread]) {
131       m_bFail = true;
132       m_strFailMessage = "createWorker returned NULL [BackgroundSupervisor]";
133       break;
134     }
135     if (m_vecpThreads[iThread]->Create () != wxTHREAD_NO_ERROR) {
136       m_bFail = true;
137       m_strFailMessage = "Thread creation failed [BackgroundSupervisor]";
138       break;
139     }
140    m_vecpThreads[iThread]->SetPriority (40);
141    iStartUnit += iNumUnits;
142   }
143   if (m_bFail)
144     return false;
145
146   m_pTimer = new Timer;
147   
148   std::string strLabel (m_strProcessTitle);
149   strLabel += " ";
150   strLabel += m_pParentFrame->GetTitle();
151   wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD);
152   addTaskEvent.SetString (strLabel.c_str());
153   addTaskEvent.SetInt (m_iTotalUnits);
154   addTaskEvent.SetClientData (this);
155   wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
156   wxPostEvent (m_pDocument, addTaskEvent);
157   m_bBackgroundTaskAdded = true;
158   
159   m_iRunning = m_iNumThreads;
160   m_iUnitsDone = 0;
161
162   for (int i = 0; i < m_iNumThreads; i++)
163     m_vecpThreads[i]->Run();
164     
165   return true;
166 }
167
168 void
169 BackgroundSupervisor::OnCancel(wxCommandEvent& event)
170 {
171   m_bCancelled = true;
172   m_bDone = true;
173   deleteWorkers();
174 }
175
176 void
177 BackgroundSupervisor::OnAckDocumentRemove(wxCommandEvent& event)
178 {
179   m_bBackgroundTaskAdded = false;
180 }
181
182 void
183 BackgroundSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
184 {
185     ++m_iUnitsDone;
186     
187 #ifdef DEBUG
188     if (theApp->getVerboseLogging())
189       *theApp->getLog() << "Units done: " << static_cast<int>(m_iUnitsDone) <<"\n";
190 #endif
191     
192     wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK);
193     addTaskEvent.SetInt (m_iUnitsDone - 1);
194     addTaskEvent.SetClientData (this);
195     wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
196 }
197
198 void
199 BackgroundSupervisor::OnWorkerDone (wxCommandEvent& event)
200 {
201   m_iRunning--;
202   wxASSERT (m_iRunning >= 0);
203
204 #ifdef DEBUG
205   if (theApp->getVerboseLogging()) {
206     wxString msg;
207     msg.Printf("Background Supervisor: Thread finished. Remaining threads: %d\n", m_iRunning);  
208     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
209     eventLog.SetString( msg );
210     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
211   }
212 #endif
213   if (m_iRunning <= 0 && ! m_bCancelled) {
214     deleteWorkers();
215     onDone();
216   }
217 }
218
219 void
220 BackgroundSupervisor::OnWorkerFail (wxCommandEvent& event)
221 {
222   m_iRunning--;
223   wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
224   eventLog.SetString( event.GetString() );
225   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
226
227   wxCommandEvent dummy;
228   OnCancel(dummy);
229 }
230
231 #endif // HAVE_WXTHREADS