foobar2000 SDK  2015-01-14
ThreadUtils.h
Go to the documentation of this file.
1 namespace ThreadUtils {
2  static bool WaitAbortable(HANDLE ev, abort_callback & abort, DWORD timeout = INFINITE) {
3  const HANDLE handles[2] = {ev, abort.get_abort_event()};
4  SetLastError(0);
5  const DWORD status = WaitForMultipleObjects(2, handles, FALSE, timeout);
6  switch(status) {
7  case WAIT_TIMEOUT:
8  PFC_ASSERT( timeout != INFINITE );
9  return false;
10  case WAIT_OBJECT_0:
11  return true;
12  case WAIT_OBJECT_0 + 1:
13  throw exception_aborted();
14  case WAIT_FAILED:
15  WIN32_OP_FAIL();
16  default:
17  uBugCheck();
18  }
19  }
20 
21  static void ProcessPendingMessages() {
22  MSG msg = {};
23  while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
24  DispatchMessage(&msg);
25  }
26  }
27 
28 
29  static void WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort) {
30  const HANDLE handles[2] = {ev, abort.get_abort_event()};
31  for(;;) {
32  SetLastError(0);
33  const DWORD status = MsgWaitForMultipleObjects(2, handles, FALSE, INFINITE, QS_ALLINPUT);
34  switch(status) {
35  case WAIT_TIMEOUT:
36  PFC_ASSERT(!"How did we get here?");
37  uBugCheck();
38  case WAIT_OBJECT_0:
39  return;
40  case WAIT_OBJECT_0 + 1:
41  throw exception_aborted();
42  case WAIT_OBJECT_0 + 2:
44  break;
45  case WAIT_FAILED:
46  WIN32_OP_FAIL();
47  default:
48  uBugCheck();
49  }
50  }
51  }
52 
53  static t_size MultiWaitAbortable_MsgLoop(const HANDLE * ev, t_size evCount, abort_callback & abort) {
54  pfc::array_t<HANDLE> handles; handles.set_size(evCount + 1);
55  handles[0] = abort.get_abort_event();
56  pfc::memcpy_t(handles.get_ptr() + 1, ev, evCount);
57  for(;;) {
58  SetLastError(0);
59  const DWORD status = MsgWaitForMultipleObjects(handles.get_count(), handles.get_ptr(), FALSE, INFINITE, QS_ALLINPUT);
60  switch(status) {
61  case WAIT_TIMEOUT:
62  PFC_ASSERT(!"How did we get here?");
63  uBugCheck();
64  case WAIT_OBJECT_0:
65  throw exception_aborted();
66  case WAIT_FAILED:
67  WIN32_OP_FAIL();
68  default:
69  {
70  t_size index = (t_size)(status - (WAIT_OBJECT_0 + 1));
71  if (index == evCount) {
73  } else if (index < evCount) {
74  return index;
75  } else {
76  uBugCheck();
77  }
78  }
79  }
80  }
81  }
82 
83  static void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout /*must not be INFINITE*/) {
84  PFC_ASSERT( timeout != INFINITE );
85  const DWORD entry = GetTickCount();
86  const HANDLE handles[1] = {abort.get_abort_event()};
87  for(;;) {
88  const DWORD done = GetTickCount() - entry;
89  if (done >= timeout) return;
90  SetLastError(0);
91  const DWORD status = MsgWaitForMultipleObjects(1, handles, FALSE, timeout - done, QS_ALLINPUT);
92  switch(status) {
93  case WAIT_TIMEOUT:
94  return;
95  case WAIT_OBJECT_0:
96  throw exception_aborted();
97  case WAIT_OBJECT_0 + 1:
99  default:
100  throw exception_win32(GetLastError());
101  }
102  }
103  }
104 
105  static bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout /*must not be INFINITE*/) {
106  PFC_ASSERT( timeout != INFINITE );
107  const DWORD entry = GetTickCount();
108  const HANDLE handles[2] = {ev, abort.get_abort_event()};
109  for(;;) {
110  const DWORD done = GetTickCount() - entry;
111  if (done >= timeout) return false;
112  SetLastError(0);
113  const DWORD status = MsgWaitForMultipleObjects(2, handles, FALSE, timeout - done, QS_ALLINPUT);
114  switch(status) {
115  case WAIT_TIMEOUT:
116  return false;
117  case WAIT_OBJECT_0:
118  return true;
119  case WAIT_OBJECT_0 + 1:
120  throw exception_aborted();
121  case WAIT_OBJECT_0 + 2:
123  break;
124  case WAIT_FAILED:
125  WIN32_OP_FAIL();
126  default:
127  uBugCheck();
128  }
129  }
130  }
131 
132  template<typename TWhat>
133  class CObjectQueue {
134  public:
135  CObjectQueue() { m_event.create(true,false); }
136 
137  template<typename TSource> void Add(const TSource & source) {
138  insync(m_sync);
139  m_content.add_item(source);
140  if (m_content.get_count() == 1) m_event.set_state(true);
141  }
142  template<typename TDestination> void Get(TDestination & out, abort_callback & abort) {
143  WaitAbortable(m_event.get(), abort);
144  _Get(out);
145  }
146 
147  template<typename TDestination> void Get_MsgLoop(TDestination & out, abort_callback & abort) {
149  _Get(out);
150  }
151 
152  private:
153  template<typename TDestination> void _Get(TDestination & out) {
154  insync(m_sync);
156  FB2K_DYNAMIC_ASSERT( iter.is_valid() );
157  out = *iter;
158  m_content.remove(iter);
159  if (m_content.get_count() == 0) m_event.set_state(false);
160  }
164  };
165 
166 
167  template<typename TBase, bool processMsgs = false>
169  private:
170  enum status {
176  };
177  protected:
178  class command {
179  protected:
181  virtual void executeImpl(TBase &) {}
182  virtual ~command() {}
183  public:
184  void execute(TBase & obj) {
185  try {
186  executeImpl(obj);
187  m_status = success;
188  } catch(exception_aborted const & e) {
189  m_status = fail_abort; m_statusMsg = e.what();
190  } catch(exception_io_data const & e) {
191  m_status = fail_io_data; m_statusMsg = e.what();
192  } catch(exception_io const & e) {
193  m_status = fail_io; m_statusMsg = e.what();
194  } catch(std::exception const & e) {
195  m_status = fail; m_statusMsg = e.what();
196  }
197  SetEvent(m_completionEvent);
198  }
199  void rethrow() const {
200  switch(m_status) {
201  case fail:
203  case fail_io:
204  throw exception_io(m_statusMsg);
205  case fail_io_data:
206  throw exception_io_data(m_statusMsg);
207  case fail_abort:
208  throw exception_aborted();
209  case success:
210  break;
211  default:
212  uBugCheck();
213  }
214  }
219  };
220 
222 
224  m_completionEvent.create(true,false);
225  this->StartThread();
226  //start();
227  }
228 
230  m_threadAbort.abort();
231  this->WaitTillThreadDone();
232  }
233 
234  void invokeCommand(command_ptr cmd, abort_callback & abort) {
235  abort.check();
237  pfc::vartoggle_t<abort_callback*> abortToggle(cmd->m_abort, &abort);
238  pfc::vartoggle_t<HANDLE> eventToggle(cmd->m_completionEvent, m_completionEvent.get() );
239  m_commands.Add(cmd);
241  //WaitAbortable(m_completionEvent.get(), abort);
242  cmd->rethrow();
243  }
244 
245  private:
246  void ThreadProc() {
247  TRACK_CALL_TEXT("CSingleThreadWrapper entry");
248  try {
249  TBase instance;
250  for(;;) {
251  command_ptr cmd;
252  if (processMsgs) m_commands.Get_MsgLoop(cmd, m_threadAbort);
253  else m_commands.Get(cmd, m_threadAbort);
254  cmd->execute(instance);
255  }
256  } catch(...) {}
257  if (processMsgs) ProcessPendingMessages();
258  }
261  abort_callback_impl m_threadAbort;
262  };
263 }
CObjectQueue< command_ptr > m_commands
Definition: ThreadUtils.h:260
const t_item * get_ptr() const
Definition: array.h:213
PFC_NORETURN PFC_NOINLINE void WIN32_OP_FAIL()
Definition: win32_misc.cpp:52
void add_item(const t_source &p_source)
static void SleepAbortable_MsgLoop(abort_callback &abort, DWORD timeout)
Definition: ThreadUtils.h:83
void Get(TDestination &out, abort_callback &abort)
Definition: ThreadUtils.h:142
void Add(const TSource &source)
Definition: ThreadUtils.h:137
void WaitTillThreadDone()
Definition: fb2k_threads.h:18
bool is_valid() const
Definition: iterators.h:24
abort_callback_impl m_threadAbort
Definition: ThreadUtils.h:261
pfc::chain_list_v2_t< TWhat > m_content
Definition: ThreadUtils.h:163
typedef HANDLE(WINAPI *pPowerCreateRequest_t)(__in void *Context)
pfc::rcptr_t< command > command_ptr
Definition: ThreadUtils.h:221
void remove(const_iterator const &p_iter)
Definition: chain_list_v2.h:73
t_size get_count() const
Definition: chain_list_v2.h:61
void invokeCommand(command_ptr cmd, abort_callback &abort)
Definition: ThreadUtils.h:234
size_t t_size
Definition: int_types.h:48
void set_size(t_size p_size)
Definition: array.h:104
void _Get(TDestination &out)
Definition: ThreadUtils.h:153
static bool WaitAbortable(HANDLE ev, abort_callback &abort, DWORD timeout=INFINITE)
Definition: ThreadUtils.h:2
static t_size MultiWaitAbortable_MsgLoop(const HANDLE *ev, t_size evCount, abort_callback &abort)
Definition: ThreadUtils.h:53
t_size get_count() const
Definition: array.h:131
critical_section m_sync
Definition: ThreadUtils.h:162
static void WaitAbortable_MsgLoop(HANDLE ev, abort_callback &abort)
Definition: ThreadUtils.h:29
std::exception exception
Definition: primitives.h:193
void memcpy_t(t_dst *p_dst, const t_src *p_src, t_size p_count)
Definition: primitives.h:611
HANDLE get() const
Definition: win-objects.h:128
IMPORTANT: all classes derived from CVerySimpleThread must call WaitTillThreadDone() in their destruc...
Definition: fb2k_threads.h:6
void create(bool p_manualreset, bool p_initialstate)
PFC_NORETURN void SHARED_EXPORT uBugCheck()
static void ProcessPendingMessages()
Definition: ThreadUtils.h:21
bool wait_for(double p_timeout_seconds)
Returns true when signaled, false on timeout.
Definition: win-objects.h:136
void Get_MsgLoop(TDestination &out, abort_callback &abort)
Definition: ThreadUtils.h:147
void set_state(bool p_state)