summaryrefslogtreecommitdiff
path: root/attic/muse_qt4_evolution/muse/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'attic/muse_qt4_evolution/muse/thread.cpp')
-rw-r--r--attic/muse_qt4_evolution/muse/thread.cpp354
1 files changed, 354 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/muse/thread.cpp b/attic/muse_qt4_evolution/muse/thread.cpp
new file mode 100644
index 00000000..8291613b
--- /dev/null
+++ b/attic/muse_qt4_evolution/muse/thread.cpp
@@ -0,0 +1,354 @@
+//=============================================================================
+// MusE
+// Linux Music Editor
+// $Id:$
+//
+// Copyright (C) 2002-2006 by Werner Schweer and others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//=============================================================================
+
+#include <poll.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include "thread.h"
+#include "globals.h"
+#include "errno.h"
+
+//---------------------------------------------------------
+// Thread
+//---------------------------------------------------------
+
+Thread::~Thread()
+ {
+ }
+
+//---------------------------------------------------------
+// serverloop
+//---------------------------------------------------------
+
+static void* loop(void* mops)
+ {
+ Thread* t = (Thread*) mops;
+ t->loop();
+ return 0;
+ }
+
+//---------------------------------------------------------
+// start
+//---------------------------------------------------------
+
+void Thread::start(int prio, void* ptr)
+ {
+ userPtr = ptr;
+ pthread_attr_t* attributes = 0;
+
+ realTimePriority = prio;
+ if (realTimePriority) {
+ attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
+ pthread_attr_init(attributes);
+
+ if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) {
+ printf("cannot set FIFO scheduling class for RT thread\n");
+ }
+ if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) {
+ printf("Cannot set scheduling scope for RT thread\n");
+ }
+ if (pthread_attr_setinheritsched(attributes, PTHREAD_EXPLICIT_SCHED)) {
+ printf("Cannot set setinheritsched for RT thread\n");
+ }
+
+ struct sched_param rt_param;
+ memset(&rt_param, 0, sizeof(rt_param));
+ rt_param.sched_priority = realTimePriority;
+ if (pthread_attr_setschedparam (attributes, &rt_param)) {
+ printf("Cannot set scheduling priority %d for RT thread (%s)\n",
+ realTimePriority, strerror(errno));
+ }
+ }
+
+ int rv;
+ if ((rv = pthread_create(&thread, attributes, ::loop, this))) {
+ fprintf(stderr, "creating thread <%s> failed: %s\n",
+ _name, strerror(rv));
+ thread = 0;
+ }
+ }
+
+//---------------------------------------------------------
+// stop
+//---------------------------------------------------------
+
+void Thread::stop(bool force)
+ {
+ if (thread == 0)
+ return;
+ if (force) {
+ pthread_cancel(thread);
+ threadStop();
+ }
+ _running = false;
+ if (pthread_join(thread, 0)) {
+ // perror("Failed to join sequencer thread");
+ }
+ }
+
+//---------------------------------------------------------
+// Thread
+// prio = 0 no realtime scheduling
+//---------------------------------------------------------
+
+Thread::Thread(const char* s)
+ {
+ userPtr = 0;
+ _name = s;
+ realTimePriority = 0;
+ pfd = 0;
+ npfd = 0;
+ maxpfd = 0;
+ _running = false;
+ _pollWait = -1;
+ thread = 0;
+ sendSerialNo = 0x00a5a500;
+
+ // create message channels
+ int filedes[2]; // 0 - reading 1 - writing
+ if (pipe(filedes) == -1) {
+ perror("thread:creating pipe4");
+ exit(-1);
+ }
+ toThreadFdr = filedes[0];
+ toThreadFdw = filedes[1];
+ if (fcntl(toThreadFdw, F_SETFL, O_NONBLOCK) == -1)
+ perror("set pipe nonblocking\n");
+
+ if (pipe(filedes) == -1) {
+ perror("thread: creating pipe5");
+ exit(-1);
+ }
+ fromThreadFdr = filedes[0];
+ fromThreadFdw = filedes[1];
+ if (fcntl(fromThreadFdw, F_SETFL, O_NONBLOCK) == -1)
+ perror("set pipe nonblocking\n");
+ }
+
+//---------------------------------------------------------
+// addPollFd
+//---------------------------------------------------------
+
+void Thread::addPollFd(int fd, int action, void (*handler)(void*,void*), void* p, void* q)
+ {
+ if (fd == -1)
+ return;
+ for (iPoll i = plist.begin(); i != plist.end(); ++i) {
+ if ((i->fd == fd) && (i->action == action))
+ return;
+ }
+
+ plist.push_back(Poll(fd, action, handler, p, q));
+
+ if (npfd == maxpfd) {
+ int n = (maxpfd == 0) ? 4 : maxpfd * 2;
+ //TODO: delete old pfd
+ pfd = new struct pollfd[n];
+ maxpfd = n;
+ }
+ ++npfd;
+ int idx = 0;
+ for (iPoll i = plist.begin(); i != plist.end(); ++i, ++idx) {
+ pfd[idx].fd = i->fd;
+ pfd[idx].events = i->action;
+ }
+ }
+
+//---------------------------------------------------------
+// removePollFd
+//---------------------------------------------------------
+
+void Thread::removePollFd(int fd, int action)
+ {
+ for (iPoll i = plist.begin(); i != plist.end(); ++i) {
+ if (i->fd == fd && i->action == action) {
+ plist.erase(i);
+ --npfd;
+ break;
+ }
+ }
+ int idx = 0;
+ for (iPoll i = plist.begin(); i != plist.end(); ++i, ++idx) {
+ pfd[idx].fd = i->fd;
+ pfd[idx].events = i->action;
+ }
+ }
+
+//---------------------------------------------------------
+// loop
+//---------------------------------------------------------
+
+void Thread::loop()
+ {
+ if (!debugMode) {
+ if (mlockall(MCL_CURRENT | MCL_FUTURE))
+ perror("WARNING: Cannot lock memory:");
+ }
+#ifdef __APPLE__
+#define BIG_ENOUGH_STACK (1024*256*1)
+#else
+#define BIG_ENOUGH_STACK (1024*1024*1)
+#endif
+ char buf[BIG_ENOUGH_STACK];
+ for (int i = 0; i < BIG_ENOUGH_STACK; i++)
+ buf[i] = i;
+#undef BIG_ENOUGH_STACK
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ int policy;
+ /*if ((policy = sched_getscheduler (0)) < 0) {
+ printf("Thread: Cannot get current client scheduler: %s\n", strerror(errno));
+ }
+*/
+ if (debugMsg)
+ printf("Thread <%s, id %p> has %s priority %d\n",
+ _name, (void *)pthread_self(), policy == SCHED_FIFO ? "SCHED_FIFO" : "SCHED_OTHER",
+ realTimePriority);
+
+ _running = true;
+
+ threadStart(userPtr);
+ while (_running) {
+ if (debugMode) // DEBUG
+ _pollWait = 10; // ms
+ else
+ _pollWait = -1;
+
+ int n = poll(pfd, npfd, _pollWait);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "poll failed: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if (n == 0) { // timeout
+ defaultTick();
+ continue;
+ }
+ struct pollfd* p = &pfd[0];
+ int i = 0;
+ for (iPoll ip = plist.begin(); ip != plist.end(); ++ip, ++p, ++i) {
+ if (ip->action & p->revents) {
+ (ip->handler)(ip->param1, ip->param2);
+ break;
+ }
+ }
+ }
+ threadStop();
+ }
+
+//---------------------------------------------------------
+// sendMsg
+// send request from gui to thread
+// wait until request is processed
+//---------------------------------------------------------
+
+extern const char* seqMsgList[];
+
+bool Thread::sendMsg(const ThreadMsg* m)
+ {
+// fprintf(stderr, "<%s> self: %p sendMsg %d id %s running %d\n",
+// _name,
+// pthread_self(), sendSerialNo, seqMsgList[m->id], _running);
+
+ m->serialNo = sendSerialNo;
+ if (_running) {
+ int rv = write(toThreadFdw, &m, sizeof(ThreadMsg*));
+ if (rv != sizeof(ThreadMsg*)) {
+ perror("Thread::sendMessage(): write pipe failed");
+ return true;
+ }
+
+ // wait for thread to finish operation
+ int c;
+ rv = read(fromThreadFdr, &c, sizeof(c));
+ if (rv != sizeof(c)) {
+ perror("Thread::sendMessage(): read pipe failed");
+ return true;
+ }
+ if (c != sendSerialNo)
+ fprintf(stderr, "%p Thread:sendMsg() serial No mismatch %d - %d\n",
+ this, c, sendSerialNo);
+ }
+ else {
+ // if thread is not running (during initialization)
+ // process commands directly:
+ processMsg(m);
+ }
+ ++sendSerialNo;
+ return false;
+ }
+
+//---------------------------------------------------------
+// sendMsg1
+// send request from gui to thread
+// do __not__ wait until request is processed
+//---------------------------------------------------------
+
+bool Thread::sendMsg1(const void* m, int n)
+ {
+ int rv = write(toThreadFdw, m, n);
+ if (rv != n) {
+ perror("Thread::sendMessage1(): write pipe failed");
+ return true;
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// readMsg
+//---------------------------------------------------------
+
+void Thread::readMsg()
+ {
+ ThreadMsg* p;
+ if (read(toThreadFdr, &p, sizeof(p)) != sizeof(p)) {
+ perror("Thread::readMsg(): read pipe failed");
+ exit(-1);
+ }
+// fprintf(stderr, "%p read msg %d %s\n", this, p->serialNo, seqMsgList[p->id]);
+
+ processMsg(p);
+ int c = p->serialNo;
+ int rv = write(fromThreadFdw, &c, sizeof(c));
+ if (rv != sizeof(c))
+ perror("Thread::readMsg(): write pipe failed");
+ }
+
+//---------------------------------------------------------
+// readMsg
+// sequencer reads one gui message
+//---------------------------------------------------------
+
+void Thread::readMsg1(int size)
+ {
+ char buffer[size];
+ int n = read(toThreadFdr, buffer, size);
+ if (n != size) {
+ fprintf(stderr, "Thread::readMessage1(): read pipe failed, get %d, expected %d: %s\n",
+ n, size, strerror(errno));
+ exit(-1);
+ }
+ processMsg1(buffer);
+ }
+