foobar2000 SDK  2015-08-03
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:
180  command() : m_status(success), m_abort(), m_completionEvent() {}
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:
202  throw pfc::exception(m_statusMsg);
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();
236  m_completionEvent.set_state(false);
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);
240  m_completionEvent.wait_for(-1);
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
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds)
Definition: pp-winapi.h:20
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
Decoder Validator v1 readme Usage Select a single file handled by the decoder you want to select Utils Decoder Utils Tag Writer Validator or Utils Fuzzer from the context menu with randomly generated info In case of success(found problems with relevant tag writer implementations)
static void fail(completion_notify_ptr p_notify)
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:131
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
void Get_MsgLoop(TDestination &out, abort_callback &abort)
Definition: ThreadUtils.h:147
void set_state(bool p_state)