thread.cc 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
  2. // Copyright (C) 2013 Henner Zeller <h.zeller@acm.org>
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation version 2.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
  15. #include "thread.h"
  16. #include <assert.h>
  17. #include <limits.h>
  18. #include <sched.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. namespace rgb_matrix {
  23. void *Thread::PthreadCallRun(void *tobject) {
  24. reinterpret_cast<Thread*>(tobject)->Run();
  25. return NULL;
  26. }
  27. Thread::Thread() : started_(false) {}
  28. Thread::~Thread() {
  29. WaitStopped();
  30. }
  31. void Thread::WaitStopped() {
  32. if (!started_) return;
  33. int result = pthread_join(thread_, NULL);
  34. if (result != 0) {
  35. perror("Issue joining thread");
  36. }
  37. started_ = false;
  38. }
  39. void Thread::Start(int priority, uint32_t affinity_mask) {
  40. assert(!started_); // Did you call WaitStopped() ?
  41. pthread_create(&thread_, NULL, &PthreadCallRun, this);
  42. int err;
  43. if (priority > 0) {
  44. struct sched_param p;
  45. p.sched_priority = priority;
  46. if ((err = pthread_setschedparam(thread_, SCHED_FIFO, &p))) {
  47. char buffer[PATH_MAX];
  48. const char *bin = realpath("/proc/self/exe", buffer); // Linux specific.
  49. fprintf(stderr, "Can't set realtime thread priority=%d: %s.\n"
  50. "\tYou are probably not running as root ?\n"
  51. "\tThis will seriously mess with color stability and flicker\n"
  52. "\tof the matrix. Please run as `root` (e.g. by invoking this\n"
  53. "\tprogram with `sudo`), or setting the capability on this\n"
  54. "\tbinary by calling\n"
  55. "\tsudo setcap 'cap_sys_nice=eip' %s\n",
  56. p.sched_priority, strerror(err), bin ? bin : "<this binary>");
  57. }
  58. }
  59. if (affinity_mask != 0) {
  60. cpu_set_t cpu_mask;
  61. CPU_ZERO(&cpu_mask);
  62. for (int i = 0; i < 32; ++i) {
  63. if ((affinity_mask & (1<<i)) != 0) {
  64. CPU_SET(i, &cpu_mask);
  65. }
  66. }
  67. if ((err=pthread_setaffinity_np(thread_, sizeof(cpu_mask), &cpu_mask))) {
  68. // On a Pi1, this won't work as there is only one core. Don't worry in
  69. // that case.
  70. }
  71. }
  72. started_ = true;
  73. }
  74. bool Mutex::WaitOn(pthread_cond_t *cond, long timeout_ms) {
  75. if (timeout_ms < 0) {
  76. pthread_cond_wait(cond, &mutex_);
  77. return true;
  78. }
  79. else {
  80. struct timespec t;
  81. clock_gettime(CLOCK_REALTIME, &t);
  82. t.tv_sec += timeout_ms / 1000;
  83. t.tv_nsec += (timeout_ms % 1000) * 1000000;
  84. t.tv_sec += t.tv_nsec / 1000000000;
  85. t.tv_nsec %= 1000000000;
  86. // TODO(hzeller): It doesn't seem we return with EINTR on signal. We should.
  87. return pthread_cond_timedwait(cond, &mutex_, &t) == 0;
  88. }
  89. }
  90. } // namespace rgb_matrix