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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2324 - (hide 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 schoenebeck 947 /***************************************************************************
2     * *
3 persson 2316 * Copyright (C) 2005 - 2012 Christian Schoenebeck *
4 schoenebeck 947 * *
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 schoenebeck 1424 #include "../common/global_private.h"
24 iliev 1826 #include "EngineChannelFactory.h"
25 schoenebeck 1424
26 schoenebeck 947 namespace LinuxSampler {
27    
28     InstrumentManagerThread::InstrumentManagerThread() : Thread(true, false, 0, -4) {
29 iliev 1761 eventHandler.pThread = this;
30 schoenebeck 947 }
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 persson 1038 dmsg(1,("Scheduling '%s' (Index=%d) to be loaded in background (if not loaded yet).\n",Filename.c_str(),uiInstrumentIndex));
48 iliev 1761
49 persson 2324 // 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 iliev 1761
55 schoenebeck 947 command_t cmd;
56     cmd.type = command_t::DIRECT_LOAD;
57     cmd.pEngineChannel = pEngineChannel;
58 persson 2277 cmd.instrumentId.Index = uiInstrumentIndex;
59     cmd.instrumentId.FileName = Filename;
60 schoenebeck 989
61     mutex.Lock();
62     queue.push_back(cmd);
63     mutex.Unlock();
64    
65 schoenebeck 947 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 schoenebeck 989
88     mutex.Lock();
89     queue.push_back(cmd);
90     mutex.Unlock();
91    
92 schoenebeck 947 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 nagata 1649
100 persson 2185 #if CONFIG_PTHREAD_TESTCANCEL
101     TestCancel();
102     #endif
103 nagata 1649
104 persson 2324 while (true) {
105 schoenebeck 947 command_t cmd;
106 schoenebeck 989
107     // grab a new command from the queue
108     mutex.Lock();
109 persson 2324 bool empty = queue.empty();
110     if (!empty) {
111     cmd = queue.front();
112     queue.pop_front();
113     }
114 schoenebeck 989 mutex.Unlock();
115 persson 2324 if (empty) break;
116 schoenebeck 989
117 schoenebeck 947 try {
118     switch (cmd.type) {
119     case command_t::DIRECT_LOAD:
120 iliev 1826 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, false);
121 persson 2277 cmd.pEngineChannel->PrepareLoadInstrument(cmd.instrumentId.FileName.c_str(), cmd.instrumentId.Index);
122 schoenebeck 947 cmd.pEngineChannel->LoadInstrument();
123 iliev 1826 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
124 schoenebeck 947 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 schoenebeck 1040 } catch (Exception e) {
132 schoenebeck 947 e.PrintMessage();
133 iliev 1826 if (cmd.type == command_t::DIRECT_LOAD) {
134     EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
135     }
136 schoenebeck 1040 } catch (...) {
137     std::cerr << "InstrumentManagerThread: some exception occured, could not finish task\n" << std::flush;
138 iliev 1826 if (cmd.type == command_t::DIRECT_LOAD) {
139     EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
140     }
141 schoenebeck 947 }
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 persson 1895 return 0;
152 schoenebeck 947 }
153 persson 1895
154 iliev 1761 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 persson 2185
174 persson 2187 #ifdef __APPLE__
175 persson 2185 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 persson 2187 #endif
183 persson 2185
184 persson 2316 #ifdef WIN32
185     int InstrumentManagerThread::StopThread() {
186     int res = Thread::StopThread();
187     conditionJobsLeft.Reset();
188     return res;
189     }
190     #endif
191    
192 schoenebeck 947 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC