r579: 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.2 2001/02/25 07:36:26 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   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     Sleep(50);
96     ProcessPendingEvents();
97   }
98
99   delete m_pTimer;
100   delete m_pDialogProgress;
101 }
102
103 void
104 BackgroundSupervisor::deleteAnyWorkers()
105 {
106   m_critsectThreadContainer.Enter();  
107   for (int i = 0; i < m_iNumThreads; i++) 
108     if (m_vecpThreads[i]) {
109       m_vecpThreads[i]->Delete(); // sends Destroy message to workers
110   }
111   m_critsectThreadContainer.Leave();
112
113   while (m_iRunning > 0) {
114     Sleep(50);
115     ProcessPendingEvents();
116   }
117 }
118
119
120 bool
121 BackgroundSupervisor::start()
122 {
123   int iBaseUnits = m_iTotalUnits / m_iNumThreads;
124   int iExtraUnits = m_iTotalUnits % m_iNumThreads;
125   for (int iThread = 0; iThread < m_iNumThreads; iThread++) {
126     int iStartUnit = iThread * iBaseUnits;
127     int iNumUnits = iBaseUnits;
128     if (iThread < iExtraUnits)
129       ++iNumUnits;
130     m_vecpThreads[iThread] = createWorker (iThread, iStartUnit, iNumUnits);
131     if (! m_vecpThreads[iThread]) {
132       m_bFail = true;
133       m_strFailMessage = "createWorker returned NULL [BackgroundSupervisor]";
134       break;
135     }
136     if (m_vecpThreads[iThread]->Create () != wxTHREAD_NO_ERROR) {
137       m_bFail = true;
138       m_strFailMessage = "Thread creation failed [BackgroundSupervisor]";
139       break;
140     }
141     m_vecpThreads[iThread]->SetPriority (40);
142   }
143   if (m_bFail)
144     return false;
145
146   m_pTimer = new Timer;
147   
148   if (! theApp->getUseBackgroundTasks())
149     m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), 
150     m_iTotalUnits, m_pParentFrame, wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
151   else {
152     std::string strLabel (m_strProcessTitle);
153     strLabel += " ";
154     strLabel += m_pParentFrame->GetTitle();
155     wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD);
156     addTaskEvent.SetString (strLabel.c_str());
157     addTaskEvent.SetInt (m_iTotalUnits);
158     addTaskEvent.SetClientData (this);
159     wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
160     wxPostEvent (m_pDocument, addTaskEvent);
161     m_bBackgroundTaskAdded = true;
162   }
163   
164   m_iRunning = m_iNumThreads;
165   m_iUnitsDone = 0;
166
167   for (int i = 0; i < m_iNumThreads; i++)
168     m_vecpThreads[i]->Run();
169     
170   return true;
171 }
172
173 void
174 BackgroundSupervisor::OnCancel(wxCommandEvent& event)
175 {
176   m_bCancelled = true;
177   deleteAnyWorkers();
178   m_bDone = true;
179 }
180
181 void
182 BackgroundSupervisor::OnAckDocumentRemove(wxCommandEvent& event)
183 {
184   m_bBackgroundTaskAdded = false;
185 }
186
187 void
188 BackgroundSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
189 {
190     ++m_iUnitsDone;
191     
192 #ifdef DEBUG
193     if (theApp->getVerboseLogging())
194       *theApp->getLog() << "Units done: " << static_cast<int>(m_iUnitsDone) <<"\n";
195 #endif
196     
197     if (m_pDialogProgress) {
198       if (! m_pDialogProgress->Update (m_iUnitsDone - 1)) {
199         wxCommandEvent dummy;
200         OnCancel (dummy);
201       }
202     } else {
203       wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK);
204       addTaskEvent.SetInt (m_iUnitsDone - 1);
205       addTaskEvent.SetClientData (this);
206       wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
207     }
208 }
209
210 void
211 BackgroundSupervisor::OnWorkerDone (wxCommandEvent& event)
212 {
213   m_iRunning--;
214   wxASSERT (m_iRunning >= 0);
215   m_critsectThreadContainer.Enter();
216   m_vecpThreads[event.GetInt()] = NULL;
217   m_critsectThreadContainer.Leave();
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     onDone();
230 }
231
232 void
233 BackgroundSupervisor::OnWorkerFail (wxCommandEvent& event)
234 {
235   m_iRunning--;
236   m_critsectThreadContainer.Enter();
237   m_vecpThreads[event.GetInt()] = NULL;
238   m_critsectThreadContainer.Leave();
239   wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
240   eventLog.SetString( event.GetString() );
241   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
242
243   onDone();
244 }
245