r580: 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.3 2001/02/25 08:00:57 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 (wxFrame* pParentFrame, wxDocument* pDocument, const char* const pszProcessTitle, int iTotalUnits)
71     : 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),
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   for (int i = 0; i < m_iNumThreads; i++) 
88     if (m_vecpThreads[i]) {
89       m_vecpThreads[i]->Delete(); // sends Destroy message to workers
90   }
91
92   while (m_iRunning > 0) {
93     Sleep(50);
94     ProcessPendingEvents();
95   }
96
97   if (m_bBackgroundTaskAdded) {
98     wxCommandEvent doneEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_REMOVE);
99     doneEvent.SetClientData (this);
100     wxPostEvent (theApp->getBackgroundManager(), doneEvent);
101     wxPostEvent (m_pDocument, doneEvent);
102   }
103
104   while (m_bBackgroundTaskAdded) {
105     Sleep(50);
106     ProcessPendingEvents();
107   }
108
109   delete m_pTimer;
110   delete m_pDialogProgress;
111 }
112
113 bool
114 BackgroundSupervisor::start()
115 {
116   int iBaseUnits = m_iTotalUnits / m_iNumThreads;
117   int iExtraUnits = m_iTotalUnits % m_iNumThreads;
118   for (int iThread = 0; iThread < m_iNumThreads; iThread++) {
119     int iStartUnit = iThread * iBaseUnits;
120     int iNumUnits = iBaseUnits;
121     if (iThread < iExtraUnits)
122       ++iNumUnits;
123     m_vecpThreads[iThread] = createWorker (iThread, iStartUnit, iNumUnits);
124     if (! m_vecpThreads[iThread]) {
125       m_bFail = true;
126       m_strFailMessage = "createWorker returned NULL [BackgroundSupervisor]";
127       break;
128     }
129     if (m_vecpThreads[iThread]->Create () != wxTHREAD_NO_ERROR) {
130       m_bFail = true;
131       m_strFailMessage = "Thread creation failed [BackgroundSupervisor]";
132       break;
133     }
134     m_vecpThreads[iThread]->SetPriority (40);
135   }
136   if (m_bFail)
137     return false;
138
139   m_pTimer = new Timer;
140   
141   if (! theApp->getUseBackgroundTasks())
142     m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), 
143     m_iTotalUnits, m_pParentFrame, wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
144   else {
145     std::string strLabel (m_strProcessTitle);
146     strLabel += " ";
147     strLabel += m_pParentFrame->GetTitle();
148     wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD);
149     addTaskEvent.SetString (strLabel.c_str());
150     addTaskEvent.SetInt (m_iTotalUnits);
151     addTaskEvent.SetClientData (this);
152     wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
153     wxPostEvent (m_pDocument, addTaskEvent);
154     m_bBackgroundTaskAdded = true;
155   }
156   
157   m_iRunning = m_iNumThreads;
158   m_iUnitsDone = 0;
159
160   for (int i = 0; i < m_iNumThreads; i++)
161     m_vecpThreads[i]->Run();
162     
163   return true;
164 }
165
166 void
167 BackgroundSupervisor::OnCancel(wxCommandEvent& event)
168 {
169   m_bCancelled = true;
170   m_bDone = true;
171 }
172
173 void
174 BackgroundSupervisor::OnAckDocumentRemove(wxCommandEvent& event)
175 {
176   m_bBackgroundTaskAdded = false;
177 }
178
179 void
180 BackgroundSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
181 {
182     ++m_iUnitsDone;
183     
184 #ifdef DEBUG
185     if (theApp->getVerboseLogging())
186       *theApp->getLog() << "Units done: " << static_cast<int>(m_iUnitsDone) <<"\n";
187 #endif
188     
189     if (m_pDialogProgress) {
190       if (! m_pDialogProgress->Update (m_iUnitsDone - 1)) {
191         wxCommandEvent dummy;
192         OnCancel (dummy);
193       }
194     } else {
195       wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK);
196       addTaskEvent.SetInt (m_iUnitsDone - 1);
197       addTaskEvent.SetClientData (this);
198       wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
199     }
200 }
201
202 void
203 BackgroundSupervisor::OnWorkerDone (wxCommandEvent& event)
204 {
205   m_iRunning--;
206   wxASSERT (m_iRunning >= 0);
207
208 #ifdef DEBUG
209   if (theApp->getVerboseLogging()) {
210     wxString msg;
211     msg.Printf("Background Supervisor: Thread finished. Remaining threads: %d\n", m_iRunning);  
212     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
213     eventLog.SetString( msg );
214     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
215   }
216 #endif
217   if (m_iRunning <= 0 && ! m_bCancelled)
218     onDone();
219 }
220
221 void
222 BackgroundSupervisor::OnWorkerFail (wxCommandEvent& event)
223 {
224   m_iRunning--;
225   wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
226   eventLog.SetString( event.GetString() );
227   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
228
229   wxCommandEvent dummy;
230   OnCancel(dummy);
231 }
232