PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/muse-2.0/muse/thread.cpp

#
C++ | 415 lines | 245 code | 58 blank | 112 comment | 72 complexity | 1692da8c1645d95d40a3f1bf6c8e8745 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. //=========================================================
  2. // MusE
  3. // Linux Music Editor
  4. // $Id: thread.cpp,v 1.4.2.5 2009/12/20 05:00:35 terminator356 Exp $
  5. //
  6. // (C) Copyright 2001-2004 Werner Schweer (ws@seh.de)
  7. //
  8. // This program is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU General Public License
  10. // as published by the Free Software Foundation; version 2 of
  11. // the License, or (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program; if not, write to the Free Software
  20. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. //
  22. //=========================================================
  23. #include "thread.h"
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <sys/mman.h>
  28. #include <sys/poll.h>
  29. #include <fcntl.h>
  30. #include "globals.h"
  31. #include "errno.h"
  32. namespace MusECore {
  33. //---------------------------------------------------------
  34. // Thread
  35. //---------------------------------------------------------
  36. Thread::~Thread()
  37. {
  38. }
  39. //---------------------------------------------------------
  40. // serverloop
  41. //---------------------------------------------------------
  42. static void* loop(void* mops)
  43. {
  44. Thread* t = (Thread*) mops;
  45. t->loop();
  46. return 0;
  47. }
  48. //---------------------------------------------------------
  49. // start
  50. //---------------------------------------------------------
  51. void Thread::start(int prio, void* ptr)
  52. {
  53. userPtr = ptr;
  54. pthread_attr_t* attributes = 0;
  55. _realTimePriority = prio;
  56. /* DELETETHIS 14
  57. attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
  58. pthread_attr_init(attributes);
  59. */
  60. // pthread_mutexattr_t mutexattr;
  61. // pthread_mutexattr_init(&mutexattr);
  62. // pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_TIMED_NP);
  63. // pthread_mutex_init(&lock, &mutexattr);
  64. // pthread_cond_init(&ready, 0);
  65. // pthread_mutex_lock(&lock);
  66. //if (_realTimePriority) {
  67. if (MusEGlobal::realTimeScheduling && _realTimePriority > 0) { // p4.0.16
  68. attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
  69. pthread_attr_init(attributes);
  70. if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) {
  71. printf("cannot set FIFO scheduling class for RT thread\n");
  72. }
  73. if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) {
  74. printf("Cannot set scheduling scope for RT thread\n");
  75. }
  76. if (pthread_attr_setinheritsched(attributes, PTHREAD_EXPLICIT_SCHED)) {
  77. printf("Cannot set setinheritsched for RT thread\n");
  78. }
  79. struct sched_param rt_param;
  80. memset(&rt_param, 0, sizeof(rt_param));
  81. rt_param.sched_priority = _realTimePriority;
  82. if (pthread_attr_setschedparam (attributes, &rt_param)) {
  83. printf("Cannot set scheduling priority %d for RT thread (%s)\n",
  84. _realTimePriority, strerror(errno));
  85. }
  86. }
  87. /* DELETETHIS 8
  88. if (pthread_create(&thread, attributes, MusECore::loop, this))
  89. perror("creating thread failed:");
  90. // else
  91. // {
  92. // pthread_cond_wait(&ready, &lock);
  93. // }
  94. // pthread_mutex_unlock(&lock);
  95. */
  96. int rv = pthread_create(&thread, attributes, MusECore::loop, this);
  97. if(rv)
  98. {
  99. // p4.0.16: MusEGlobal::realTimeScheduling is unreliable. It is true even in some clearly non-RT cases.
  100. // I cannot seem to find a reliable answer to the question of "are we RT or not".
  101. // MusE was failing with a stock kernel because of PTHREAD_EXPLICIT_SCHED.
  102. // So we'll just have to try again without attributes.
  103. if (MusEGlobal::realTimeScheduling && _realTimePriority > 0)
  104. rv = pthread_create(&thread, NULL, MusECore::loop, this);
  105. }
  106. if(rv)
  107. fprintf(stderr, "creating thread <%s> failed: %s\n", _name, strerror(rv));
  108. if (attributes) // p4.0.16
  109. {
  110. pthread_attr_destroy(attributes);
  111. free(attributes);
  112. }
  113. }
  114. //---------------------------------------------------------
  115. // stop
  116. //---------------------------------------------------------
  117. void Thread::stop(bool force)
  118. {
  119. if (thread == 0)
  120. return;
  121. if (force) {
  122. pthread_cancel(thread);
  123. threadStop();
  124. }
  125. _running = false;
  126. if (thread) {
  127. if (pthread_join(thread, 0)) {
  128. // perror("Failed to join sequencer thread"); DELETETHIS and the if around?
  129. }
  130. }
  131. }
  132. //---------------------------------------------------------
  133. // Thread
  134. // prio = 0 no realtime scheduling
  135. //---------------------------------------------------------
  136. Thread::Thread(const char* s)
  137. {
  138. userPtr = 0;
  139. _name = s;
  140. _realTimePriority = 0;
  141. pfd = 0;
  142. npfd = 0;
  143. maxpfd = 0;
  144. _running = false;
  145. _pollWait = -1;
  146. thread = 0;
  147. // create message channels
  148. int filedes[2]; // 0 - reading 1 - writing
  149. if (pipe(filedes) == -1) {
  150. perror("thread:creating pipe");
  151. exit(-1);
  152. }
  153. toThreadFdr = filedes[0];
  154. toThreadFdw = filedes[1];
  155. if (pipe(filedes) == -1) {
  156. perror("thread: creating pipe");
  157. exit(-1);
  158. }
  159. fromThreadFdr = filedes[0];
  160. fromThreadFdw = filedes[1];
  161. // pthread_mutexattr_t mutexattr; DELETETHIS 5
  162. // pthread_mutexattr_init(&mutexattr);
  163. // pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_TIMED_NP);
  164. // pthread_mutex_init(&lock, &mutexattr);
  165. // pthread_cond_init(&ready, 0);
  166. }
  167. //---------------------------------------------------------
  168. // addPollFd
  169. //---------------------------------------------------------
  170. void Thread::addPollFd(int fd, int action, void (*handler)(void*,void*), void* p, void* q)
  171. {
  172. if (fd == -1)
  173. return;
  174. for (iPoll i = plist.begin(); i != plist.end(); ++i) {
  175. if ((i->fd == fd) && (i->action == action))
  176. return;
  177. }
  178. plist.push_back(Poll(fd, action, handler, p, q));
  179. if (npfd == maxpfd) {
  180. int n = (maxpfd == 0) ? 4 : maxpfd * 2;
  181. //TODO: delete old pfd
  182. pfd = new struct pollfd[n];
  183. maxpfd = n;
  184. }
  185. ++npfd;
  186. int idx = 0;
  187. for (iPoll i = plist.begin(); i != plist.end(); ++i, ++idx) {
  188. pfd[idx].fd = i->fd;
  189. pfd[idx].events = i->action;
  190. }
  191. }
  192. //---------------------------------------------------------
  193. // removePollFd
  194. //---------------------------------------------------------
  195. void Thread::removePollFd(int fd, int action)
  196. {
  197. for (iPoll i = plist.begin(); i != plist.end(); ++i) {
  198. if (i->fd == fd && i->action == action) {
  199. plist.erase(i);
  200. --npfd;
  201. break;
  202. }
  203. }
  204. int idx = 0;
  205. for (iPoll i = plist.begin(); i != plist.end(); ++i, ++idx) {
  206. pfd[idx].fd = i->fd;
  207. pfd[idx].events = i->action;
  208. }
  209. }
  210. //---------------------------------------------------------
  211. // loop
  212. //---------------------------------------------------------
  213. void Thread::loop()
  214. {
  215. if (!MusEGlobal::debugMode) {
  216. if (mlockall(MCL_CURRENT | MCL_FUTURE))
  217. perror("WARNING: Cannot lock memory:");
  218. }
  219. #ifdef __APPLE__
  220. #define BIG_ENOUGH_STACK (1024*256*1)
  221. #else
  222. #define BIG_ENOUGH_STACK (1024*1024*1)
  223. #endif
  224. char buf[BIG_ENOUGH_STACK];
  225. for (int i = 0; i < BIG_ENOUGH_STACK; i++)
  226. buf[i] = i;
  227. #undef BIG_ENOUGH_STACK
  228. pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
  229. pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
  230. int policy = buf[0]; // Initialize using buf[0] to keep the compiler from complaining about unused buf.
  231. policy = 0; // Now set the true desired inital value.
  232. if ((policy = sched_getscheduler (0)) < 0) {
  233. printf("Thread: Cannot get current client scheduler: %s\n", strerror(errno));
  234. }
  235. if (MusEGlobal::debugMsg)
  236. printf("Thread <%s, id %p> has %s priority %d\n",
  237. _name, (void *)pthread_self(), policy == SCHED_FIFO ? "SCHED_FIFO" : "SCHED_OTHER",
  238. policy == SCHED_FIFO ? _realTimePriority : 0);
  239. // pthread_mutex_lock(&lock); DELETETHIS and below
  240. _running = true;
  241. // pthread_cond_signal(&ready);
  242. // pthread_mutex_unlock(&lock);
  243. threadStart(userPtr);
  244. while (_running) {
  245. if (MusEGlobal::debugMode) // DEBUG
  246. _pollWait = 10; // ms
  247. else
  248. _pollWait = -1;
  249. int n = poll(pfd, npfd, _pollWait);
  250. if (n < 0) {
  251. if (errno == EINTR)
  252. continue;
  253. fprintf(stderr, "poll failed: %s\n", strerror(errno));
  254. exit(-1);
  255. }
  256. if (n == 0) { // timeout
  257. defaultTick();
  258. continue;
  259. }
  260. struct pollfd* p = &pfd[0];
  261. int i = 0;
  262. for (iPoll ip = plist.begin(); ip != plist.end(); ++ip, ++p, ++i) {
  263. if (ip->action & p->revents) {
  264. (ip->handler)(ip->param1, ip->param2);
  265. break;
  266. }
  267. }
  268. }
  269. threadStop();
  270. }
  271. //---------------------------------------------------------
  272. // send
  273. // send request from gui to thread
  274. // wait until request is processed
  275. //---------------------------------------------------------
  276. bool Thread::sendMsg(const ThreadMsg* m)
  277. {
  278. if (_running)
  279. {
  280. int rv = write(toThreadFdw, &m, sizeof(ThreadMsg*));
  281. if (rv != sizeof(ThreadMsg*)) {
  282. perror("Thread::sendMessage(): write pipe failed");
  283. return true;
  284. }
  285. // wait for sequencer to finish operation
  286. char c;
  287. rv = read(fromThreadFdr, &c, 1);
  288. if (rv != 1)
  289. {
  290. perror("Thread::sendMessage(): read pipe failed");
  291. return true;
  292. }
  293. //int c; DELETETHIS 6
  294. //rv = read(fromThreadFdr, &c, sizeof(c));
  295. //if (rv != sizeof(c)) {
  296. // perror("Thread::sendMessage(): read pipe failed");
  297. // return true;
  298. // }
  299. }
  300. else
  301. {
  302. // if thread is not running (during initialization)
  303. // process commands directly:
  304. processMsg(m);
  305. }
  306. return false;
  307. }
  308. //---------------------------------------------------------
  309. // send
  310. // send request from gui to thread
  311. // do __not__ wait until request is processed
  312. //---------------------------------------------------------
  313. bool Thread::sendMsg1(const void* m, int n)
  314. {
  315. int rv = write(toThreadFdw, m, n);
  316. if (rv != n) {
  317. perror("Thread::sendMessage1(): write pipe failed");
  318. return true;
  319. }
  320. return false;
  321. }
  322. //---------------------------------------------------------
  323. // readMsg
  324. //---------------------------------------------------------
  325. void Thread::readMsg()
  326. {
  327. ThreadMsg* p;
  328. if (read(toThreadFdr, &p, sizeof(p)) != sizeof(p)) {
  329. perror("Thread::readMessage(): read pipe failed");
  330. exit(-1);
  331. }
  332. processMsg(p);
  333. char c = 'x';
  334. int rv = write(fromThreadFdw, &c, 1);
  335. if (rv != 1)
  336. perror("Thread::readMessage(): write pipe failed");
  337. //int c = p->serialNo; DELETETHIS 4
  338. //int rv = write(fromThreadFdw, &c, sizeof(c));
  339. //if (rv != sizeof(c))
  340. // perror("Thread::readMsg(): write pipe failed");
  341. }
  342. //---------------------------------------------------------
  343. // readMsg
  344. // sequencer reads one gui message
  345. //---------------------------------------------------------
  346. void Thread::readMsg1(int size)
  347. {
  348. char buffer[size];
  349. int n = read(toThreadFdr, buffer, size);
  350. if (n != size) {
  351. fprintf(stderr, "Thread::readMsg1(): read pipe failed, get %d, expected %d: %s\n",
  352. n, size, strerror(errno));
  353. exit(-1);
  354. }
  355. processMsg1(buffer);
  356. }
  357. } // namespace MusECore