threading.cpp
Go to the documentation of this file.
1 
2 // Copyright (c) 2003-2021 Xsens Technologies B.V. or subsidiaries worldwide.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions, and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions, and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the names of the copyright holders nor the names of their contributors
16 // may be used to endorse or promote products derived from this software without
17 // specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24 // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
26 // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.THE LAWS OF THE NETHERLANDS
28 // SHALL BE EXCLUSIVELY APPLICABLE AND ANY DISPUTES SHALL BE FINALLY SETTLED UNDER THE RULES
29 // OF ARBITRATION OF THE INTERNATIONAL CHAMBER OF COMMERCE IN THE HAGUE BY ONE OR MORE
30 // ARBITRATORS APPOINTED IN ACCORDANCE WITH SAID RULES.
31 //
32 
33 
34 // Copyright (c) 2003-2021 Xsens Technologies B.V. or subsidiaries worldwide.
35 // All rights reserved.
36 //
37 // Redistribution and use in source and binary forms, with or without modification,
38 // are permitted provided that the following conditions are met:
39 //
40 // 1. Redistributions of source code must retain the above copyright notice,
41 // this list of conditions, and the following disclaimer.
42 //
43 // 2. Redistributions in binary form must reproduce the above copyright notice,
44 // this list of conditions, and the following disclaimer in the documentation
45 // and/or other materials provided with the distribution.
46 //
47 // 3. Neither the names of the copyright holders nor the names of their contributors
48 // may be used to endorse or promote products derived from this software without
49 // specific prior written permission.
50 //
51 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
52 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
53 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
54 // THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 // SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
56 // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
58 // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.THE LAWS OF THE NETHERLANDS
60 // SHALL BE EXCLUSIVELY APPLICABLE AND ANY DISPUTES SHALL BE FINALLY SETTLED UNDER THE RULES
61 // OF ARBITRATION OF THE INTERNATIONAL CHAMBER OF COMMERCE IN THE HAGUE BY ONE OR MORE
62 // ARBITRATORS APPOINTED IN ACCORDANCE WITH SAID RULES.
63 //
64 
65 #include "threading.h"
66 #include <signal.h>
67 #include <time.h>
68 #include <xstypes/xstime.h>
69 
70 #ifdef __GNUC__
71  #include <sys/time.h>
72  #include <signal.h>
73  #include <fcntl.h>
74  #include <sys/stat.h>
75  #define _strdup strdup
76 #endif
77 
78 namespace xsens
79 {
80 #ifdef __GNUC__
81 pthread_t xsStartThread(void* (func)(void*), void* param, void* pid)
82 {
83  return ::xsStartThread(func, param, pid);
84 }
85 #endif
86 
90  : m_thread(XSENS_INVALID_THREAD)
91  , m_priority(XS_THREAD_PRIORITY_NORMAL)
92  , m_stop(false)
93  , m_yieldOnZeroSleep(true)
94 #ifdef _WIN32
95  , m_stopHandle(::CreateEvent(NULL, TRUE, FALSE, NULL))
96  , m_running(::CreateEvent(NULL, TRUE, FALSE, NULL))
97  , m_threadId(0)
98 #else
99  , m_running(false)
100 #endif
101  , m_name(NULL)
102 {
103 #ifndef _WIN32
104  pthread_attr_init(&m_attr);
105 #endif
106 }
107 
111 {
112  stopThread();
113 
114  if (m_name)
115  {
116  free(m_name);
117  m_name = NULL;
118  }
119 
120 #ifdef _WIN32
121  ::CloseHandle(m_running);
122  ::CloseHandle(m_stopHandle);
123 #else
124  pthread_attr_destroy(&m_attr);
125 #endif
126 }
127 
128 #ifdef _WIN32
129 
130 void StandardThread::terminateThread()
131 {
133  ::TerminateThread(m_thread, DWORD(-1));
135 }
136 #endif
137 
140 bool StandardThread::isAlive(void) volatile const noexcept
141 {
142  if (m_thread == XSENS_INVALID_THREAD)
143  return false;
144 
145 #ifdef _WIN32
146  DWORD exitCode;
147  if (::GetExitCodeThread(m_thread, &exitCode))
148  {
149  if (exitCode == STILL_ACTIVE)
150  return true;
151  }
152  return false;
153 #else
154  return (pthread_kill(m_thread, 0) == 0);
155 #endif
156 }
157 
160 bool StandardThread::isRunning(void) volatile const noexcept
161 {
162  if (!isAlive())
163  return false;
164 #ifdef _WIN32
165  switch (::WaitForSingleObject(m_running, 0))
166  {
167  case WAIT_ABANDONED:
168  case WAIT_TIMEOUT:
169  return false;
170  case WAIT_OBJECT_0:
171  return true;
172  default:
173  return false;
174  }
175 #else
176  return m_running;
177 #endif
178 }
179 
182 bool StandardThread::isTerminating(void) volatile const noexcept
183 {
184  return m_stop;
185 }
186 
192 {
193  m_priority = pri;
194 
195  if (!isAlive())
196  return false;
197 
198 #ifdef _WIN32
199  ::SetThreadPriority(m_thread, (int) pri);
200 #else
201 #ifdef _POSIX_PRIORITY_SCHEDULING
202  int32_t rv;
203  int32_t policy;
204  struct sched_param param;
205 
206  if (!isAlive())
207  return false;
208 
209  rv = pthread_getschedparam(m_thread, &policy, &param);
210  switch (rv)
211  {
212  case ESRCH:
213  /* The value specified by thread does not refer to an existing thread. */
214  return false;
215  default:
216  break;
217  }
218 
219  switch (pri)
220  {
222  param.sched_priority = sched_get_priority_max(policy);
223  break;
224 
226  param.sched_priority = sched_get_priority_max(policy);
227  // Fallthrough.
228  default:
229  /* we need to map the priority to the values used on this system */
230  int32_t min_prio = sched_get_priority_min(policy);
231  int32_t max_prio = sched_get_priority_max(policy);
232 
233  if (min_prio < 0 || max_prio < 0)
234  return false;
235 
236  /* divide range up in amount of priority levels */
237  float priostep = ((float)(max_prio - min_prio)) / ((int32_t)XS_THREAD_PRIORITY_HIGHEST + 1);
238 
239  param.sched_priority = (int32_t)(min_prio + (pri * priostep));
240  break;
241  }
242 
243  rv = pthread_setschedparam(m_thread, policy, &param);
244  switch (rv)
245  {
246  case ESRCH:
247  /* The value specified by thread does not refer to an existing thread. */
248  case EINVAL:
249  /* The value specified by policy or one of the scheduling parameters
250  associated with the scheduling policy policy is invalid.
251  */
252  case ENOTSUP:
253  /* An attempt was made to set the policy or scheduling parameters to an
254  unsupported value.
255  An attempt was made to dynamically change the scheduling policy to
256  SCHED_SPORADIC, and the implementation does not support this change.
257  */
258  case EPERM:
259  /* The caller does not have the appropriate permission to set either the
260  scheduling parameters or the scheduling policy of the specified thread.
261  The implementation does not allow the application to modify one of the
262  parameters to the value specified.
263  */
264  return false;
265  default:
266  break;
267  }
268 
269  return true;
270 #else
271  return true;
272 #endif
273 #endif
274  return true;
275 }
276 
281 bool StandardThread::startThread(const char* name)
282 {
283  if (isAlive())
284  return false;
285 
286  if (m_name)
287  free(m_name);
288  if (name)
289  m_name = _strdup(name);
290  else
291  m_name = NULL;
292 
293 #ifdef _WIN32
294  m_stop = false;
295  ::ResetEvent(m_stopHandle);
296  ::SetEvent(m_running);
297  m_thread = xsStartThread(&threadInit, this, &m_threadId);
299  {
300  ::ResetEvent(m_running);
301  return false;
302  }
303 #else
304  m_stop = false;
305  m_running = true;
306  if (pthread_create(&m_thread, &m_attr, threadInit, this))
307  {
308  /* something went wrong */
310  return false;
311  }
312 #endif
314 
315  return true;
316 }
317 
321 {
322 #ifdef _WIN32
323  m_stop = true;
324  ::SetEvent(m_stopHandle);
325  ::SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
326 #else
328  m_stop = true;
329 #endif
330 }
331 
334 void StandardThread::stopThread(void) noexcept
335 {
336 #ifdef _WIN32
337  // prevent multiple threads from doing this at the same time on windows, pthreads deals with this in its own special way
338  xsens::Lock locky(&m_mux, false);
339  if (m_threadId == xsGetCurrentThreadId())
340  locky.tryLock();
341  else
342  locky.lock();
343 #endif
344 
345  if (!isAlive())
346  return;
347 
348  signalStopThread();
349 #ifdef _WIN32
350  // don't wait for my thread to end myself
351  if (m_threadId == xsGetCurrentThreadId())
352  return;
353 
354  // in debug mode we ALWAYS want to know if there's some kind of deadlock occurring
355  //#if XSENS_THREAD_KILL_TIMEOUT_MS > 0 && !defined(XSENS_DEBUG)
356  // XsTimeStamp endOfWait = XsTimeStamp::now() + XSENS_THREAD_KILL_TIMEOUT_MS;
357  // while(isAlive() && (XsTimeStamp::now() < endOfWait))
358  // xsYield();
359  //#else
360 
361  while (isAlive())
362  xsYield();
363  //#endif
364  if (m_thread != XSENS_INVALID_THREAD && ::CloseHandle(m_thread) == 0)
365  {
366  DWORD lastErr = GetLastError();
367  (void)lastErr;
368  return;
369  }
370 #else
371  // don't wait for my thread to end myself
372  if (pthread_equal(m_thread, xsGetCurrentThreadId()))
373  return;
374 
375  // in debug mode we ALWAYS want to know if there's some kind of deadlock occurring
376  //#if XSENS_THREAD_KILL_TIMEOUT_MS > 0 && !defined(XSENS_DEBUG)
377  // XsTimeStamp endOfWait = XsTimeStamp::now() + XSENS_THREAD_KILL_TIMEOUT_MS;
378  // while(isAlive() && (XsTimeStamp::now() < endOfWait))
379  // xsYield();
380 
381  // if (isAlive()) {
382  // if (pthread_kill(m_thread, 9))
383  // return;
384  // }
385  //#else
386  while (isAlive())
387  xsYield();
388  //#endif
389  if (pthread_join(m_thread, NULL))
390  {
391  switch (errno)
392  {
393  case EINVAL:
394  /* no joinable thread found */
395  case ESRCH:
396  /* no thread fits thread id */
397  case EDEADLK:
398  /* deadlock or trying to join self */
399  default:
400  break;
401  }
402  }
403 
404  m_running = false;
405 #endif
406  m_thread = XSENS_INVALID_THREAD;
407 }
408 
410 {
411  StandardThread* thread = reinterpret_cast<StandardThread*>(obj);
412  if (thread->m_name)
413  xsNameThisThread(thread->m_name);
414 
415  thread->threadMain();
416  return 0;
417 }
418 
419 #ifndef _WIN32
420 
422 {
423  ((StandardThread*)obj)->exitFunction();
424 }
425 #endif
426 
430 {
431  initFunction();
432  do
433  {
434  int32_t rv = innerFunction();
435  if (rv > 0)
436  {
437  int64_t sleepStart = XsTimeStamp::nowMs();
438  while (!m_stop)
439  {
440  // sleep max 100ms at a time so we can terminate the thread quickly if necessary
441  int64_t timePassed = XsTimeStamp::nowMs() - sleepStart;
442  int32_t remaining = rv - (int32_t) timePassed;
443  if (remaining > 100)
444  XsTime::msleep(100);
445  else if (remaining <= 0)
446  break;
447  else
448  XsTime::msleep((uint32_t) remaining);
449  }
450  }
451  else if (m_yieldOnZeroSleep && !m_stop)
452  xsYield();
453  } while (!m_stop);
454  exitFunction();
455 }
456 
460 
462  : m_thread(XSENS_INVALID_THREAD)
463 #ifdef _WIN32
464  , m_stop(::CreateEvent(NULL, TRUE, FALSE, NULL))
465  , m_running(::CreateEvent(NULL, TRUE, FALSE, NULL))
466  , m_reset(::CreateEvent(NULL, TRUE, FALSE, NULL))
467 #else
468  , m_running(false)
469  , m_reset(false)
470  , m_stop(false)
471 #endif
472  , m_timeout(10000)
473  , m_func(func)
474  , m_param(param)
475  , m_name(NULL)
476  , m_threadId(0)
477 {
478 #ifndef _WIN32
479  pthread_attr_init(&m_attr);
480 #endif
481 }
482 
484 {
485  stopTimer();
486 
487  if (m_name)
488  {
489  free(m_name);
490  m_name = NULL;
491  }
492 
493 #ifdef _WIN32
494  ::CloseHandle(m_reset);
495  ::CloseHandle(m_running);
496  ::CloseHandle(m_stop);
497 #else
498  pthread_attr_destroy(&m_attr);
499 #endif
500 }
501 
502 bool WatchDogThread::isAlive(void) volatile const noexcept
503 {
504 #ifdef _WIN32
505  DWORD exitCode;
506  if (::GetExitCodeThread(m_thread, &exitCode))
507  return (exitCode == STILL_ACTIVE);
508 #else
509  if (m_thread == XSENS_INVALID_THREAD)
510  return false;
511 
512  return (pthread_kill(m_thread, 0) == 0);
513 #endif
514  return false;
515 }
516 
517 bool WatchDogThread::isRunning(void) volatile const noexcept
518 {
519  if (!isAlive())
520  return false;
521 #ifdef _WIN32
522  switch (::WaitForSingleObject(m_running, 0))
523  {
524  case WAIT_ABANDONED:
525  case WAIT_TIMEOUT:
526  return false;
527  case WAIT_OBJECT_0:
528  switch (::WaitForSingleObject(m_stop, 0))
529  {
530  case WAIT_ABANDONED:
531  case WAIT_TIMEOUT:
532  return true;
533  case WAIT_OBJECT_0:
534  return false;
535  default:
536  return false;
537  }
538  default:
539  return false;
540  }
541 #else
542  return m_running;
543 #endif
544 }
545 
551 bool WatchDogThread::startTimer(uint32_t timeout, const char* name)
552 {
553  if (isAlive())
554  return false;
555 
556  if (timeout != 0)
557  m_timeout = timeout;
558 
559  if (m_name)
560  free(m_name);
561  if (name)
562  m_name = _strdup(name);
563  else
564  m_name = NULL;
565 
566 #ifdef _WIN32
567  ::ResetEvent(m_stop);
568  ::SetEvent(m_running);
569  ::ResetEvent(m_reset);
572  {
573  ::ResetEvent(m_running);
574  return false;
575  }
576 
577 #else
578  m_running = true;
579  m_reset = false;
580  m_stop = false;
581 
582  if (pthread_create(&m_thread, &m_attr, threadInit, this) != 0)
583  return false;
584 #endif
585  return true;
586 }
587 
591 bool WatchDogThread::stopTimer(void) noexcept
592 {
593  if (!isAlive())
594  return true;
595 
596 #ifdef _WIN32
597  ::SetEvent(m_stop);
598  ::SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
599 
600  while (isAlive())
601  xsYield();
602  if (::CloseHandle(m_thread) == 0)
603  {
604  DWORD lastErr = GetLastError();
605  (void)lastErr;
606  return false;
607  }
608 #else
609  int rv;
610  int32_t policy;
611  struct sched_param param;
612 
613  m_stop = true;
614  rv = pthread_getschedparam(m_thread, &policy, &param);
615  if (rv)
616  {
617  switch (errno)
618  {
619  case ESRCH:
620  return false;
621  default:
622  break;
623  }
624  }
625  param.sched_priority = sched_get_priority_max(policy);
626 
627  rv = pthread_setschedparam(m_thread, policy, &param);
628  if (rv)
629  {
630  switch (errno)
631  {
632  case ESRCH:
633  case EINVAL:
634  case ENOTSUP:
635  case EPERM:
636  return false;
637  default:
638  break;
639  }
640  }
641 
642  rv = pthread_join(m_thread, NULL);
643  if (rv)
644  {
645  switch (errno)
646  {
647  case EINVAL:
648  case ESRCH:
649  case EDEADLK:
650  default:
651  break;
652  }
653  }
654  m_running = false;
655  m_thread = XSENS_INVALID_THREAD;
656 #endif
657  m_thread = XSENS_INVALID_THREAD;
658  return true;
659 }
660 
662 {
663  WatchDogThread* thread = reinterpret_cast<WatchDogThread*>(obj);
664  if (thread->m_name)
665  xsNameThisThread(thread->m_name);
666 
667  thread->threadMain();
668  return 0;
669 }
670 
672 {
673  XsTimeStamp toTime((int64_t)(XsTimeStamp::now().msTime() + m_timeout));
674 
675 #ifdef _WIN32
676  HANDLE hlist[2];
677 #endif
678  bool go = true;
679  while (go)
680  {
681 #ifdef _WIN32
682  uint32_t timeout = (uint32_t)(toTime - XsTimeStamp::now()).msTime();
683  if (timeout > m_timeout)
684  break;
685  hlist[0] = m_reset;
686  hlist[1] = m_stop;
687 
688  switch (::WaitForMultipleObjects(2, hlist, FALSE, timeout))
689  {
690  case WAIT_OBJECT_0: // m_reset
691  // received an update for the timer
692  toTime = XsTimeStamp::now() + XsTimeStamp((int) m_timeout);
693  ::ResetEvent(m_reset);
694  continue;
695 
696  case WAIT_OBJECT_0+1: // m_stop
697  case WAIT_ABANDONED:
698  default:
699  go = false;
700  break;
701 
702  case WAIT_TIMEOUT:
703  break;
704  }
705 #else
706  Lock lock(&m_mutex, true);
707  lock.unlock();
708 
709  uint32_t timeout;
710 
711  while (go)
712  {
713  timeout = static_cast<uint32_t>((toTime - XsTimeStamp::now()).msTime());
714  if (timeout > m_timeout)
715  break;
716 
717  lock.lock();
718  if (m_reset)
719  {
720  toTime = XsTimeStamp((XsTimeStamp::now().msTime() + m_timeout));
721  m_reset = false;
722  }
723  lock.unlock();
724 
725  if (m_stop)
726  go = false;
727  }
728 #endif
729  break;
730  }
731  if (go)
732  m_func(m_param);
733 }
734 
740 {
741  if (!isRunning())
742  return false;
743 
744 #ifdef _WIN32
745  if (timeout != 0)
746  m_timeout = timeout;
747  ::SetEvent(m_reset);
748 #else
749  Lock lock(&m_mutex);
750 
751  m_timeout = timeout;
752  m_reset = true;
753 #endif
754  return true;
755 }
756 
757 #ifdef _WIN32
758 Semaphore::Semaphore(int32_t initVal, uint32_t nofOtherHandles, HANDLE* otherHandles)
759 {
760  m_nofHandles = nofOtherHandles + 1;
761  m_handleList = new HANDLE[m_nofHandles];
762  for (uint32_t i = 0; i < m_nofHandles - 1; i++)
763  m_handleList[i] = otherHandles[i];
764  m_handleList[m_nofHandles - 1] = CreateSemaphore(NULL, initVal, 0x7fffffff, NULL);
765 }
766 
768 {
769  post();
770  CloseHandle(m_handleList[m_nofHandles - 1]);
771  delete[] m_handleList;
772 }
773 
774 bool Semaphore::wait1()
775 {
776  return wait1(static_cast<uint32_t>(-1));
777 }
778 
779 bool Semaphore::wait1(uint32_t timeout)
780 {
781  for (;;) // loop + timeout for debugging only
782  {
783  DWORD r = WaitForMultipleObjects(m_nofHandles, m_handleList, FALSE, timeout);
784  if (r == WAIT_TIMEOUT)
785  return false;
786  if (r < WAIT_OBJECT_0 + m_nofHandles)
787  return r - WAIT_OBJECT_0 == m_nofHandles - 1;
788  if (r != WAIT_TIMEOUT)
789  return false;
790  xsYield(); // prevent race condition
791  }
792 }
793 
794 int32_t Semaphore::post(int32_t increment) noexcept
795 {
796  LONG prev;
797  ReleaseSemaphore(m_handleList[m_nofHandles - 1], increment, &prev);
798  return (int32_t) prev;
799 }
800 
801 #else // _WIN32
802 
804  m_semname(nullptr),
805  m_handle(SEM_FAILED)
806 {
807 #if defined(SEM_VALUE_MAX) && INT32_MAX > SEM_VALUE_MAX
808  if (initVal > SEM_VALUE_MAX)
809  initVal = SEM_VALUE_MAX;
810 #endif
811 
812  uint64_t id = (uint64_t)this;
813  char semname[20];
814 
815  while (true)
816  {
817  sprintf(semname, "%" PRINTF_INT64_MODIFIER "x", id);
818  m_semname = strdup(semname);
819  m_handle = sem_open(semname, O_EXCL | O_CREAT, S_IRWXU, initVal);
820  if (m_handle != SEM_FAILED)
821  break;
822 
823  if (errno != EEXIST)
824  {
825  perror("opening semaphore");
826  exit(-1);
827  }
828 
829  id++;
830  free(m_semname);
831  }
832 }
833 
835 {
836  post();
837  sem_unlink(m_semname);
838  free(m_semname);
839 }
840 
842 {
843  return wait1(static_cast<uint32_t>(-1));
844 }
845 
847 {
848  if (ms == UINT32_MAX)
849  return sem_wait(m_handle);
850 
851 #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
852  timespec ts;
853 
854  clock_gettime(CLOCK_REALTIME, &ts);
855 
856  int64_t s = ms / 1000;
857  ts.tv_sec += s;
858 
859  ms -= s * 1000;
860  int64_t ns = ts.tv_nsec + (ms * 1000000);
861 
862  ts.tv_sec += ns / 1000000000L;
863  ts.tv_nsec = ns % 1000000000L;
864 
865  return sem_timedwait(m_handle, &ts) == 0;
866 #else
867  XsTimeStamp end = XsTimeStamp::now() + XsTimeStamp(int64_t(ms));
868 
869  while (XsTimeStamp::now() < end)
870  {
871  if (sem_trywait(m_handle) == 0)
872  return true;
873  else
874  xsYield();
875  }
876 
877  return false;
878 #endif
879 }
880 
881 #ifndef __APPLE__
882 int32_t Semaphore::post(int32_t increment) throw()
883 {
884  int prev;
885  sem_getvalue(m_handle, &prev);
886  for (int i = 0; i < increment; i++)
887  sem_post(m_handle);
888  return (int32_t)prev;
889 }
890 #else
891 int32_t Semaphore::post(int32_t increment) throw()
892 {
893  int prev = 0;
894  for (int i = 0; i < increment; i++)
895  sem_post(m_handle);
896  return (int32_t)prev;
897 }
898 #endif
899 #endif // _WIN32
900 
901 #ifdef __APPLE__
902 
909 #ifndef CLOCK_REALTIME
910  #define CLOCK_REALTIME 0
911 #endif
912 static int clock_gettime(int clk_id, struct timespec* tp)
913 {
914  (void)clk_id;
915  struct timeval now;
916 
917  int rv = gettimeofday(&now, NULL);
918  if (rv != 0)
919  return rv;
920 
921  tp->tv_sec = now.tv_sec;
922  tp->tv_nsec = now.tv_usec * 1000;
923 
924  return 0;
925 }
926 #endif
927 
930 {
931 #ifdef _WIN32
932  InitializeConditionVariable(&m_cond);
933 #else
934  pthread_condattr_init(&m_condattr);
935 #if !defined(__APPLE__) && (defined(_POSIX_CLOCK_SELECTION) || defined(_SC_CLOCK_SELECTION)) && !defined(ANDROID)
936  m_clockId = CLOCK_MONOTONIC;
937  if (pthread_condattr_setclock(&m_condattr, m_clockId) != 0)
938  pthread_condattr_getclock(&m_condattr, &m_clockId);
939 #else
940  /* we'll fall back to the wallclock, but we may be influenced by
941  time keeping software (ntp, date), which doesn't happen with
942  the monotonic clock
943  */
944  m_clockId = CLOCK_REALTIME;
945 #endif
946  pthread_cond_init(&m_cond, &m_condattr);
947 #endif
948 }
949 
952 {
953  try
954  {
955  broadcast();
956 #ifndef _WIN32
957  pthread_cond_destroy(&m_cond);
958  pthread_condattr_destroy(&m_condattr);
959 #endif
960  }
961  catch (...)
962  {
963  }
964 }
965 
968 {
969 #ifdef _WIN32
970  WakeConditionVariable(&m_cond);
971 #else
972  pthread_cond_signal(&m_cond);
973 #endif
974 }
975 
978 {
979 #ifdef _WIN32
980  WakeAllConditionVariable(&m_cond);
981 #else
982  pthread_cond_broadcast(&m_cond);
983 #endif
984 }
985 
995 {
996 #ifdef _WIN32
997  return SleepConditionVariableCS(&m_cond, &m_mutex.m_mutex, INFINITE) != 0;
998 #else
999  return pthread_cond_wait(&m_cond, &m_mutex.m_mutex) == 0;
1000 #endif
1001 }
1002 
1014 {
1015 #ifdef _WIN32
1016  return SleepConditionVariableCS(&m_cond, &m_mutex.m_mutex, timeout) != 0;
1017 #else
1018  static const int64_t NANOS_PER_MILLI = 1000000;
1019  static const int64_t NANOS_PER_ONE = NANOS_PER_MILLI * 1000;
1020 
1021  struct timespec time;
1022  int64_t nsec;
1023 
1024  clock_gettime(m_clockId, &time);
1025 
1026  nsec = time.tv_nsec + timeout * NANOS_PER_MILLI;
1027  time.tv_nsec = nsec % NANOS_PER_ONE;
1028  time.tv_sec += nsec / NANOS_PER_ONE;
1029 
1030  return pthread_cond_timedwait(&m_cond, &m_mutex.m_mutex, &time) == 0;
1031 #endif
1032 }
1033 
1034 #if defined(_WIN32)
1035 
1037  : m_waiterCount(0)
1038  , m_terminating(false)
1039 {
1040  m_event = ::CreateEventA(NULL, TRUE, FALSE, NULL);
1041 }
1042 
1045 {
1046  try
1047  {
1048  terminate();
1049  }
1050  catch (...)
1051  {}
1052  assert(m_waiterCount == 0);
1053  ::CloseHandle(m_event);
1054  m_event = INVALID_HANDLE_VALUE;
1055 }
1056 
1060 bool WaitEvent::wait()
1061 {
1062  if (m_terminating)
1063  return false;
1064 
1065  ++m_waiterCount;
1066 
1067  switch (::WaitForSingleObject(m_event, INFINITE))
1068  {
1069  case WAIT_ABANDONED:
1070  case WAIT_TIMEOUT:
1071  --m_waiterCount;
1072  return false;
1073  case WAIT_OBJECT_0:
1074  --m_waiterCount;
1075  return !m_terminating;
1076  default:
1077  --m_waiterCount;
1078  return false;
1079  }
1080 }
1081 
1085 void WaitEvent::set()
1086 {
1087  ::SetEvent(m_event);
1088 }
1089 
1094 void WaitEvent::reset()
1095 {
1096  if (!m_terminating)
1097  ::ResetEvent(m_event);
1098 }
1099 #else
1101  : m_waiterCount(0)
1102  , m_terminating(false)
1103 {
1104  pthread_mutex_init(&m_mutex, 0);
1105  pthread_cond_init(&m_cond, 0);
1106  m_triggered = false;
1107 }
1108 
1110 {
1111  terminate();
1112  pthread_cond_destroy(&m_cond);
1113  pthread_mutex_destroy(&m_mutex);
1114 }
1115 
1120 {
1121  if (m_terminating)
1122  return false;
1123 
1124  ++m_waiterCount;
1125  pthread_mutex_lock(&m_mutex);
1126  while (!m_triggered && !m_terminating)
1127  pthread_cond_wait(&m_cond, &m_mutex);
1128  pthread_mutex_unlock(&m_mutex);
1129  --m_waiterCount;
1130  return !m_terminating;
1131 }
1132 
1137 {
1138  pthread_mutex_lock(&m_mutex);
1139  m_triggered = true;
1140  pthread_cond_signal(&m_cond);
1141  pthread_mutex_unlock(&m_mutex);
1142 }
1143 
1149 {
1150  if (!m_terminating)
1151  {
1152  pthread_mutex_lock(&m_mutex);
1153  m_triggered = false;
1154  pthread_mutex_unlock(&m_mutex);
1155  }
1156 }
1157 
1158 #endif
1159 
1163 {
1164  m_terminating = true;
1165  set();
1166 
1167  while (m_waiterCount > 0)
1168  XsTime_msleep(2);
1169 }
1170 
1171 } // namespace xsens
xsens::WatchDogThread::m_param
void * m_param
Definition: threading.h:185
xsens::Semaphore::Semaphore
Semaphore(Semaphore const &)=delete
xsens::StandardThread::~StandardThread
virtual ~StandardThread()
Definition: threading.cpp:110
xsens::WaitEvent::m_cond
pthread_cond_t m_cond
Definition: xsens_mutex.h:1860
xsens::WatchDogThread::m_stop
bool m_stop
Definition: threading.h:181
xsens::WaitCondition::m_cond
pthread_cond_t m_cond
Definition: xsens_mutex.h:1825
xsens::WaitEvent::wait
bool wait()
Wait for the event to be set or object termination.
Definition: threading.cpp:1119
xsens::StandardThread::threadInit
static XSENS_THREAD_RETURN threadInit(void *obj)
Definition: threading.cpp:409
xsens::StandardThread::threadCleanup
static void threadCleanup(void *obj)
Cleanup the thread by calling the exit function.
Definition: threading.cpp:421
XsTime_msleep
void XsTime_msleep(uint32_t ms)
Make the current thread sleep for at least ms milliseconds.
Definition: xstime.c:353
xsens::StandardThread::isRunning
bool isRunning(void) volatile const noexcept
Returns whether the thread is currently running.
Definition: threading.cpp:160
xsens::StandardThread::m_attr
pthread_attr_t m_attr
Duplicates m_stop functionality for external dependent classes such as Semaphore.
Definition: threading.h:101
xsens::WaitEvent::terminate
void terminate()
Terminates the thread.
Definition: threading.cpp:1162
s
XmlRpcServer s
xsens::WaitEvent::WaitEvent
WaitEvent()
Definition: threading.cpp:1100
xsens::WatchDogThread::m_attr
pthread_attr_t m_attr
Definition: threading.h:177
xsens::Semaphore::m_semname
char * m_semname
A name of the semaphore.
Definition: xsens_mutex.h:1724
time.h
xsNameThisThread
void XSTYPES_DLL_API xsNameThisThread(const char *threadName)
Set the name of the current thread to threadName.
Definition: xsthread.c:140
xsens::WatchDogThread::stopTimer
bool stopTimer(void) noexcept
Stops the timer.
Definition: threading.cpp:591
xsens::WaitEvent::set
void set()
Set the event.
Definition: threading.cpp:1136
xsens::WatchDogThread::resetTimer
bool resetTimer(uint32_t timeout=0)
Resets the timer and sets a timeout.
Definition: threading.cpp:739
UINT32_MAX
#define UINT32_MAX
Definition: pstdint.h:481
xsens::WaitCondition::~WaitCondition
~WaitCondition()
Destroy the wait condition.
Definition: threading.cpp:951
xsens::WatchDogThread::m_thread
XsThread m_thread
Definition: threading.h:171
xsens::StandardThread::innerFunction
virtual int32_t innerFunction(void)
Virtual inner function.
Definition: threading.h:119
xsens::Lock::lock
bool lock()
Locks the unlocked mutex.
Definition: xsens_mutex.h:1019
xsens::WaitCondition::m_clockId
clockid_t m_clockId
Definition: xsens_mutex.h:1830
xsYield
#define xsYield()
Release the remainder of the timeslice so other operations can run.
Definition: xsthread.h:182
xsStartThread
pthread_t XSTYPES_DLL_API xsStartThread(void *(func)(void *), void *param, void *pid)
Start a function as a thread.
Definition: xsthread.c:156
xsens::StandardThread::m_name
char * m_name
Definition: threading.h:105
xsens::WatchDogThread::m_mutex
Mutex m_mutex
Definition: threading.h:178
xsens::WatchDogThread::m_threadId
XsThreadId m_threadId
Definition: threading.h:189
xsens::WaitCondition::broadcast
void broadcast()
Unblock all waiting threads.
Definition: threading.cpp:977
xsens::StandardThread::startThread
bool startThread(const char *name=NULL)
Starts the thread.
Definition: threading.cpp:281
xsens::Semaphore::m_handle
sem_t * m_handle
A semaphore's handle.
Definition: xsens_mutex.h:1725
xsens::StandardThread::m_yieldOnZeroSleep
volatile std::atomic_bool m_yieldOnZeroSleep
When true, a sleep value of 0 returned by innerFunction will trigger a thread yield operation....
Definition: threading.h:94
xsens::WatchDogThread::WatchDogThread
WatchDogThread(WatchDogFunction func, void *param=NULL)
Constructor.
Definition: threading.cpp:461
xsens::WaitCondition::WaitCondition
WaitCondition(WaitCondition const &)=delete
xsens::WatchDogThread::m_running
bool m_running
Definition: threading.h:179
xsens::WatchDogThread::m_reset
bool m_reset
Definition: threading.h:180
xsens::Mutex::m_mutex
CRITICAL_SECTION m_mutex
Definition: xsens_mutex.h:136
xsens::WatchDogThread::~WatchDogThread
~WatchDogThread()
Destructor.
Definition: threading.cpp:483
uint32_t
unsigned int uint32_t
Definition: pstdint.h:485
xsens::WaitCondition::wait
bool wait()
Wait until we're signalled to continue.
Definition: threading.cpp:994
XS_THREAD_PRIORITY_NORMAL
@ XS_THREAD_PRIORITY_NORMAL
Definition: xsthread.h:167
xsens::StandardThread::exitFunction
virtual void exitFunction(void)
Virtual exit function.
Definition: threading.h:116
xsens::StandardThread::isTerminating
bool isTerminating() volatile const noexcept
Returns whether the thread should (have) terminate(d)
Definition: threading.cpp:182
xsens::WaitEvent::~WaitEvent
~WaitEvent()
Definition: threading.cpp:1109
xsens::WaitCondition::signal
void signal()
Unblock a single waiting thread.
Definition: threading.cpp:967
xsens::StandardThread::signalStopThread
virtual void signalStopThread(void)
Tells the thread to stop but does not wait for it to end.
Definition: threading.cpp:320
xsens::Mutex
A base mutex class.
Definition: xsens_mutex.h:132
xsens::WaitEvent::m_terminating
volatile std::atomic_bool m_terminating
Definition: xsens_mutex.h:1864
xsens::WaitEvent::m_waiterCount
volatile std::atomic_int m_waiterCount
Definition: xsens_mutex.h:1863
xsens::StandardThread::m_running
bool m_running
Indicates that the thread is running.
Definition: threading.h:102
xsens::WaitEvent::m_mutex
pthread_mutex_t m_mutex
Definition: xsens_mutex.h:1859
xsSetThreadPriority
#define xsSetThreadPriority(thrd, prio)
Definition: xsthread.h:194
xsens::StandardThread::StandardThread
StandardThread()
Definition: threading.cpp:89
xsens::StandardThread::m_thread
XsThread m_thread
Definition: threading.h:86
xsens::WatchDogThread::isAlive
bool isAlive(void) volatile const noexcept
Definition: threading.cpp:502
XSENS_THREAD_RETURN
#define XSENS_THREAD_RETURN
Definition: xsthread.h:175
xsens::WaitEvent::m_triggered
bool m_triggered
Definition: xsens_mutex.h:1861
xsens::WatchDogThread::threadMain
void threadMain(void)
Definition: threading.cpp:671
xsens::StandardThread::threadMain
void threadMain(void)
The inner loop of the thread, calls innerFunction repeatedly and sleeps when necessary.
Definition: threading.cpp:429
xsens::WaitCondition::m_condattr
pthread_condattr_t m_condattr
Definition: xsens_mutex.h:1826
xsens::Lock::unlock
bool unlock() noexcept
Unlocks the locked mutex.
Definition: xsens_mutex.h:1032
threading.h
xsens::Semaphore::~Semaphore
~Semaphore()
Destructor.
Definition: threading.cpp:834
xsens::WatchDogThread::isRunning
bool isRunning(void) volatile const noexcept
Definition: threading.cpp:517
xsens::WatchDogThread::startTimer
bool startTimer(uint32_t timeout=10000, const char *name=NULL)
Starts a timer using some parameters.
Definition: threading.cpp:551
xsens::StandardThread
A class for a standard thread that has to perform the same action repeatedly.
Definition: threading.h:83
XSENS_INVALID_THREAD
#define XSENS_INVALID_THREAD
Definition: xsthread.h:179
xsens::Semaphore::m_nofHandles
uint32_t m_nofHandles
A number of the semaphore's handles.
Definition: xsens_mutex.h:1727
XsThreadPriority
XsThreadPriority
Thread priorities for xsSetThreadPriority() and xsGetThreadPriority()
Definition: xsthread.h:162
xsens::StandardThread::stopThread
void stopThread(void) noexcept
Tells the thread to stop and waits for it to end.
Definition: threading.cpp:334
xsens::WatchDogThread
A class that keeps an eye on a threads timer.
Definition: threading.h:168
xsens::Lock
A base class for a Lock.
Definition: xsens_mutex.h:947
xstime.h
int32_t
signed int int32_t
Definition: pstdint.h:515
param
T param(const std::string &param_name, const T &default_val)
xsens::StandardThread::m_stop
volatile std::atomic_bool m_stop
Indicates that the thread should stop. Derived classes should check isTerminating() instead of direct...
Definition: threading.h:93
xsens::WatchDogThread::threadInit
static XSENS_THREAD_RETURN threadInit(void *obj)
Definition: threading.cpp:661
xsens::StandardThread::isAlive
bool isAlive(void) volatile const noexcept
Definition: threading.cpp:140
XS_THREAD_PRIORITY_LOWEST
@ XS_THREAD_PRIORITY_LOWEST
Definition: xsthread.h:164
xsens::WaitCondition::m_mutex
Mutex & m_mutex
Definition: xsens_mutex.h:1833
xsens::StandardThread::initFunction
virtual void initFunction(void)
Virtual initialization function.
Definition: threading.h:113
xsens::WaitEvent::reset
void reset()
Reset the event.
Definition: threading.cpp:1148
xsens::StandardThread::setPriority
bool setPriority(XsThreadPriority pri)
Sets the priority of the thread.
Definition: threading.cpp:191
xsGetCurrentThreadId
#define xsGetCurrentThreadId()
Definition: xsthread.h:191
xsens::Lock::tryLock
bool tryLock()
Tries to lock the unlocked mutex.
Definition: xsens_mutex.h:1058
xsens::WatchDogFunction
void(CDECL_XS * WatchDogFunction)(void *)
Definition: threading.h:163
xsens::Semaphore::post
int32_t post(int32_t increment=1) noexcept
Increases the count of the specified semaphore object by a specified amount.
Definition: threading.cpp:882
xsens::Semaphore::wait1
bool wait1()
Waits for an infinite time or until the semaphore is released.
Definition: threading.cpp:841
xsens
Definition: threading.cpp:78
XsTimeStamp
struct XsTimeStamp XsTimeStamp
Definition: xstimestamp.h:458
xsens::StandardThread::m_priority
XsThreadPriority m_priority
Definition: threading.h:87
XS_THREAD_PRIORITY_HIGHEST
@ XS_THREAD_PRIORITY_HIGHEST
Definition: xsthread.h:170
xsens::WatchDogThread::m_timeout
volatile std::atomic< std::uint32_t > m_timeout
Definition: threading.h:183
XsTimeStamp
This class contains method to set, retrieve and compare timestamps.
Definition: xstimestamp.h:115
xsens::WatchDogThread::m_name
char * m_name
Definition: threading.h:186
xsens::WatchDogThread::m_func
WatchDogFunction m_func
Definition: threading.h:184


xsens_mti_driver
Author(s):
autogenerated on Sun Sep 3 2023 02:43:20