OpenCPN Partial API docs
SencManager.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: S57 Chart Object
5  * Author: David Register
6  *
7  ***************************************************************************
8  * Copyright (C) 2010 by David S. Register *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  **************************************************************************/
25 
26 // For compilers that support precompilation, includes "wx.h".
27 #include "wx/wxprec.h"
28 
29 #ifndef WX_PRECOMP
30 #include "wx/wx.h"
31 #endif // precompiled headers
32 
33 #include "s57chart.h"
34 #include "Osenc.h"
35 #include "chcanv.h"
36 #include "ocpn_frame.h"
37 
38 extern MyFrame *gFrame;
39 extern int g_nCPUCount;
40 extern S57ClassRegistrar *g_poRegistrar;
41 
42 //----------------------------------------------------------------------------------
43 // SENCJobTicket Implementation
44 //----------------------------------------------------------------------------------
45 SENCJobTicket::SENCJobTicket() {
46  m_SENCResult = SENC_BUILD_INACTIVE;
47  m_status = THREAD_INACTIVE;
48 }
49 
50 const wxEventType wxEVT_OCPN_BUILDSENCTHREAD = wxNewEventType();
51 
52 //----------------------------------------------------------------------------------
53 // OCPN_BUILDSENC_ThreadEvent Implementation
54 //----------------------------------------------------------------------------------
55 OCPN_BUILDSENC_ThreadEvent::OCPN_BUILDSENC_ThreadEvent(wxEventType commandType,
56  int id)
57  : wxEvent(id, commandType) {
58  stat = 0;
59 }
60 
61 OCPN_BUILDSENC_ThreadEvent::~OCPN_BUILDSENC_ThreadEvent() {}
62 
63 wxEvent *OCPN_BUILDSENC_ThreadEvent::Clone() const {
65  newevent->stat = this->stat;
66  newevent->type = this->type;
67  newevent->m_ticket = this->m_ticket;
68 
69  return newevent;
70 }
71 
72 //----------------------------------------------------------------------------------
73 // SENCThreadManager Implementation
74 //----------------------------------------------------------------------------------
75 SENCThreadManager::SENCThreadManager() {
76  // ideally we would use the cpu count -1, and only launch jobs
77  // when the idle load average is sufficient (greater than 1)
78  int nCPU = wxMax(1, wxThread::GetCPUCount());
79  if (g_nCPUCount > 0) nCPU = g_nCPUCount;
80 
81  // obviously there's at least one CPU!
82  if (nCPU < 1) nCPU = 1;
83 
84  m_max_jobs = wxMax(nCPU - 1, 1);
85  // m_max_jobs = 1;
86 
87  wxLogDebug("SENC: nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
88 
89  // Create/connect a dynamic event handler slot for messages from the worker
90  // threads
91  Connect(
92  wxEVT_OCPN_BUILDSENCTHREAD,
93  (wxObjectEventFunction)(wxEventFunction)&SENCThreadManager::OnEvtThread);
94 
95  // m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(
96  // glTextureManager::OnTimer ), NULL, this); m_timer.Start(500);
97 }
98 
99 SENCThreadManager::~SENCThreadManager() {
100  // ClearJobList();
101 }
102 
103 SENCThreadStatus SENCThreadManager::ScheduleJob(SENCJobTicket *ticket) {
104  // Do not add a job if there is already a job pending for this chart, by name
105  for (size_t i = 0; i < ticket_list.size(); i++) {
106  if (ticket_list[i]->m_FullPath000 == ticket->m_FullPath000)
107  return THREAD_PENDING;
108  }
109 
110  ticket->m_status = THREAD_PENDING;
111  ticket_list.push_back(ticket);
112 
113  // printf("Scheduling job: %s\n", (const
114  // char*)ticket->m_FullPath000.mb_str()); printf("Job count: %d\n",
115  // ticket_list.size());
116  StartTopJob();
117  return THREAD_PENDING;
118 }
119 
120 void SENCThreadManager::StartTopJob() {
121  SENCJobTicket *startCandidate;
122  // Get the running job count
123  int nRunning = 0;
124  for (size_t i = 0; i < ticket_list.size(); i++) {
125  if (ticket_list[i]->m_status == THREAD_STARTED) nRunning++;
126  }
127 
128  // OK to start one?
129  if (nRunning < m_max_jobs) {
130  // Find the first eligible
131  startCandidate = NULL;
132  for (size_t i = 0; i < ticket_list.size(); i++) {
133  if (ticket_list[i]->m_status == THREAD_PENDING) {
134  startCandidate = ticket_list[i];
135  break;
136  }
137  }
138 
139  // Found one?
140  if (startCandidate) {
141  // printf("Starting job: %s\n", (const
142  // char*)startCandidate->m_FullPath000.mb_str());
143 
144  SENCBuildThread *thread = new SENCBuildThread(startCandidate, this);
145  startCandidate->m_thread = thread;
146  startCandidate->m_status = THREAD_STARTED;
147  thread->SetPriority(20);
148  thread->Run();
149  nRunning++;
150  }
151  }
152 
153  if (nRunning) {
154  wxString count;
155  count.Printf(_T(" %ld"), ticket_list.size());
156  if (gFrame->GetPrimaryCanvas())
157  gFrame->GetPrimaryCanvas()->SetAlertString(_("Preparing vector chart ") +
158  count);
159  }
160 }
161 
162 void SENCThreadManager::FinishJob(SENCJobTicket *ticket) {
163  // printf("Finishing job: %s\n", (const
164  // char*)ticket->m_FullPath000.mb_str());
165 
166  // Find and remove the ticket from the list
167  for (size_t i = 0; i < ticket_list.size(); i++) {
168  if (ticket_list[i] == ticket) {
169  // printf(" Removing job: %s\n", (const
170  // char*)ticket->m_FullPath000.mb_str());
171 
172  ticket_list.erase(ticket_list.begin() + i);
173  // printf("Job count: %d\n", ticket_list.size());
174 
175  break;
176  }
177  }
178 
179 #if 1
180  int nRunning = 0;
181  for (size_t i = 0; i < ticket_list.size(); i++) {
182  if (ticket_list[i]->m_status == THREAD_STARTED) nRunning++;
183  }
184 
185  if (nRunning) {
186  wxString count;
187  count.Printf(_T(" %ld"), ticket_list.size());
188  if (gFrame->GetPrimaryCanvas())
189  gFrame->GetPrimaryCanvas()->SetAlertString(_("Preparing vector chart ") +
190  count);
191  } else {
192  if (gFrame->GetPrimaryCanvas())
193  gFrame->GetPrimaryCanvas()->SetAlertString(_T(""));
194  }
195 #endif
196 }
197 
198 int SENCThreadManager::GetJobCount() { return ticket_list.size(); }
199 
200 bool SENCThreadManager::IsChartInTicketlist(s57chart *chart) {
201  for (size_t i = 0; i < ticket_list.size(); i++) {
202  if (ticket_list[i]->m_chart == chart) return true;
203  }
204  return false;
205 }
206 
207 bool SENCThreadManager::SetChartPointer(s57chart *chart, void *new_ptr) {
208  // Find the ticket
209  for (size_t i = 0; i < ticket_list.size(); i++) {
210  if (ticket_list[i]->m_chart == chart) {
211  ticket_list[i]->m_chart = (s57chart *)new_ptr;
212  return true;
213  }
214  }
215  return false;
216 }
217 
218 #define NBAR_LENGTH 40
219 
220 void SENCThreadManager::OnEvtThread(OCPN_BUILDSENC_ThreadEvent &event) {
221  OCPN_BUILDSENC_ThreadEvent Sevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
222 
223  switch (event.type) {
224  case SENC_BUILD_STARTED:
225  // printf("SENC build started\n");
226  Sevent.type = SENC_BUILD_STARTED;
227  Sevent.m_ticket = event.m_ticket;
228 
229  break;
230  case SENC_BUILD_DONE_NOERROR:
231  // printf("SENC build done no error\n");
232  Sevent.type = SENC_BUILD_DONE_NOERROR;
233  Sevent.m_ticket = event.m_ticket;
234  FinishJob(event.m_ticket);
235  StartTopJob();
236 
237  break;
238  case SENC_BUILD_DONE_ERROR:
239  // printf("SENC build done ERROR\n");
240  Sevent.type = SENC_BUILD_DONE_ERROR;
241  Sevent.m_ticket = event.m_ticket;
242  FinishJob(event.m_ticket);
243  StartTopJob();
244 
245  break;
246  default:
247  break;
248  }
249  if (gFrame) gFrame->GetEventHandler()->AddPendingEvent(Sevent);
250 }
251 
252 //----------------------------------------------------------------------------------
253 // SENCBuildThread Implementation
254 //----------------------------------------------------------------------------------
255 
256 SENCBuildThread::SENCBuildThread(SENCJobTicket *ticket,
257  SENCThreadManager *manager) {
258  m_FullPath000 = ticket->m_FullPath000;
259  m_SENCFileName = ticket->m_SENCFileName;
260  m_manager = manager;
261  m_ticket = ticket;
262 
263  Create();
264 }
265 
266 void *SENCBuildThread::Entry() {
267  //#ifdef __MSVC__
268  // _set_se_translator(my_translate);
269 
270  // On Windows, if anything in this thread produces a SEH exception (like
271  // access violation) we handle the exception locally, and simply alow the
272  // thread to exit smoothly with no results. Upstream will notice that nothing
273  // got done, and maybe try again later.
274 
275  try
276  //#endif
277  {
278  // Start the SENC build
279  Osenc senc;
280 
281  senc.setRegistrar(g_poRegistrar);
282  senc.setRefLocn(m_ticket->ref_lat, m_ticket->ref_lon);
283  senc.SetLODMeters(m_ticket->m_LOD_meters);
284  senc.setNoErrDialog(true);
285 
286  m_ticket->m_SENCResult = SENC_BUILD_STARTED;
287  OCPN_BUILDSENC_ThreadEvent Sevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
288  Sevent.stat = 0;
289  Sevent.type = SENC_BUILD_STARTED;
290  Sevent.m_ticket = m_ticket;
291  if (m_manager) m_manager->QueueEvent(Sevent.Clone());
292 
293  int ret = senc.createSenc200(m_FullPath000, m_SENCFileName, false);
294 
295  OCPN_BUILDSENC_ThreadEvent Nevent(wxEVT_OCPN_BUILDSENCTHREAD, 0);
296  Nevent.stat = ret;
297  Nevent.m_ticket = m_ticket;
298  if (ret == ERROR_INGESTING000)
299  Nevent.type = SENC_BUILD_DONE_ERROR;
300  else
301  Nevent.type = SENC_BUILD_DONE_NOERROR;
302 
303  m_ticket->m_SENCResult = Sevent.type;
304  if (m_manager) m_manager->QueueEvent(Nevent.Clone());
305 
306  // if(ret == ERROR_INGESTING000)
307  // return BUILD_SENC_NOK_PERMANENT;
308  // else
309  // return ret;
310 
311  return 0;
312  } // try
313 
314  //#ifdef __MSVC__
315  catch (const std::exception &e /*SE_Exception e*/) {
316  const char *msg = e.what();
317  if (m_manager) {
318  // OCPN_CompressionThreadEvent
319  // Nevent(wxEVT_OCPN_COMPRESSIONTHREAD, 0);
320  // m_ticket->b_isaborted = true;
321  // Nevent.SetTicket(m_ticket);
322  // Nevent.type = 0;
323  // m_manager->QueueEvent(Nevent.Clone());
324  }
325 
326  return 0;
327  }
328  //#endif
329 }
Definition: Osenc.h:401