/[svn]/linuxsampler/trunk/src/engines/InstrumentManagerThread.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/InstrumentManagerThread.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2349 - (show annotations) (download)
Sun Jun 17 15:47:43 2012 UTC (11 years, 10 months ago) by persson
File size: 8561 byte(s)
* Mac OS X: fixed crash when unloading plugin on 10.7 and later

1 /***************************************************************************
2 * *
3 * Copyright (C) 2005 - 2012 Christian Schoenebeck *
4 * *
5 * This library is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this library; if not, write to the Free Software *
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
18 * MA 02111-1307 USA *
19 ***************************************************************************/
20
21 #include "InstrumentManagerThread.h"
22
23 #include "../common/global_private.h"
24 #include "EngineChannelFactory.h"
25
26 #ifdef __APPLE__
27 #include <sys/utsname.h>
28 #endif
29
30 namespace LinuxSampler {
31
32 InstrumentManagerThread::InstrumentManagerThread() : Thread(true, false, 0, -4) {
33 eventHandler.pThread = this;
34 }
35
36 InstrumentManagerThread::~InstrumentManagerThread() {
37 }
38
39 /**
40 * @brief Order loading of a new instrument.
41 *
42 * The request will go into a queue waiting to be processed by the
43 * class internal task thread. This method will immediately return and
44 * the instrument will be loaded in the background.
45 *
46 * @param Filename - file name of the instrument
47 * @param uiInstrumentIndex - index of the instrument within the file
48 * @param pEngineChannel - engine channel on which the instrument should be loaded
49 */
50 void InstrumentManagerThread::StartNewLoad(String Filename, uint uiInstrumentIndex, EngineChannel* pEngineChannel) {
51 dmsg(1,("Scheduling '%s' (Index=%d) to be loaded in background (if not loaded yet).\n",Filename.c_str(),uiInstrumentIndex));
52
53 // the listener only needs to be registered once in the
54 // Sampler, but as we don't know if Sampler has been
55 // recreated, we simply remove and add every time
56 pEngineChannel->GetSampler()->RemoveChannelCountListener(&eventHandler);
57 pEngineChannel->GetSampler()->AddChannelCountListener(&eventHandler);
58
59 command_t cmd;
60 cmd.type = command_t::DIRECT_LOAD;
61 cmd.pEngineChannel = pEngineChannel;
62 cmd.instrumentId.Index = uiInstrumentIndex;
63 cmd.instrumentId.FileName = Filename;
64
65 mutex.Lock();
66 queue.push_back(cmd);
67 mutex.Unlock();
68
69 StartThread(); // ensure thread is running
70 conditionJobsLeft.Set(true); // wake up thread
71 }
72
73 /**
74 * @brief Order changing the life-time strategy of an instrument.
75 *
76 * The request will go into a queue waiting to be processed by the
77 * class internal task thread. This method will immediately return and
78 * in case the instrument has to be loaded due to a mode change to
79 * PERSISTENT, it will be loaded in the background.
80 *
81 * @param pManager - InstrumentManager which manages the instrument
82 * @param ID - unique ID of the instrument
83 * @param Mode - life-time strategy to set for this instrument
84 */
85 void InstrumentManagerThread::StartSettingMode(InstrumentManager* pManager, const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) {
86 command_t cmd;
87 cmd.type = command_t::INSTR_MODE;
88 cmd.pManager = pManager;
89 cmd.instrumentId = ID;
90 cmd.mode = Mode;
91
92 mutex.Lock();
93 queue.push_back(cmd);
94 mutex.Unlock();
95
96 StartThread(); // ensure thread is running
97 conditionJobsLeft.Set(true); // wake up thread
98 }
99
100 // Entry point for the task thread.
101 int InstrumentManagerThread::Main() {
102 while (true) {
103
104 #if CONFIG_PTHREAD_TESTCANCEL
105 TestCancel();
106 #endif
107
108 while (true) {
109 command_t cmd;
110
111 // grab a new command from the queue
112 mutex.Lock();
113 bool empty = queue.empty();
114 if (!empty) {
115 cmd = queue.front();
116 queue.pop_front();
117
118 if (cmd.type == command_t::DIRECT_LOAD) {
119 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, false);
120 }
121 }
122 mutex.Unlock();
123 if (empty) break;
124
125 try {
126 switch (cmd.type) {
127 case command_t::DIRECT_LOAD:
128 cmd.pEngineChannel->PrepareLoadInstrument(cmd.instrumentId.FileName.c_str(), cmd.instrumentId.Index);
129 cmd.pEngineChannel->LoadInstrument();
130 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
131 break;
132 case command_t::INSTR_MODE:
133 cmd.pManager->SetMode(cmd.instrumentId, cmd.mode);
134 break;
135 default:
136 std::cerr << "InstrumentManagerThread: unknown command - BUG!\n" << std::flush;
137 }
138 } catch (Exception e) {
139 e.PrintMessage();
140 if (cmd.type == command_t::DIRECT_LOAD) {
141 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
142 }
143 } catch (...) {
144 std::cerr << "InstrumentManagerThread: some exception occured, could not finish task\n" << std::flush;
145 if (cmd.type == command_t::DIRECT_LOAD) {
146 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
147 }
148 }
149 }
150
151 // nothing left to do, sleep until new jobs arrive
152 conditionJobsLeft.WaitIf(false);
153 // reset flag
154 conditionJobsLeft.Set(false);
155 // unlock condition object so it can be turned again by other thread
156 conditionJobsLeft.Unlock();
157 }
158 return 0;
159 }
160
161 void InstrumentManagerThread::EventHandler::ChannelToBeRemoved(SamplerChannel* pChannel) {
162 /*
163 Removing from the queue an eventual scheduled loading of an instrument
164 to a sampler channel which is going to be removed.
165 */
166 pThread->mutex.Lock();
167 std::list<command_t>::iterator it;
168 for (it = pThread->queue.begin(); it != pThread->queue.end();){
169 if ((*it).type != command_t::DIRECT_LOAD) { ++it; continue; }
170 if ((*it).pEngineChannel == pChannel->GetEngineChannel()) {
171 it = pThread->queue.erase(it);
172 // we don't break here because the same engine channel could
173 // occur more than once in the queue, so don't make optimizations
174 } else {
175 ++it;
176 }
177 }
178 pThread->mutex.Unlock();
179 }
180
181 #ifdef __APPLE__
182 int InstrumentManagerThread::StopThread() {
183 utsname buf;
184 int osVersion = uname(&buf) ? 0 : atoi(buf.release);
185
186 // This is a fix for Mac OS X 10.6 and earlier, where
187 // SignalStopThread doesn't wake up a thread waiting for a
188 // condition variable.
189 if (osVersion < 11) { // darwin 11 = OS X 10.7
190 SignalStopThread(); // send stop signal, but don't wait
191 conditionJobsLeft.Set(true); // wake thread
192 }
193 return Thread::StopThread(); // then wait for it to cancel
194 }
195 #endif
196
197 #ifdef WIN32
198 int InstrumentManagerThread::StopThread() {
199 int res = Thread::StopThread();
200 conditionJobsLeft.Reset();
201 return res;
202 }
203 #endif
204
205 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC