/[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 2324 - (show annotations) (download)
Sun Mar 4 09:01:32 2012 UTC (12 years, 1 month ago) by persson
File size: 8246 byte(s)
* plugin bugfix: instrument loading hang when the plugin was loaded a
  second time (this time it's for Linux and Mac, previous similar fix
  was for Windows)
* thread safety fixes for the instrument loading thread
* MME driver: removed compiler warning
* LV2: fixed invalid realtime statement in plugin metadata

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 namespace LinuxSampler {
27
28 InstrumentManagerThread::InstrumentManagerThread() : Thread(true, false, 0, -4) {
29 eventHandler.pThread = this;
30 }
31
32 InstrumentManagerThread::~InstrumentManagerThread() {
33 }
34
35 /**
36 * @brief Order loading of a new instrument.
37 *
38 * The request will go into a queue waiting to be processed by the
39 * class internal task thread. This method will immediately return and
40 * the instrument will be loaded in the background.
41 *
42 * @param Filename - file name of the instrument
43 * @param uiInstrumentIndex - index of the instrument within the file
44 * @param pEngineChannel - engine channel on which the instrument should be loaded
45 */
46 void InstrumentManagerThread::StartNewLoad(String Filename, uint uiInstrumentIndex, EngineChannel* pEngineChannel) {
47 dmsg(1,("Scheduling '%s' (Index=%d) to be loaded in background (if not loaded yet).\n",Filename.c_str(),uiInstrumentIndex));
48
49 // the listener only needs to be registered once in the
50 // Sampler, but as we don't know if Sampler has been
51 // recreated, we simply remove and add every time
52 pEngineChannel->GetSampler()->RemoveChannelCountListener(&eventHandler);
53 pEngineChannel->GetSampler()->AddChannelCountListener(&eventHandler);
54
55 command_t cmd;
56 cmd.type = command_t::DIRECT_LOAD;
57 cmd.pEngineChannel = pEngineChannel;
58 cmd.instrumentId.Index = uiInstrumentIndex;
59 cmd.instrumentId.FileName = Filename;
60
61 mutex.Lock();
62 queue.push_back(cmd);
63 mutex.Unlock();
64
65 StartThread(); // ensure thread is running
66 conditionJobsLeft.Set(true); // wake up thread
67 }
68
69 /**
70 * @brief Order changing the life-time strategy of an instrument.
71 *
72 * The request will go into a queue waiting to be processed by the
73 * class internal task thread. This method will immediately return and
74 * in case the instrument has to be loaded due to a mode change to
75 * PERSISTENT, it will be loaded in the background.
76 *
77 * @param pManager - InstrumentManager which manages the instrument
78 * @param ID - unique ID of the instrument
79 * @param Mode - life-time strategy to set for this instrument
80 */
81 void InstrumentManagerThread::StartSettingMode(InstrumentManager* pManager, const InstrumentManager::instrument_id_t& ID, InstrumentManager::mode_t Mode) {
82 command_t cmd;
83 cmd.type = command_t::INSTR_MODE;
84 cmd.pManager = pManager;
85 cmd.instrumentId = ID;
86 cmd.mode = Mode;
87
88 mutex.Lock();
89 queue.push_back(cmd);
90 mutex.Unlock();
91
92 StartThread(); // ensure thread is running
93 conditionJobsLeft.Set(true); // wake up thread
94 }
95
96 // Entry point for the task thread.
97 int InstrumentManagerThread::Main() {
98 while (true) {
99
100 #if CONFIG_PTHREAD_TESTCANCEL
101 TestCancel();
102 #endif
103
104 while (true) {
105 command_t cmd;
106
107 // grab a new command from the queue
108 mutex.Lock();
109 bool empty = queue.empty();
110 if (!empty) {
111 cmd = queue.front();
112 queue.pop_front();
113 }
114 mutex.Unlock();
115 if (empty) break;
116
117 try {
118 switch (cmd.type) {
119 case command_t::DIRECT_LOAD:
120 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, false);
121 cmd.pEngineChannel->PrepareLoadInstrument(cmd.instrumentId.FileName.c_str(), cmd.instrumentId.Index);
122 cmd.pEngineChannel->LoadInstrument();
123 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
124 break;
125 case command_t::INSTR_MODE:
126 cmd.pManager->SetMode(cmd.instrumentId, cmd.mode);
127 break;
128 default:
129 std::cerr << "InstrumentManagerThread: unknown command - BUG!\n" << std::flush;
130 }
131 } catch (Exception e) {
132 e.PrintMessage();
133 if (cmd.type == command_t::DIRECT_LOAD) {
134 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
135 }
136 } catch (...) {
137 std::cerr << "InstrumentManagerThread: some exception occured, could not finish task\n" << std::flush;
138 if (cmd.type == command_t::DIRECT_LOAD) {
139 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
140 }
141 }
142 }
143
144 // nothing left to do, sleep until new jobs arrive
145 conditionJobsLeft.WaitIf(false);
146 // reset flag
147 conditionJobsLeft.Set(false);
148 // unlock condition object so it can be turned again by other thread
149 conditionJobsLeft.Unlock();
150 }
151 return 0;
152 }
153
154 void InstrumentManagerThread::EventHandler::ChannelToBeRemoved(SamplerChannel* pChannel) {
155 /*
156 Removing from the queue an eventual scheduled loading of an instrument
157 to a sampler channel which is going to be removed.
158 */
159 pThread->mutex.Lock();
160 std::list<command_t>::iterator it;
161 for (it = pThread->queue.begin(); it != pThread->queue.end();){
162 if ((*it).type != command_t::DIRECT_LOAD) { ++it; continue; }
163 if ((*it).pEngineChannel == pChannel->GetEngineChannel()) {
164 it = pThread->queue.erase(it);
165 // we don't break here because the same engine channel could
166 // occur more than once in the queue, so don't make optimizations
167 } else {
168 ++it;
169 }
170 }
171 pThread->mutex.Unlock();
172 }
173
174 #ifdef __APPLE__
175 int InstrumentManagerThread::StopThread() {
176 // This is a fix for Mac OS X, where SignalStopThread doesn't
177 // wake up a thread waiting for a condition variable.
178 SignalStopThread(); // send stop signal, but don't wait
179 conditionJobsLeft.Set(true); // wake thread
180 return Thread::StopThread(); // then wait for it to cancel
181 }
182 #endif
183
184 #ifdef WIN32
185 int InstrumentManagerThread::StopThread() {
186 int res = Thread::StopThread();
187 conditionJobsLeft.Reset();
188 return res;
189 }
190 #endif
191
192 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC