/[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 2349 - (hide 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 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 persson 2349 #ifdef __APPLE__
27     #include <sys/utsname.h>
28     #endif
29    
30 schoenebeck 947 namespace LinuxSampler {
31    
32     InstrumentManagerThread::InstrumentManagerThread() : Thread(true, false, 0, -4) {
33 iliev 1761 eventHandler.pThread = this;
34 schoenebeck 947 }
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 persson 1038 dmsg(1,("Scheduling '%s' (Index=%d) to be loaded in background (if not loaded yet).\n",Filename.c_str(),uiInstrumentIndex));
52 iliev 1761
53 persson 2324 // 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 iliev 1761
59 schoenebeck 947 command_t cmd;
60     cmd.type = command_t::DIRECT_LOAD;
61     cmd.pEngineChannel = pEngineChannel;
62 persson 2277 cmd.instrumentId.Index = uiInstrumentIndex;
63     cmd.instrumentId.FileName = Filename;
64 schoenebeck 989
65     mutex.Lock();
66     queue.push_back(cmd);
67     mutex.Unlock();
68    
69 schoenebeck 947 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 schoenebeck 989
92     mutex.Lock();
93     queue.push_back(cmd);
94     mutex.Unlock();
95    
96 schoenebeck 947 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 nagata 1649
104 persson 2185 #if CONFIG_PTHREAD_TESTCANCEL
105     TestCancel();
106     #endif
107 nagata 1649
108 persson 2324 while (true) {
109 schoenebeck 947 command_t cmd;
110 schoenebeck 989
111     // grab a new command from the queue
112     mutex.Lock();
113 persson 2324 bool empty = queue.empty();
114     if (!empty) {
115     cmd = queue.front();
116     queue.pop_front();
117 persson 2326
118     if (cmd.type == command_t::DIRECT_LOAD) {
119     EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, false);
120     }
121 persson 2324 }
122 schoenebeck 989 mutex.Unlock();
123 persson 2324 if (empty) break;
124 schoenebeck 989
125 schoenebeck 947 try {
126     switch (cmd.type) {
127     case command_t::DIRECT_LOAD:
128 persson 2277 cmd.pEngineChannel->PrepareLoadInstrument(cmd.instrumentId.FileName.c_str(), cmd.instrumentId.Index);
129 schoenebeck 947 cmd.pEngineChannel->LoadInstrument();
130 iliev 1826 EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
131 schoenebeck 947 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 schoenebeck 1040 } catch (Exception e) {
139 schoenebeck 947 e.PrintMessage();
140 iliev 1826 if (cmd.type == command_t::DIRECT_LOAD) {
141     EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
142     }
143 schoenebeck 1040 } catch (...) {
144     std::cerr << "InstrumentManagerThread: some exception occured, could not finish task\n" << std::flush;
145 iliev 1826 if (cmd.type == command_t::DIRECT_LOAD) {
146     EngineChannelFactory::SetDeleteEnabled(cmd.pEngineChannel, true);
147     }
148 schoenebeck 947 }
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 persson 1895 return 0;
159 schoenebeck 947 }
160 persson 1895
161 iliev 1761 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 persson 2185
181 persson 2187 #ifdef __APPLE__
182 persson 2185 int InstrumentManagerThread::StopThread() {
183 persson 2349 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 persson 2185 return Thread::StopThread(); // then wait for it to cancel
194     }
195 persson 2187 #endif
196 persson 2185
197 persson 2316 #ifdef WIN32
198     int InstrumentManagerThread::StopThread() {
199     int res = Thread::StopThread();
200     conditionJobsLeft.Reset();
201     return res;
202     }
203     #endif
204    
205 schoenebeck 947 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC