r588: 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.8 2001/02/26 17:36:56 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 #if defined(HAVE_CONFIG_H)
42 #include "config.h"
43 #endif
44
45
46 ////////////////////////////////////////////////////////////////////////////
47 //
48 // Class BackgroundSupervisor -- An event handler run by a SupervisorThread
49 //
50 ////////////////////////////////////////////////////////////////////////////
51
52 IMPLEMENT_DYNAMIC_CLASS(BackgroundSupervisor, wxEvtHandler)
53 BEGIN_EVENT_TABLE(BackgroundSupervisor, BackgroundSupervisor)
54 EVT_MENU(MSG_BACKGROUND_SUPERVISOR_CANCEL, BackgroundSupervisor::OnCancel)
55 EVT_MENU(MSG_WORKER_THREAD_FAIL, BackgroundSupervisor::OnWorkerFail)
56 EVT_MENU(MSG_WORKER_THREAD_DONE, BackgroundSupervisor::OnWorkerDone)
57 EVT_MENU(MSG_WORKER_THREAD_UNIT_TICK, BackgroundSupervisor::OnWorkerUnitTick)
58 EVT_MENU(MSG_DOCUMENT_ACK_REMOVE, BackgroundSupervisor::OnAckDocumentRemove)
59 END_EVENT_TABLE()
60
61 // Static function
62 void 
63 BackgroundSupervisor::cancelSupervisor (BackgroundSupervisor* pSupervisor)
64 {
65   wxCommandEvent cancelEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_CANCEL);
66   wxPostEvent (pSupervisor, cancelEvent);
67 }
68
69
70 BackgroundSupervisor::BackgroundSupervisor (SupervisorThread* pMyThread, wxFrame* pParentFrame, wxDocument* pDocument, const char* const pszProcessTitle, int iTotalUnits)
71     : m_pMyThread(pMyThread), m_pParentFrame(pParentFrame), m_pDocument(pDocument), m_pDialogProgress(NULL), m_strProcessTitle(pszProcessTitle), 
72     m_iTotalUnits(iTotalUnits), m_iNumThreads(0), m_bDone(false), m_bFail(false), m_bCancelled(false), 
73     m_pTimer(NULL), m_bBackgroundTaskAdded(false), m_bWorkersDeleted(false),
74     wxEvtHandler()
75 {
76   m_iNumThreads = theApp->getNumberCPU();
77 //    ++m_iNumThreads;
78
79   m_vecpThreads.reserve (m_iNumThreads);
80   for (int iThread = 0; iThread < m_iNumThreads; iThread++)
81     m_vecpThreads[iThread] = NULL;
82
83 }
84
85 BackgroundSupervisor::~BackgroundSupervisor()
86 {
87   if (m_bBackgroundTaskAdded) {
88     wxCommandEvent doneEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_REMOVE);
89     doneEvent.SetClientData (this);
90     wxPostEvent (theApp->getBackgroundManager(), doneEvent);
91     wxPostEvent (m_pDocument, doneEvent);
92   }
93
94   while (m_bBackgroundTaskAdded) {
95     m_pMyThread->Sleep(50);
96     ProcessPendingEvents();
97   }
98
99   delete m_pTimer;
100   delete m_pDialogProgress;
101 }
102
103 void
104 BackgroundSupervisor::deleteWorkers()
105 {
106   wxCriticalSectionLocker lock (m_critsectThreads);
107   if (m_bWorkersDeleted)
108     return;
109
110   for (int i = 0; i < m_iNumThreads; i++) 
111     if (m_vecpThreads[i]) {
112       m_vecpThreads[i]->Delete(); // sends Destroy message to workers
113   }
114
115   while (m_iRunning > 0) {
116     m_pMyThread->Sleep(50);
117     ProcessPendingEvents();
118   }
119   m_iRunning = 0;
120   m_bWorkersDeleted = true;
121 }
122
123 bool
124 BackgroundSupervisor::start()
125 {
126   int iBaseUnits = m_iTotalUnits / m_iNumThreads;
127   int iExtraUnits = m_iTotalUnits % m_iNumThreads;
128   for (int iThread = 0; iThread < m_iNumThreads; iThread++) {
129     int iStartUnit = iThread * iBaseUnits;
130     int iNumUnits = iBaseUnits;
131     if (iThread < iExtraUnits)
132       ++iNumUnits;
133     m_vecpThreads[iThread] = createWorker (iThread, iStartUnit, iNumUnits);
134     if (! m_vecpThreads[iThread]) {
135       m_bFail = true;
136       m_strFailMessage = "createWorker returned NULL [BackgroundSupervisor]";
137       break;
138     }
139     if (m_vecpThreads[iThread]->Create () != wxTHREAD_NO_ERROR) {
140       m_bFail = true;
141       m_strFailMessage = "Thread creation failed [BackgroundSupervisor]";
142       break;
143     }
144     m_vecpThreads[iThread]->SetPriority (40);
145   }
146   if (m_bFail)
147     return false;
148
149   m_pTimer = new Timer;
150   
151   if (! theApp->getUseBackgroundTasks())
152     m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), 
153     m_iTotalUnits, m_pParentFrame, wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
154   else {
155     std::string strLabel (m_strProcessTitle);
156     strLabel += " ";
157     strLabel += m_pParentFrame->GetTitle();
158     wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD);
159     addTaskEvent.SetString (strLabel.c_str());
160     addTaskEvent.SetInt (m_iTotalUnits);
161     addTaskEvent.SetClientData (this);
162     wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
163     wxPostEvent (m_pDocument, addTaskEvent);
164     m_bBackgroundTaskAdded = true;
165   }
166   
167   m_iRunning = m_iNumThreads;
168   m_iUnitsDone = 0;
169
170   for (int i = 0; i < m_iNumThreads; i++)
171     m_vecpThreads[i]->Run();
172     
173   return true;
174 }
175
176 void
177 BackgroundSupervisor::OnCancel(wxCommandEvent& event)
178 {
179   m_bCancelled = true;
180   m_bDone = true;
181   deleteWorkers();
182 }
183
184 void
185 BackgroundSupervisor::OnAckDocumentRemove(wxCommandEvent& event)
186 {
187   m_bBackgroundTaskAdded = false;
188 }
189
190 void
191 BackgroundSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
192 {
193     ++m_iUnitsDone;
194     
195 #ifdef DEBUG
196     if (theApp->getVerboseLogging())
197       *theApp->getLog() << "Units done: " << static_cast<int>(m_iUnitsDone) <<"\n";
198 #endif
199     
200     if (m_pDialogProgress) {
201       if (! m_pDialogProgress->Update (m_iUnitsDone - 1)) {
202         wxCommandEvent dummy;
203         OnCancel (dummy);
204       }
205     } else {
206       wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK);
207       addTaskEvent.SetInt (m_iUnitsDone - 1);
208       addTaskEvent.SetClientData (this);
209       wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
210     }
211 }
212
213 void
214 BackgroundSupervisor::OnWorkerDone (wxCommandEvent& event)
215 {
216   m_iRunning--;
217   wxASSERT (m_iRunning >= 0);
218
219 #ifdef DEBUG
220   if (theApp->getVerboseLogging()) {
221     wxString msg;
222     msg.Printf("Background Supervisor: Thread finished. Remaining threads: %d\n", m_iRunning);  
223     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
224     eventLog.SetString( msg );
225     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
226   }
227 #endif
228   if (m_iRunning <= 0 && ! m_bCancelled) {
229     deleteWorkers();
230     onDone();
231   }
232 }
233
234 void
235 BackgroundSupervisor::OnWorkerFail (wxCommandEvent& event)
236 {
237   m_iRunning--;
238   wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
239   eventLog.SetString( event.GetString() );
240   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
241
242   wxCommandEvent dummy;
243   OnCancel(dummy);
244 }
245