| @@ -5417,18 +5417,16 @@ void juce_CheckForDanglingStreams() | |||
| OutputStream::OutputStream() throw() | |||
| { | |||
| #if JUCE_DEBUG | |||
| activeStreamLock.enter(); | |||
| const ScopedLock sl (activeStreamLock); | |||
| activeStreams.add (this); | |||
| activeStreamLock.exit(); | |||
| #endif | |||
| } | |||
| OutputStream::~OutputStream() | |||
| { | |||
| #if JUCE_DEBUG | |||
| activeStreamLock.enter(); | |||
| const ScopedLock sl (activeStreamLock); | |||
| activeStreams.removeValue (this); | |||
| activeStreamLock.exit(); | |||
| #endif | |||
| } | |||
| @@ -15373,9 +15371,6 @@ void juce_setCurrentThreadName (const String& name); | |||
| void juce_CloseThreadHandle (void* handle); | |||
| #endif | |||
| static VoidArray runningThreads; | |||
| static CriticalSection runningThreadsLock; | |||
| void Thread::threadEntryPoint (Thread* const thread) | |||
| { | |||
| { | |||
| @@ -15573,7 +15568,7 @@ Thread* Thread::getCurrentThread() | |||
| for (int i = runningThreads.size(); --i >= 0;) | |||
| { | |||
| Thread* const t = (Thread*) runningThreads.getUnchecked(i); | |||
| Thread* const t = runningThreads.getUnchecked(i); | |||
| if (t->threadId_ == thisId) | |||
| return t; | |||
| @@ -15588,22 +15583,28 @@ void Thread::stopAllThreads (const int timeOutMilliseconds) | |||
| const ScopedLock sl (runningThreadsLock); | |||
| for (int i = runningThreads.size(); --i >= 0;) | |||
| ((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit(); | |||
| runningThreads.getUnchecked(i)->signalThreadShouldExit(); | |||
| } | |||
| for (;;) | |||
| { | |||
| runningThreadsLock.enter(); | |||
| Thread* const t = (Thread*) runningThreads[0]; | |||
| runningThreadsLock.exit(); | |||
| Thread* firstThread; | |||
| { | |||
| const ScopedLock sl (runningThreadsLock); | |||
| firstThread = runningThreads.getFirst(); | |||
| } | |||
| if (t == 0) | |||
| if (firstThread == 0) | |||
| break; | |||
| t->stopThread (timeOutMilliseconds); | |||
| firstThread->stopThread (timeOutMilliseconds); | |||
| } | |||
| } | |||
| Array<Thread*> Thread::runningThreads; | |||
| CriticalSection Thread::runningThreadsLock; | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_Thread.cpp ***/ | |||
| @@ -15796,9 +15797,11 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| const bool interruptIfRunning, | |||
| const int timeOutMs) | |||
| { | |||
| bool dontWait = true; | |||
| if (job != 0) | |||
| { | |||
| lock.enter(); | |||
| const ScopedLock sl (lock); | |||
| if (jobs.contains (job)) | |||
| { | |||
| @@ -15807,20 +15810,16 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| if (interruptIfRunning) | |||
| job->signalJobShouldExit(); | |||
| lock.exit(); | |||
| return waitForJobToFinish (job, timeOutMs); | |||
| dontWait = false; | |||
| } | |||
| else | |||
| { | |||
| jobs.removeValue (job); | |||
| } | |||
| } | |||
| lock.exit(); | |||
| } | |||
| return true; | |||
| return dontWait || waitForJobToFinish (job, timeOutMs); | |||
| } | |||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| @@ -18016,9 +18015,12 @@ void DeletedAtShutdown::deleteAll() | |||
| { | |||
| // make a local copy of the array, so it can't get into a loop if something | |||
| // creates another DeletedAtShutdown object during its destructor. | |||
| lock.enter(); | |||
| const VoidArray localCopy (objectsToDelete); | |||
| lock.exit(); | |||
| VoidArray localCopy; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| localCopy = objectsToDelete; | |||
| } | |||
| for (int i = localCopy.size(); --i >= 0;) | |||
| { | |||
| @@ -22950,11 +22952,12 @@ void AudioTransportSource::start() | |||
| { | |||
| if ((! playing) && masterSource != 0) | |||
| { | |||
| callbackLock.enter(); | |||
| playing = true; | |||
| stopped = false; | |||
| inputStreamEOF = false; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| playing = true; | |||
| stopped = false; | |||
| inputStreamEOF = false; | |||
| } | |||
| sendChangeMessage (this); | |||
| } | |||
| @@ -22964,9 +22967,10 @@ void AudioTransportSource::stop() | |||
| { | |||
| if (playing) | |||
| { | |||
| callbackLock.enter(); | |||
| playing = false; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| playing = false; | |||
| } | |||
| int n = 500; | |||
| while (--n >= 0 && ! stopped) | |||
| @@ -23350,45 +23354,47 @@ void BufferingAudioSource::setNextReadPosition (int newPosition) | |||
| bool BufferingAudioSource::readNextBufferChunk() | |||
| { | |||
| bufferStartPosLock.enter(); | |||
| int newBVS, newBVE, sectionToReadStart, sectionToReadEnd; | |||
| if (wasSourceLooping != isLooping()) | |||
| { | |||
| wasSourceLooping = isLooping(); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| const ScopedLock sl (bufferStartPosLock); | |||
| int newBVS = jmax (0, nextPlayPos); | |||
| int newBVE = newBVS + buffer.getNumSamples() - 4; | |||
| int sectionToReadStart = 0; | |||
| int sectionToReadEnd = 0; | |||
| if (wasSourceLooping != isLooping()) | |||
| { | |||
| wasSourceLooping = isLooping(); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| const int maxChunkSize = 2048; | |||
| newBVS = jmax (0, nextPlayPos); | |||
| newBVE = newBVS + buffer.getNumSamples() - 4; | |||
| sectionToReadStart = 0; | |||
| sectionToReadEnd = 0; | |||
| if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) | |||
| { | |||
| newBVE = jmin (newBVE, newBVS + maxChunkSize); | |||
| const int maxChunkSize = 2048; | |||
| sectionToReadStart = newBVS; | |||
| sectionToReadEnd = newBVE; | |||
| if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) | |||
| { | |||
| newBVE = jmin (newBVE, newBVS + maxChunkSize); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| else if (abs (newBVS - bufferValidStart) > 512 | |||
| || abs (newBVE - bufferValidEnd) > 512) | |||
| { | |||
| newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize); | |||
| sectionToReadStart = newBVS; | |||
| sectionToReadEnd = newBVE; | |||
| sectionToReadStart = bufferValidEnd; | |||
| sectionToReadEnd = newBVE; | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| else if (abs (newBVS - bufferValidStart) > 512 | |||
| || abs (newBVE - bufferValidEnd) > 512) | |||
| { | |||
| newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize); | |||
| bufferValidStart = newBVS; | |||
| bufferValidEnd = jmin (bufferValidEnd, newBVE); | |||
| } | |||
| sectionToReadStart = bufferValidEnd; | |||
| sectionToReadEnd = newBVE; | |||
| bufferStartPosLock.exit(); | |||
| bufferValidStart = newBVS; | |||
| bufferValidEnd = jmin (bufferValidEnd, newBVE); | |||
| } | |||
| } | |||
| if (sectionToReadStart != sectionToReadEnd) | |||
| { | |||
| @@ -23696,10 +23702,14 @@ void MixerAudioSource::addInputSource (AudioSource* input, const bool deleteWhen | |||
| { | |||
| if (input != 0 && ! inputs.contains (input)) | |||
| { | |||
| lock.enter(); | |||
| double localRate = currentSampleRate; | |||
| int localBufferSize = bufferSizeExpected; | |||
| lock.exit(); | |||
| double localRate; | |||
| int localBufferSize; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| localRate = currentSampleRate; | |||
| localBufferSize = bufferSizeExpected; | |||
| } | |||
| if (localRate != 0.0) | |||
| input->prepareToPlay (localBufferSize, localRate); | |||
| @@ -23715,16 +23725,19 @@ void MixerAudioSource::removeInputSource (AudioSource* input, const bool deleteI | |||
| { | |||
| if (input != 0) | |||
| { | |||
| lock.enter(); | |||
| const int index = inputs.indexOf ((void*) input); | |||
| int index; | |||
| if (index >= 0) | |||
| { | |||
| inputsToDelete.shiftBits (index, 1); | |||
| inputs.remove (index); | |||
| } | |||
| const ScopedLock sl (lock); | |||
| lock.exit(); | |||
| index = inputs.indexOf ((void*) input); | |||
| if (index >= 0) | |||
| { | |||
| inputsToDelete.shiftBits (index, 1); | |||
| inputs.remove (index); | |||
| } | |||
| } | |||
| if (index >= 0) | |||
| { | |||
| @@ -23738,11 +23751,14 @@ void MixerAudioSource::removeInputSource (AudioSource* input, const bool deleteI | |||
| void MixerAudioSource::removeAllInputs() | |||
| { | |||
| lock.enter(); | |||
| VoidArray inputsCopy (inputs); | |||
| BitArray inputsToDeleteCopy (inputsToDelete); | |||
| inputs.clear(); | |||
| lock.exit(); | |||
| VoidArray inputsCopy; | |||
| BitArray inputsToDeleteCopy; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| inputsCopy = inputs; | |||
| inputsToDeleteCopy = inputsToDelete; | |||
| } | |||
| for (int i = inputsCopy.size(); --i >= 0;) | |||
| if (inputsToDeleteCopy[i]) | |||
| @@ -24987,10 +25003,13 @@ void AudioDeviceManager::CallbackHandler::handleIncomingMidiMessage (MidiInput* | |||
| void AudioDeviceManager::playTestSound() | |||
| { | |||
| { | |||
| audioCallbackLock.enter(); | |||
| ScopedPointer <AudioSampleBuffer> oldSound (testSound); | |||
| audioCallbackLock.exit(); | |||
| { // cunningly nested to swap, unlock and delete in that order. | |||
| ScopedPointer <AudioSampleBuffer> oldSound; | |||
| { | |||
| const ScopedLock sl (audioCallbackLock); | |||
| oldSound = testSound; | |||
| } | |||
| } | |||
| testSoundPosition = 0; | |||
| @@ -25179,26 +25198,28 @@ void MidiOutput::run() | |||
| uint32 eventTime = 0; | |||
| uint32 timeToWait = 500; | |||
| lock.enter(); | |||
| PendingMessage* message = firstMessage; | |||
| PendingMessage* message; | |||
| if (message != 0) | |||
| { | |||
| eventTime = roundToInt (message->message.getTimeStamp()); | |||
| const ScopedLock sl (lock); | |||
| message = firstMessage; | |||
| if (eventTime > now + 20) | |||
| { | |||
| timeToWait = eventTime - (now + 20); | |||
| message = 0; | |||
| } | |||
| else | |||
| if (message != 0) | |||
| { | |||
| firstMessage = message->next; | |||
| eventTime = roundToInt (message->message.getTimeStamp()); | |||
| if (eventTime > now + 20) | |||
| { | |||
| timeToWait = eventTime - (now + 20); | |||
| message = 0; | |||
| } | |||
| else | |||
| { | |||
| firstMessage = message->next; | |||
| } | |||
| } | |||
| } | |||
| lock.exit(); | |||
| if (message != 0) | |||
| { | |||
| if (eventTime > now) | |||
| @@ -34679,9 +34700,12 @@ void AudioProcessor::sendParamChangeMessageToListeners (const int parameterIndex | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChanged (this, parameterIndex, newValue); | |||
| @@ -34701,9 +34725,12 @@ void AudioProcessor::beginParameterChangeGesture (int parameterIndex) | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChangeGestureBegin (this, parameterIndex); | |||
| @@ -34724,9 +34751,12 @@ void AudioProcessor::endParameterChangeGesture (int parameterIndex) | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChangeGestureEnd (this, parameterIndex); | |||
| @@ -34737,9 +34767,12 @@ void AudioProcessor::updateHostDisplay() | |||
| { | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorChanged (this); | |||
| @@ -36211,11 +36244,14 @@ void AudioProcessorPlayer::setProcessor (AudioProcessor* const processorToPlay) | |||
| processorToPlay->prepareToPlay (sampleRate, blockSize); | |||
| } | |||
| lock.enter(); | |||
| AudioProcessor* const oldOne = isPrepared ? processor : 0; | |||
| processor = processorToPlay; | |||
| isPrepared = true; | |||
| lock.exit(); | |||
| AudioProcessor* oldOne; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| oldOne = isPrepared ? processor : 0; | |||
| processor = processorToPlay; | |||
| isPrepared = true; | |||
| } | |||
| if (oldOne != 0) | |||
| oldOne->releaseResources(); | |||
| @@ -37963,25 +37999,24 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw() | |||
| return thisThread == messageThreadId || thisThread == threadWithLock; | |||
| } | |||
| class SharedLockingEvents : public ReferenceCountedObject | |||
| class MessageManagerLock::SharedEvents : public ReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedLockingEvents() throw() {} | |||
| ~SharedLockingEvents() {} | |||
| SharedEvents() {} | |||
| ~SharedEvents() {} | |||
| WaitableEvent lockedEvent, releaseEvent; | |||
| private: | |||
| SharedEvents (const SharedEvents&); | |||
| SharedEvents& operator= (const SharedEvents&); | |||
| }; | |||
| class MMLockMessage : public CallbackMessage | |||
| class MessageManagerLock::BlockingMessage : public CallbackMessage | |||
| { | |||
| public: | |||
| MMLockMessage (SharedLockingEvents* const events_) throw() | |||
| : events (events_) | |||
| {} | |||
| ~MMLockMessage() throw() {} | |||
| ReferenceCountedObjectPtr <SharedLockingEvents> events; | |||
| BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} | |||
| ~BlockingMessage() throw() {} | |||
| void messageCallback() | |||
| { | |||
| @@ -37991,20 +38026,23 @@ public: | |||
| juce_UseDebuggingNewOperator | |||
| MMLockMessage (const MMLockMessage&); | |||
| const MMLockMessage& operator= (const MMLockMessage&); | |||
| private: | |||
| ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events; | |||
| BlockingMessage (const BlockingMessage&); | |||
| BlockingMessage& operator= (const BlockingMessage&); | |||
| }; | |||
| MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) throw() | |||
| : locked (false), | |||
| needsUnlocking (false) | |||
| : sharedEvents (0), | |||
| locked (false) | |||
| { | |||
| init (threadToCheck, 0); | |||
| } | |||
| MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw() | |||
| : locked (false), | |||
| needsUnlocking (false) | |||
| : sharedEvents (0), | |||
| locked (false) | |||
| { | |||
| init (0, jobToCheckForExitSignal); | |||
| } | |||
| @@ -38035,19 +38073,19 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| } | |||
| } | |||
| SharedLockingEvents* const events = new SharedLockingEvents(); | |||
| sharedEvents = events; | |||
| events->incReferenceCount(); | |||
| sharedEvents = new SharedEvents(); | |||
| sharedEvents->incReferenceCount(); | |||
| (new MMLockMessage (events))->post(); | |||
| (new BlockingMessage (sharedEvents))->post(); | |||
| while (! events->lockedEvent.wait (50)) | |||
| while (! sharedEvents->lockedEvent.wait (50)) | |||
| { | |||
| if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | |||
| || (job != 0 && job->shouldExit())) | |||
| { | |||
| events->releaseEvent.signal(); | |||
| events->decReferenceCount(); | |||
| sharedEvents->releaseEvent.signal(); | |||
| sharedEvents->decReferenceCount(); | |||
| sharedEvents = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| return; | |||
| } | |||
| @@ -38057,21 +38095,24 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); | |||
| locked = true; | |||
| needsUnlocking = true; | |||
| } | |||
| } | |||
| } | |||
| MessageManagerLock::~MessageManagerLock() throw() | |||
| { | |||
| if (needsUnlocking && MessageManager::instance != 0) | |||
| if (sharedEvents != 0) | |||
| { | |||
| jassert (MessageManager::instance->currentThreadHasLockedMessageManager()); | |||
| jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | |||
| sharedEvents->releaseEvent.signal(); | |||
| sharedEvents->decReferenceCount(); | |||
| ((SharedLockingEvents*) sharedEvents)->releaseEvent.signal(); | |||
| ((SharedLockingEvents*) sharedEvents)->decReferenceCount(); | |||
| MessageManager::instance->threadWithLock = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| if (MessageManager::instance != 0) | |||
| { | |||
| MessageManager::instance->threadWithLock = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| } | |||
| } | |||
| } | |||
| @@ -38228,11 +38269,15 @@ public: | |||
| const int elapsed = now - lastTime; | |||
| lastTime = now; | |||
| lock.enter(); | |||
| decrementAllCounters (elapsed); | |||
| const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs | |||
| : 1000; | |||
| lock.exit(); | |||
| int timeUntilFirstTimer = 1000; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| decrementAllCounters (elapsed); | |||
| if (firstTimer != 0) | |||
| timeUntilFirstTimer = firstTimer->countdownMs; | |||
| } | |||
| if (timeUntilFirstTimer <= 0) | |||
| { | |||
| @@ -56299,16 +56344,19 @@ void TreeViewItem::addSubItem (TreeViewItem* const newItem, const int insertPosi | |||
| void TreeViewItem::removeSubItem (const int index, const bool deleteItem) | |||
| { | |||
| if (ownerView != 0) | |||
| ownerView->nodeAlterationLock.enter(); | |||
| { | |||
| const ScopedLock sl (ownerView->nodeAlterationLock); | |||
| if (((unsigned int) index) < (unsigned int) subItems.size()) | |||
| if (((unsigned int) index) < (unsigned int) subItems.size()) | |||
| { | |||
| subItems.remove (index, deleteItem); | |||
| treeHasChanged(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| subItems.remove (index, deleteItem); | |||
| treeHasChanged(); | |||
| } | |||
| if (ownerView != 0) | |||
| ownerView->nodeAlterationLock.exit(); | |||
| } | |||
| bool TreeViewItem::isOpen() const throw() | |||
| @@ -222335,24 +222383,25 @@ public: | |||
| return; | |||
| const int numBytes = MidiMessage::getMessageLengthFromFirstByte ((uint8) byte); | |||
| const double time = timeStampToTime (timeStamp); | |||
| lock.enter(); | |||
| if (pendingLength < midiBufferSize - 12) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = numBytes; | |||
| *(uint32*) (p + 12) = message; | |||
| pendingLength += 12 + numBytes; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| const ScopedLock sl (lock); | |||
| if (pendingLength < midiBufferSize - 12) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = numBytes; | |||
| *(uint32*) (p + 12) = message; | |||
| pendingLength += 12 + numBytes; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| } | |||
| } | |||
| lock.exit(); | |||
| notify(); | |||
| } | |||
| @@ -222364,22 +222413,23 @@ public: | |||
| { | |||
| const double time = timeStampToTime (timeStamp); | |||
| lock.enter(); | |||
| if (pendingLength < midiBufferSize - (8 + num)) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = num; | |||
| memcpy (p + 12, hdr->lpData, num); | |||
| pendingLength += 12 + num; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| const ScopedLock sl (lock); | |||
| if (pendingLength < midiBufferSize - (8 + num)) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = num; | |||
| memcpy (p + 12, hdr->lpData, num); | |||
| pendingLength += 12 + num; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| } | |||
| } | |||
| lock.exit(); | |||
| notify(); | |||
| } | |||
| } | |||
| @@ -222410,20 +222460,22 @@ public: | |||
| } | |||
| } | |||
| lock.enter(); | |||
| int len; | |||
| int len = pendingLength; | |||
| if (len > 0) | |||
| { | |||
| pendingCopy.ensureSize (len); | |||
| pendingCopy.copyFrom (pending, 0, len); | |||
| pendingLength = 0; | |||
| } | |||
| const ScopedLock sl (lock); | |||
| lock.exit(); | |||
| len = pendingLength; | |||
| if (len > 0) | |||
| { | |||
| pendingCopy.ensureSize (len); | |||
| pendingCopy.copyFrom (pending, 0, len); | |||
| pendingLength = 0; | |||
| } | |||
| } | |||
| //xxx needs to figure out if blocks are broken up or not | |||
| //xxx needs to figure out if blocks are broken up or not | |||
| if (len == 0) | |||
| { | |||
| @@ -222487,8 +222539,7 @@ public: | |||
| activeMidiThreads.removeValue (this); | |||
| lock.enter(); | |||
| lock.exit(); | |||
| { const ScopedLock sl (lock); } | |||
| for (int i = numInHeaders; --i >= 0;) | |||
| { | |||
| @@ -242981,9 +243032,8 @@ public: | |||
| if (callback_ != 0) | |||
| callback_->audioDeviceAboutToStart (this); | |||
| callbackLock.enter(); | |||
| const ScopedLock sl (callbackLock); | |||
| callback = callback_; | |||
| callbackLock.exit(); | |||
| } | |||
| } | |||
| @@ -242991,10 +243041,13 @@ public: | |||
| { | |||
| if (isRunning) | |||
| { | |||
| callbackLock.enter(); | |||
| AudioIODeviceCallback* const lastCallback = callback; | |||
| callback = 0; | |||
| callbackLock.exit(); | |||
| AudioIODeviceCallback* lastCallback; | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| lastCallback = callback; | |||
| callback = 0; | |||
| } | |||
| if (lastCallback != 0) | |||
| lastCallback->audioDeviceStopped(); | |||
| @@ -243939,9 +243992,10 @@ MidiInput::~MidiInput() | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| mpc->active = false; | |||
| callbackLock.enter(); | |||
| activeCallbacks.removeValue (mpc); | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| activeCallbacks.removeValue (mpc); | |||
| } | |||
| if (mpc->portAndEndpoint->port != 0) | |||
| OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); | |||
| @@ -243952,16 +244006,14 @@ MidiInput::~MidiInput() | |||
| void MidiInput::start() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = true; | |||
| ((MidiPortAndCallback*) internal)->active = true; | |||
| } | |||
| void MidiInput::stop() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = false; | |||
| ((MidiPortAndCallback*) internal)->active = false; | |||
| } | |||
| #undef log | |||
| @@ -250475,9 +250527,10 @@ public: | |||
| void stop (bool leaveInterruptRunning) | |||
| { | |||
| callbackLock.enter(); | |||
| callback = 0; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| callback = 0; | |||
| } | |||
| if (started | |||
| && (deviceID != 0) | |||
| @@ -250493,8 +250546,7 @@ public: | |||
| #endif | |||
| started = false; | |||
| callbackLock.enter(); | |||
| callbackLock.exit(); | |||
| { const ScopedLock sl (callbackLock); } | |||
| // wait until it's definately stopped calling back.. | |||
| for (int i = 40; --i >= 0;) | |||
| @@ -250515,8 +250567,7 @@ public: | |||
| break; | |||
| } | |||
| callbackLock.enter(); | |||
| callbackLock.exit(); | |||
| const ScopedLock sl (callbackLock); | |||
| } | |||
| if (inputDevice != 0) | |||
| @@ -251850,9 +251901,10 @@ MidiInput::~MidiInput() | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| mpc->active = false; | |||
| callbackLock.enter(); | |||
| activeCallbacks.removeValue (mpc); | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| activeCallbacks.removeValue (mpc); | |||
| } | |||
| if (mpc->portAndEndpoint->port != 0) | |||
| OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); | |||
| @@ -251863,16 +251915,14 @@ MidiInput::~MidiInput() | |||
| void MidiInput::start() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = true; | |||
| ((MidiPortAndCallback*) internal)->active = true; | |||
| } | |||
| void MidiInput::stop() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = false; | |||
| ((MidiPortAndCallback*) internal)->active = false; | |||
| } | |||
| #undef log | |||
| @@ -128,11 +128,12 @@ void AudioTransportSource::start() | |||
| { | |||
| if ((! playing) && masterSource != 0) | |||
| { | |||
| callbackLock.enter(); | |||
| playing = true; | |||
| stopped = false; | |||
| inputStreamEOF = false; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| playing = true; | |||
| stopped = false; | |||
| inputStreamEOF = false; | |||
| } | |||
| sendChangeMessage (this); | |||
| } | |||
| @@ -142,9 +143,10 @@ void AudioTransportSource::stop() | |||
| { | |||
| if (playing) | |||
| { | |||
| callbackLock.enter(); | |||
| playing = false; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| playing = false; | |||
| } | |||
| int n = 500; | |||
| while (--n >= 0 && ! stopped) | |||
| @@ -269,45 +269,47 @@ void BufferingAudioSource::setNextReadPosition (int newPosition) | |||
| bool BufferingAudioSource::readNextBufferChunk() | |||
| { | |||
| bufferStartPosLock.enter(); | |||
| int newBVS, newBVE, sectionToReadStart, sectionToReadEnd; | |||
| if (wasSourceLooping != isLooping()) | |||
| { | |||
| wasSourceLooping = isLooping(); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| const ScopedLock sl (bufferStartPosLock); | |||
| int newBVS = jmax (0, nextPlayPos); | |||
| int newBVE = newBVS + buffer.getNumSamples() - 4; | |||
| int sectionToReadStart = 0; | |||
| int sectionToReadEnd = 0; | |||
| if (wasSourceLooping != isLooping()) | |||
| { | |||
| wasSourceLooping = isLooping(); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| const int maxChunkSize = 2048; | |||
| newBVS = jmax (0, nextPlayPos); | |||
| newBVE = newBVS + buffer.getNumSamples() - 4; | |||
| sectionToReadStart = 0; | |||
| sectionToReadEnd = 0; | |||
| if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) | |||
| { | |||
| newBVE = jmin (newBVE, newBVS + maxChunkSize); | |||
| const int maxChunkSize = 2048; | |||
| sectionToReadStart = newBVS; | |||
| sectionToReadEnd = newBVE; | |||
| if (newBVS < bufferValidStart || newBVS >= bufferValidEnd) | |||
| { | |||
| newBVE = jmin (newBVE, newBVS + maxChunkSize); | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| else if (abs (newBVS - bufferValidStart) > 512 | |||
| || abs (newBVE - bufferValidEnd) > 512) | |||
| { | |||
| newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize); | |||
| sectionToReadStart = newBVS; | |||
| sectionToReadEnd = newBVE; | |||
| sectionToReadStart = bufferValidEnd; | |||
| sectionToReadEnd = newBVE; | |||
| bufferValidStart = 0; | |||
| bufferValidEnd = 0; | |||
| } | |||
| else if (abs (newBVS - bufferValidStart) > 512 | |||
| || abs (newBVE - bufferValidEnd) > 512) | |||
| { | |||
| newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize); | |||
| bufferValidStart = newBVS; | |||
| bufferValidEnd = jmin (bufferValidEnd, newBVE); | |||
| } | |||
| sectionToReadStart = bufferValidEnd; | |||
| sectionToReadEnd = newBVE; | |||
| bufferStartPosLock.exit(); | |||
| bufferValidStart = newBVS; | |||
| bufferValidEnd = jmin (bufferValidEnd, newBVE); | |||
| } | |||
| } | |||
| if (sectionToReadStart != sectionToReadEnd) | |||
| { | |||
| @@ -49,10 +49,14 @@ void MixerAudioSource::addInputSource (AudioSource* input, const bool deleteWhen | |||
| { | |||
| if (input != 0 && ! inputs.contains (input)) | |||
| { | |||
| lock.enter(); | |||
| double localRate = currentSampleRate; | |||
| int localBufferSize = bufferSizeExpected; | |||
| lock.exit(); | |||
| double localRate; | |||
| int localBufferSize; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| localRate = currentSampleRate; | |||
| localBufferSize = bufferSizeExpected; | |||
| } | |||
| if (localRate != 0.0) | |||
| input->prepareToPlay (localBufferSize, localRate); | |||
| @@ -68,16 +72,19 @@ void MixerAudioSource::removeInputSource (AudioSource* input, const bool deleteI | |||
| { | |||
| if (input != 0) | |||
| { | |||
| lock.enter(); | |||
| const int index = inputs.indexOf ((void*) input); | |||
| int index; | |||
| if (index >= 0) | |||
| { | |||
| inputsToDelete.shiftBits (index, 1); | |||
| inputs.remove (index); | |||
| } | |||
| const ScopedLock sl (lock); | |||
| lock.exit(); | |||
| index = inputs.indexOf ((void*) input); | |||
| if (index >= 0) | |||
| { | |||
| inputsToDelete.shiftBits (index, 1); | |||
| inputs.remove (index); | |||
| } | |||
| } | |||
| if (index >= 0) | |||
| { | |||
| @@ -91,11 +98,14 @@ void MixerAudioSource::removeInputSource (AudioSource* input, const bool deleteI | |||
| void MixerAudioSource::removeAllInputs() | |||
| { | |||
| lock.enter(); | |||
| VoidArray inputsCopy (inputs); | |||
| BitArray inputsToDeleteCopy (inputsToDelete); | |||
| inputs.clear(); | |||
| lock.exit(); | |||
| VoidArray inputsCopy; | |||
| BitArray inputsToDeleteCopy; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| inputsCopy = inputs; | |||
| inputsToDeleteCopy = inputsToDelete; | |||
| } | |||
| for (int i = inputsCopy.size(); --i >= 0;) | |||
| if (inputsToDeleteCopy[i]) | |||
| @@ -919,10 +919,13 @@ void AudioDeviceManager::CallbackHandler::handleIncomingMidiMessage (MidiInput* | |||
| //============================================================================== | |||
| void AudioDeviceManager::playTestSound() | |||
| { | |||
| { | |||
| audioCallbackLock.enter(); | |||
| ScopedPointer <AudioSampleBuffer> oldSound (testSound); | |||
| audioCallbackLock.exit(); | |||
| { // cunningly nested to swap, unlock and delete in that order. | |||
| ScopedPointer <AudioSampleBuffer> oldSound; | |||
| { | |||
| const ScopedLock sl (audioCallbackLock); | |||
| oldSound = testSound; | |||
| } | |||
| } | |||
| testSoundPosition = 0; | |||
| @@ -123,26 +123,28 @@ void MidiOutput::run() | |||
| uint32 eventTime = 0; | |||
| uint32 timeToWait = 500; | |||
| lock.enter(); | |||
| PendingMessage* message = firstMessage; | |||
| PendingMessage* message; | |||
| if (message != 0) | |||
| { | |||
| eventTime = roundToInt (message->message.getTimeStamp()); | |||
| const ScopedLock sl (lock); | |||
| message = firstMessage; | |||
| if (eventTime > now + 20) | |||
| { | |||
| timeToWait = eventTime - (now + 20); | |||
| message = 0; | |||
| } | |||
| else | |||
| if (message != 0) | |||
| { | |||
| firstMessage = message->next; | |||
| eventTime = roundToInt (message->message.getTimeStamp()); | |||
| if (eventTime > now + 20) | |||
| { | |||
| timeToWait = eventTime - (now + 20); | |||
| message = 0; | |||
| } | |||
| else | |||
| { | |||
| firstMessage = message->next; | |||
| } | |||
| } | |||
| } | |||
| lock.exit(); | |||
| if (message != 0) | |||
| { | |||
| if (eventTime > now) | |||
| @@ -114,9 +114,12 @@ void AudioProcessor::sendParamChangeMessageToListeners (const int parameterIndex | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChanged (this, parameterIndex, newValue); | |||
| @@ -136,9 +139,12 @@ void AudioProcessor::beginParameterChangeGesture (int parameterIndex) | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChangeGestureBegin (this, parameterIndex); | |||
| @@ -159,9 +165,12 @@ void AudioProcessor::endParameterChangeGesture (int parameterIndex) | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorParameterChangeGestureEnd (this, parameterIndex); | |||
| @@ -172,9 +181,12 @@ void AudioProcessor::updateHostDisplay() | |||
| { | |||
| for (int i = listeners.size(); --i >= 0;) | |||
| { | |||
| listenerLock.enter(); | |||
| AudioProcessorListener* const l = (AudioProcessorListener*) listeners [i]; | |||
| listenerLock.exit(); | |||
| AudioProcessorListener* l; | |||
| { | |||
| const ScopedLock sl (listenerLock); | |||
| l = (AudioProcessorListener*) listeners [i]; | |||
| } | |||
| if (l != 0) | |||
| l->audioProcessorChanged (this); | |||
| @@ -61,11 +61,14 @@ void AudioProcessorPlayer::setProcessor (AudioProcessor* const processorToPlay) | |||
| processorToPlay->prepareToPlay (sampleRate, blockSize); | |||
| } | |||
| lock.enter(); | |||
| AudioProcessor* const oldOne = isPrepared ? processor : 0; | |||
| processor = processorToPlay; | |||
| isPrepared = true; | |||
| lock.exit(); | |||
| AudioProcessor* oldOne; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| oldOne = isPrepared ? processor : 0; | |||
| processor = processorToPlay; | |||
| isPrepared = true; | |||
| } | |||
| if (oldOne != 0) | |||
| oldOne->releaseResources(); | |||
| @@ -72,14 +72,12 @@ public: | |||
| */ | |||
| Array (const Array<ElementType, TypeOfCriticalSectionToUse>& other) | |||
| { | |||
| other.lockArray(); | |||
| const ScopedLockType lock (other.getLock()); | |||
| numUsed = other.numUsed; | |||
| data.setAllocatedSize (other.numUsed); | |||
| for (int i = 0; i < numUsed; ++i) | |||
| new (data.elements + i) ElementType (other.data.elements[i]); | |||
| other.unlockArray(); | |||
| } | |||
| /** Initalises from a null-terminated C array of values. | |||
| @@ -117,7 +115,7 @@ public: | |||
| /** Copies another array. | |||
| @param other the array to copy | |||
| */ | |||
| Array <ElementType, TypeOfCriticalSectionToUse>& operator= (const Array <ElementType, TypeOfCriticalSectionToUse>& other) | |||
| Array& operator= (const Array& other) | |||
| { | |||
| if (this != &other) | |||
| { | |||
| @@ -137,24 +135,15 @@ public: | |||
| template <class OtherArrayType> | |||
| bool operator== (const OtherArrayType& other) const | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (numUsed != other.numUsed) | |||
| { | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (data.elements [i] != other.data.elements [i]) | |||
| { | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| } | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| @@ -179,14 +168,13 @@ public: | |||
| */ | |||
| void clear() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| for (int i = 0; i < numUsed; ++i) | |||
| data.elements[i].~ElementType(); | |||
| data.setAllocatedSize (0); | |||
| numUsed = 0; | |||
| data.exit(); | |||
| } | |||
| /** Removes all elements from the array without freeing the array's allocated storage. | |||
| @@ -195,13 +183,12 @@ public: | |||
| */ | |||
| void clearQuick() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| for (int i = 0; i < numUsed; ++i) | |||
| data.elements[i].~ElementType(); | |||
| numUsed = 0; | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -224,13 +211,9 @@ public: | |||
| */ | |||
| inline ElementType operator[] (const int index) const | |||
| { | |||
| data.enter(); | |||
| const ElementType result ((((unsigned int) index) < (unsigned int) numUsed) | |||
| ? data.elements [index] | |||
| : ElementType()); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (((unsigned int) index) < (unsigned int) numUsed) ? data.elements [index] | |||
| : ElementType(); | |||
| } | |||
| /** Returns one of the elements in the array, without checking the index passed in. | |||
| @@ -244,12 +227,9 @@ public: | |||
| */ | |||
| inline const ElementType getUnchecked (const int index) const | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| const ElementType result (data.elements [index]); | |||
| data.exit(); | |||
| return result; | |||
| return data.elements [index]; | |||
| } | |||
| /** Returns a direct reference to one of the elements in the array, without checking the index passed in. | |||
| @@ -263,11 +243,9 @@ public: | |||
| */ | |||
| inline ElementType& getReference (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| ElementType& result = data.elements [index]; | |||
| data.exit(); | |||
| return result; | |||
| return data.elements [index]; | |||
| } | |||
| /** Returns the first element in the array, or 0 if the array is empty. | |||
| @@ -276,12 +254,9 @@ public: | |||
| */ | |||
| inline ElementType getFirst() const | |||
| { | |||
| data.enter(); | |||
| const ElementType result ((numUsed > 0) ? data.elements [0] | |||
| : ElementType()); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (numUsed > 0) ? data.elements [0] | |||
| : ElementType(); | |||
| } | |||
| /** Returns the last element in the array, or 0 if the array is empty. | |||
| @@ -290,12 +265,9 @@ public: | |||
| */ | |||
| inline ElementType getLast() const | |||
| { | |||
| data.enter(); | |||
| const ElementType result ((numUsed > 0) ? data.elements [numUsed - 1] | |||
| : ElementType()); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (numUsed > 0) ? data.elements [numUsed - 1] | |||
| : ElementType(); | |||
| } | |||
| //============================================================================== | |||
| @@ -309,24 +281,18 @@ public: | |||
| */ | |||
| int indexOf (const ElementType& elementToLookFor) const | |||
| { | |||
| int result = -1; | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const ElementType* e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (elementToLookFor == *e) | |||
| { | |||
| result = (int) (e - data.elements); | |||
| break; | |||
| } | |||
| return (int) (e - data.elements); | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return result; | |||
| return -1; | |||
| } | |||
| /** Returns true if the array contains at least one occurrence of an object. | |||
| @@ -336,24 +302,19 @@ public: | |||
| */ | |||
| bool contains (const ElementType& elementToLookFor) const | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const ElementType* e = data.elements; | |||
| int num = numUsed; | |||
| while (num > 0) | |||
| { | |||
| if (elementToLookFor == *e) | |||
| { | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| --num; | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| @@ -365,10 +326,9 @@ public: | |||
| */ | |||
| void add (const ElementType& newElement) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| new (data.elements + numUsed++) ElementType (newElement); | |||
| data.exit(); | |||
| } | |||
| /** Inserts a new element into the array at a given position. | |||
| @@ -385,7 +345,7 @@ public: | |||
| */ | |||
| void insert (int indexToInsertAt, const ElementType& newElement) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) | |||
| @@ -403,8 +363,6 @@ public: | |||
| { | |||
| new (data.elements + numUsed++) ElementType (newElement); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Inserts multiple copies of an element into the array at a given position. | |||
| @@ -424,7 +382,7 @@ public: | |||
| { | |||
| if (numberOfTimesToInsertIt > 0) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt); | |||
| ElementType* insertPos; | |||
| @@ -443,8 +401,6 @@ public: | |||
| while (--numberOfTimesToInsertIt >= 0) | |||
| new (insertPos++) ElementType (newElement); | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -466,7 +422,7 @@ public: | |||
| { | |||
| if (numberOfElements > 0) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + numberOfElements); | |||
| ElementType* insertPos; | |||
| @@ -485,8 +441,6 @@ public: | |||
| while (--numberOfElements >= 0) | |||
| new (insertPos++) ElementType (*newElements++); | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -500,12 +454,10 @@ public: | |||
| */ | |||
| void addIfNotAlreadyThere (const ElementType& newElement) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (! contains (newElement)) | |||
| add (newElement); | |||
| data.exit(); | |||
| } | |||
| /** Replaces an element with a new value. | |||
| @@ -520,8 +472,7 @@ public: | |||
| void set (const int indexToChange, const ElementType& newValue) | |||
| { | |||
| jassert (indexToChange >= 0); | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) indexToChange) < (unsigned int) numUsed) | |||
| { | |||
| @@ -532,8 +483,6 @@ public: | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| new (data.elements + numUsed++) ElementType (newValue); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Replaces an element with a new value without doing any bounds-checking. | |||
| @@ -547,10 +496,9 @@ public: | |||
| */ | |||
| void setUnchecked (const int indexToChange, const ElementType& newValue) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) indexToChange) < (unsigned int) numUsed); | |||
| data.elements [indexToChange] = newValue; | |||
| data.exit(); | |||
| } | |||
| /** Adds elements from an array to the end of this array. | |||
| @@ -561,7 +509,7 @@ public: | |||
| */ | |||
| void addArray (const ElementType* elementsToAdd, int numElementsToAdd) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (numElementsToAdd > 0) | |||
| { | |||
| @@ -570,8 +518,6 @@ public: | |||
| while (--numElementsToAdd >= 0) | |||
| new (data.elements + numUsed++) ElementType (*elementsToAdd++); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** This swaps the contents of this array with those of another array. | |||
| @@ -579,14 +525,13 @@ public: | |||
| If you need to exchange two arrays, this is vastly quicker than using copy-by-value | |||
| because it just swaps their internal pointers. | |||
| */ | |||
| void swapWithArray (Array <ElementType>& otherArray) throw() | |||
| void swapWithArray (Array& otherArray) throw() | |||
| { | |||
| data.enter(); | |||
| otherArray.data.enter(); | |||
| const ScopedLockType lock1 (getLock()); | |||
| const ScopedLockType lock2 (otherArray.getLock()); | |||
| data.swapWith (otherArray.data); | |||
| swapVariables (numUsed, otherArray.numUsed); | |||
| otherArray.data.exit(); | |||
| data.exit(); | |||
| } | |||
| /** Adds elements from another array to the end of this array. | |||
| @@ -603,8 +548,8 @@ public: | |||
| int startIndex = 0, | |||
| int numElementsToAdd = -1) | |||
| { | |||
| arrayToAddFrom.lockArray(); | |||
| data.enter(); | |||
| const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| if (startIndex < 0) | |||
| { | |||
| @@ -617,9 +562,6 @@ public: | |||
| while (--numElementsToAdd >= 0) | |||
| add (arrayToAddFrom.getUnchecked (startIndex++)); | |||
| data.exit(); | |||
| arrayToAddFrom.unlockArray(); | |||
| } | |||
| /** Inserts a new element into the array, assuming that the array is sorted. | |||
| @@ -636,9 +578,8 @@ public: | |||
| template <class ElementComparator> | |||
| void addSorted (ElementComparator& comparator, const ElementType& newElement) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| insert (findInsertIndexInSortedArray (comparator, (ElementType*) data.elements, newElement, 0, numUsed), newElement); | |||
| data.exit(); | |||
| } | |||
| /** Finds the index of an element in the array, assuming that the array is sorted. | |||
| @@ -658,8 +599,8 @@ public: | |||
| { | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end = numUsed; | |||
| @@ -667,12 +608,10 @@ public: | |||
| { | |||
| if (start >= end) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (comparator.compareElements (elementToLookFor, data.elements [start]) == 0) | |||
| { | |||
| data.exit(); | |||
| return start; | |||
| } | |||
| else | |||
| @@ -680,10 +619,7 @@ public: | |||
| const int halfway = (start + end) >> 1; | |||
| if (halfway == start) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) | |||
| start = halfway; | |||
| else | |||
| @@ -705,7 +641,7 @@ public: | |||
| */ | |||
| ElementType remove (const int indexToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) indexToRemove) < (unsigned int) numUsed) | |||
| { | |||
| @@ -722,12 +658,10 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| data.exit(); | |||
| return removed; | |||
| } | |||
| else | |||
| { | |||
| data.exit(); | |||
| return ElementType(); | |||
| } | |||
| } | |||
| @@ -742,7 +676,7 @@ public: | |||
| */ | |||
| void removeValue (const ElementType& valueToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ElementType* e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| @@ -755,8 +689,6 @@ public: | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes a range of elements from the array. | |||
| @@ -773,7 +705,7 @@ public: | |||
| */ | |||
| void removeRange (int startIndex, int numberToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); | |||
| startIndex = jlimit (0, numUsed, startIndex); | |||
| @@ -794,8 +726,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes the last n elements from the array. | |||
| @@ -805,7 +735,7 @@ public: | |||
| */ | |||
| void removeLast (int howManyToRemove = 1) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (howManyToRemove > numUsed) | |||
| howManyToRemove = numUsed; | |||
| @@ -817,8 +747,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| data.exit(); | |||
| } | |||
| /** Removes any elements which are also in another array. | |||
| @@ -829,8 +757,8 @@ public: | |||
| template <class OtherArrayType> | |||
| void removeValuesIn (const OtherArrayType& otherArray) | |||
| { | |||
| otherArray.lockArray(); | |||
| data.enter(); | |||
| const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| if (this == &otherArray) | |||
| { | |||
| @@ -845,9 +773,6 @@ public: | |||
| remove (i); | |||
| } | |||
| } | |||
| data.exit(); | |||
| otherArray.unlockArray(); | |||
| } | |||
| /** Removes any elements which are not found in another array. | |||
| @@ -860,8 +785,8 @@ public: | |||
| template <class OtherArrayType> | |||
| void removeValuesNotIn (const OtherArrayType& otherArray) | |||
| { | |||
| otherArray.lockArray(); | |||
| data.enter(); | |||
| const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| if (this != &otherArray) | |||
| { | |||
| @@ -876,9 +801,6 @@ public: | |||
| remove (i); | |||
| } | |||
| } | |||
| data.exit(); | |||
| otherArray.unlockArray(); | |||
| } | |||
| /** Swaps over two elements in the array. | |||
| @@ -892,7 +814,7 @@ public: | |||
| void swap (const int index1, | |||
| const int index2) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) index1) < (unsigned int) numUsed | |||
| && ((unsigned int) index2) < (unsigned int) numUsed) | |||
| @@ -900,8 +822,6 @@ public: | |||
| swapVariables (data.elements [index1], | |||
| data.elements [index2]); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Moves one of the values to a different position. | |||
| @@ -922,7 +842,7 @@ public: | |||
| { | |||
| if (currentIndex != newIndex) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) currentIndex) < (unsigned int) numUsed) | |||
| { | |||
| @@ -947,8 +867,6 @@ public: | |||
| memcpy (data.elements + newIndex, tempCopy, sizeof (ElementType)); | |||
| } | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -961,9 +879,8 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.shrinkToNoMoreThan (numUsed); | |||
| data.exit(); | |||
| } | |||
| /** Increases the array's internal storage to hold a minimum number of elements. | |||
| @@ -974,9 +891,8 @@ public: | |||
| */ | |||
| void ensureStorageAllocated (const int minNumElements) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (minNumElements); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -1010,38 +926,21 @@ public: | |||
| void sort (ElementComparator& comparator, | |||
| const bool retainOrderOfEquivalentItems = false) const | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| sortArray (comparator, (ElementType*) data.elements, 0, size() - 1, retainOrderOfEquivalentItems); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Locks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see unlockArray | |||
| /** Returns the CriticalSection that locks this array. | |||
| To lock, you can call getLock().enter() and getLock().exit(), or preferably use | |||
| an object of ScopedLockType as an RAII lock for it. | |||
| */ | |||
| void lockArray() const throw() | |||
| { | |||
| data.enter(); | |||
| } | |||
| /** Unlocks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see lockArray | |||
| */ | |||
| void unlockArray() const throw() | |||
| { | |||
| data.exit(); | |||
| } | |||
| inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } | |||
| /** Returns the type of scoped lock to use for locking this array */ | |||
| typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -78,7 +78,7 @@ public: | |||
| /** Clears the array, optionally deleting the objects inside it first. */ | |||
| void clear (const bool deleteObjects = true) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (deleteObjects) | |||
| { | |||
| @@ -88,7 +88,6 @@ public: | |||
| data.setAllocatedSize (0); | |||
| numUsed = 0; | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -110,13 +109,9 @@ public: | |||
| */ | |||
| inline ObjectClass* operator[] (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| ObjectClass* const result = (((unsigned int) index) < (unsigned int) numUsed) | |||
| ? data.elements [index] | |||
| : (ObjectClass*) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (((unsigned int) index) < (unsigned int) numUsed) ? data.elements [index] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. | |||
| @@ -126,12 +121,9 @@ public: | |||
| */ | |||
| inline ObjectClass* getUnchecked (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| ObjectClass* const result = data.elements [index]; | |||
| data.exit(); | |||
| return result; | |||
| return data.elements [index]; | |||
| } | |||
| /** Returns a pointer to the first object in the array. | |||
| @@ -141,11 +133,9 @@ public: | |||
| */ | |||
| inline ObjectClass* getFirst() const throw() | |||
| { | |||
| data.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? data.elements [0] | |||
| : (ObjectClass*) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [0] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| /** Returns a pointer to the last object in the array. | |||
| @@ -155,12 +145,9 @@ public: | |||
| */ | |||
| inline ObjectClass* getLast() const throw() | |||
| { | |||
| data.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? data.elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| //============================================================================== | |||
| @@ -171,24 +158,18 @@ public: | |||
| */ | |||
| int indexOf (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| int result = -1; | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ObjectClass* const* e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| { | |||
| result = (int) (e - data.elements); | |||
| break; | |||
| } | |||
| return (int) (e - data.elements); | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return result; | |||
| return -1; | |||
| } | |||
| /** Returns true if the array contains a specified object. | |||
| @@ -198,8 +179,7 @@ public: | |||
| */ | |||
| bool contains (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ObjectClass* const* e = data.elements; | |||
| int i = numUsed; | |||
| @@ -210,7 +190,6 @@ public: | |||
| || objectToLookFor == *++e | |||
| || objectToLookFor == *++e) | |||
| { | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| @@ -221,16 +200,12 @@ public: | |||
| while (i > 0) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| { | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| --i; | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| @@ -248,10 +223,9 @@ public: | |||
| */ | |||
| void add (const ObjectClass* const newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| data.elements [numUsed++] = const_cast <ObjectClass*> (newObject); | |||
| data.exit(); | |||
| } | |||
| /** Inserts a new object into the array at the given index. | |||
| @@ -276,7 +250,7 @@ public: | |||
| { | |||
| if (indexToInsertAt >= 0) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (indexToInsertAt > numUsed) | |||
| indexToInsertAt = numUsed; | |||
| @@ -291,8 +265,6 @@ public: | |||
| *e = const_cast <ObjectClass*> (newObject); | |||
| ++numUsed; | |||
| data.exit(); | |||
| } | |||
| else | |||
| { | |||
| @@ -309,12 +281,10 @@ public: | |||
| */ | |||
| void addIfNotAlreadyThere (const ObjectClass* const newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (! contains (newObject)) | |||
| add (newObject); | |||
| data.exit(); | |||
| } | |||
| /** Replaces an object in the array with a different one. | |||
| @@ -337,7 +307,7 @@ public: | |||
| if (indexToChange >= 0) | |||
| { | |||
| ScopedPointer <ObjectClass> toDelete; | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (indexToChange < numUsed) | |||
| { | |||
| @@ -356,8 +326,6 @@ public: | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| data.elements [numUsed++] = const_cast <ObjectClass*> (newObject); | |||
| } | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -378,9 +346,8 @@ public: | |||
| { | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| insert (findInsertIndexInSortedArray (comparator, (ObjectClass**) data.elements, newObject, 0, numUsed), newObject); | |||
| data.exit(); | |||
| } | |||
| /** Finds the index of an object in the array, assuming that the array is sorted. | |||
| @@ -401,7 +368,7 @@ public: | |||
| { | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end = numUsed; | |||
| @@ -410,12 +377,10 @@ public: | |||
| { | |||
| if (start >= end) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (comparator.compareElements (objectToLookFor, data.elements [start]) == 0) | |||
| { | |||
| data.exit(); | |||
| return start; | |||
| } | |||
| else | |||
| @@ -423,10 +388,7 @@ public: | |||
| const int halfway = (start + end) >> 1; | |||
| if (halfway == start) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0) | |||
| start = halfway; | |||
| else | |||
| @@ -450,7 +412,7 @@ public: | |||
| const bool deleteObject = true) | |||
| { | |||
| ScopedPointer <ObjectClass> toDelete; | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) indexToRemove) < (unsigned int) numUsed) | |||
| { | |||
| @@ -468,8 +430,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes a specified object from the array. | |||
| @@ -483,7 +443,7 @@ public: | |||
| void removeObject (const ObjectClass* const objectToRemove, | |||
| const bool deleteObject = true) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ObjectClass** e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| @@ -496,8 +456,6 @@ public: | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes a range of objects from the array. | |||
| @@ -517,7 +475,7 @@ public: | |||
| const int numberToRemove, | |||
| const bool deleteObjects = true) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); | |||
| startIndex = jlimit (0, numUsed, startIndex); | |||
| @@ -546,8 +504,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes the last n objects from the array. | |||
| @@ -559,7 +515,7 @@ public: | |||
| void removeLast (int howManyToRemove = 1, | |||
| const bool deleteObjects = true) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (howManyToRemove >= numUsed) | |||
| { | |||
| @@ -570,8 +526,6 @@ public: | |||
| while (--howManyToRemove >= 0) | |||
| remove (numUsed - 1, deleteObjects); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Swaps a pair of objects in the array. | |||
| @@ -582,7 +536,7 @@ public: | |||
| void swap (const int index1, | |||
| const int index2) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) index1) < (unsigned int) numUsed | |||
| && ((unsigned int) index2) < (unsigned int) numUsed) | |||
| @@ -590,8 +544,6 @@ public: | |||
| swapVariables (data.elements [index1], | |||
| data.elements [index2]); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Moves one of the objects to a different position. | |||
| @@ -612,7 +564,7 @@ public: | |||
| { | |||
| if (currentIndex != newIndex) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) currentIndex) < (unsigned int) numUsed) | |||
| { | |||
| @@ -636,8 +588,6 @@ public: | |||
| data.elements [newIndex] = value; | |||
| } | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -646,14 +596,13 @@ public: | |||
| If you need to exchange two arrays, this is vastly quicker than using copy-by-value | |||
| because it just swaps their internal pointers. | |||
| */ | |||
| void swapWithArray (OwnedArray <ObjectClass>& otherArray) throw() | |||
| void swapWithArray (OwnedArray& otherArray) throw() | |||
| { | |||
| data.enter(); | |||
| otherArray.data.enter(); | |||
| const ScopedLockType lock1 (getLock()); | |||
| const ScopedLockType lock2 (otherArray.getLock()); | |||
| data.swapWith (otherArray.data); | |||
| swapVariables (numUsed, otherArray.numUsed); | |||
| otherArray.data.exit(); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -665,9 +614,8 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.shrinkToNoMoreThan (numUsed); | |||
| data.exit(); | |||
| } | |||
| /** Increases the array's internal storage to hold a minimum number of elements. | |||
| @@ -678,9 +626,8 @@ public: | |||
| */ | |||
| void ensureStorageAllocated (const int minNumElements) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (minNumElements); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -716,35 +663,19 @@ public: | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| sortArray (comparator, (ObjectClass**) data.elements, 0, size() - 1, retainOrderOfEquivalentItems); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Locks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see unlockArray | |||
| /** Returns the CriticalSection that locks this array. | |||
| To lock, you can call getLock().enter() and getLock().exit(), or preferably use | |||
| an object of ScopedLockType as an RAII lock for it. | |||
| */ | |||
| void lockArray() const throw() | |||
| { | |||
| data.enter(); | |||
| } | |||
| /** Unlocks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } | |||
| @see lockArray | |||
| */ | |||
| void unlockArray() const throw() | |||
| { | |||
| data.exit(); | |||
| } | |||
| /** Returns the type of scoped lock to use for locking this array */ | |||
| typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; | |||
| //============================================================================== | |||
| @@ -61,7 +61,7 @@ public: | |||
| /** Creates a copy of another array */ | |||
| ReferenceCountedArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) throw() | |||
| { | |||
| other.lockArray(); | |||
| const ScopedLockType lock (other.getLock()); | |||
| numUsed = other.numUsed; | |||
| data.setAllocatedSize (numUsed); | |||
| memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); | |||
| @@ -69,8 +69,6 @@ public: | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (data.elements[i] != 0) | |||
| data.elements[i]->incReferenceCount(); | |||
| other.unlockArray(); | |||
| } | |||
| /** Copies another array into this one. | |||
| @@ -104,7 +102,7 @@ public: | |||
| */ | |||
| void clear() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| while (numUsed > 0) | |||
| if (data.elements [--numUsed] != 0) | |||
| @@ -112,8 +110,6 @@ public: | |||
| jassert (numUsed == 0); | |||
| data.setAllocatedSize (0); | |||
| data.exit(); | |||
| } | |||
| /** Returns the current number of objects in the array. */ | |||
| @@ -132,12 +128,9 @@ public: | |||
| */ | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((((unsigned int) index) < (unsigned int) numUsed) | |||
| ? data.elements [index] | |||
| : (ObjectClass*) 0); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (((unsigned int) index) < (unsigned int) numUsed) ? data.elements [index] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. | |||
| @@ -147,11 +140,9 @@ public: | |||
| */ | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getUnchecked (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| const ReferenceCountedObjectPtr<ObjectClass> result (data.elements [index]); | |||
| data.exit(); | |||
| return result; | |||
| return data.elements [index]; | |||
| } | |||
| /** Returns a pointer to the first object in the array. | |||
| @@ -161,12 +152,9 @@ public: | |||
| */ | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw() | |||
| { | |||
| data.enter(); | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? data.elements [0] | |||
| : (ObjectClass*) 0); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [0] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| /** Returns a pointer to the last object in the array. | |||
| @@ -176,12 +164,9 @@ public: | |||
| */ | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw() | |||
| { | |||
| data.enter(); | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? data.elements [numUsed - 1] | |||
| : (ObjectClass*) 0); | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| } | |||
| //============================================================================== | |||
| @@ -192,24 +177,18 @@ public: | |||
| */ | |||
| int indexOf (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| int result = -1; | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ObjectClass** e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| { | |||
| result = (int) (e - data.elements); | |||
| break; | |||
| } | |||
| return (int) (e - data.elements); | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return result; | |||
| return -1; | |||
| } | |||
| /** Returns true if the array contains a specified object. | |||
| @@ -219,21 +198,17 @@ public: | |||
| */ | |||
| bool contains (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| ObjectClass** e = data.elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| { | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| ++e; | |||
| } | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| @@ -246,14 +221,12 @@ public: | |||
| */ | |||
| void add (ObjectClass* const newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| data.elements [numUsed++] = newObject; | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| data.exit(); | |||
| } | |||
| /** Inserts a new object into the array at the given index. | |||
| @@ -274,7 +247,7 @@ public: | |||
| { | |||
| if (indexToInsertAt >= 0) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (indexToInsertAt > numUsed) | |||
| indexToInsertAt = numUsed; | |||
| @@ -293,7 +266,6 @@ public: | |||
| newObject->incReferenceCount(); | |||
| ++numUsed; | |||
| data.exit(); | |||
| } | |||
| else | |||
| { | |||
| @@ -310,12 +282,9 @@ public: | |||
| */ | |||
| void addIfNotAlreadyThere (ObjectClass* const newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (! contains (newObject)) | |||
| add (newObject); | |||
| data.exit(); | |||
| } | |||
| /** Replaces an object in the array with a different one. | |||
| @@ -335,7 +304,7 @@ public: | |||
| { | |||
| if (indexToChange >= 0) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| @@ -352,8 +321,6 @@ public: | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| data.elements [numUsed++] = newObject; | |||
| } | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -371,7 +338,7 @@ public: | |||
| int numElementsToAdd = -1) throw() | |||
| { | |||
| arrayToAddFrom.lockArray(); | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (startIndex < 0) | |||
| { | |||
| @@ -390,7 +357,6 @@ public: | |||
| add (arrayToAddFrom.getUnchecked (startIndex++)); | |||
| } | |||
| data.exit(); | |||
| arrayToAddFrom.unlockArray(); | |||
| } | |||
| @@ -409,9 +375,8 @@ public: | |||
| void addSorted (ElementComparator& comparator, | |||
| ObjectClass* newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| insert (findInsertIndexInSortedArray (comparator, (ObjectClass**) data.elements, newObject, 0, numUsed), newObject); | |||
| data.exit(); | |||
| } | |||
| /** Inserts or replaces an object in the array, assuming it is sorted. | |||
| @@ -423,15 +388,13 @@ public: | |||
| void addOrReplaceSorted (ElementComparator& comparator, | |||
| ObjectClass* newObject) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const int index = findInsertIndexInSortedArray (comparator, (ObjectClass**) data.elements, newObject, 0, numUsed); | |||
| if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0) | |||
| set (index - 1, newObject); // replace an existing object that matches | |||
| else | |||
| insert (index, newObject); // no match, so insert the new one | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -450,7 +413,7 @@ public: | |||
| */ | |||
| void remove (const int indexToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) indexToRemove) < (unsigned int) numUsed) | |||
| { | |||
| @@ -468,8 +431,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes the first occurrence of a specified object from the array. | |||
| @@ -482,9 +443,8 @@ public: | |||
| */ | |||
| void removeObject (ObjectClass* const objectToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| remove (indexOf (objectToRemove)); | |||
| data.exit(); | |||
| } | |||
| /** Removes a range of objects from the array. | |||
| @@ -505,7 +465,7 @@ public: | |||
| void removeRange (const int startIndex, | |||
| const int numberToRemove) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| const int start = jlimit (0, numUsed, startIndex); | |||
| const int end = jlimit (0, numUsed, startIndex + numberToRemove); | |||
| @@ -536,8 +496,6 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Removes the last n objects from the array. | |||
| @@ -550,15 +508,13 @@ public: | |||
| */ | |||
| void removeLast (int howManyToRemove = 1) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (howManyToRemove > numUsed) | |||
| howManyToRemove = numUsed; | |||
| while (--howManyToRemove >= 0) | |||
| remove (numUsed - 1); | |||
| data.exit(); | |||
| } | |||
| /** Swaps a pair of objects in the array. | |||
| @@ -569,7 +525,7 @@ public: | |||
| void swap (const int index1, | |||
| const int index2) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) index1) < (unsigned int) numUsed | |||
| && ((unsigned int) index2) < (unsigned int) numUsed) | |||
| @@ -577,8 +533,6 @@ public: | |||
| swapVariables (data.elements [index1], | |||
| data.elements [index2]); | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Moves one of the objects to a different position. | |||
| @@ -599,7 +553,7 @@ public: | |||
| { | |||
| if (currentIndex != newIndex) | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) currentIndex) < (unsigned int) numUsed) | |||
| { | |||
| @@ -623,8 +577,6 @@ public: | |||
| data.elements [newIndex] = value; | |||
| } | |||
| data.exit(); | |||
| } | |||
| } | |||
| @@ -634,14 +586,13 @@ public: | |||
| If you need to exchange two arrays, this is vastly quicker than using copy-by-value | |||
| because it just swaps their internal pointers. | |||
| */ | |||
| void swapWithArray (ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& otherArray) throw() | |||
| void swapWithArray (ReferenceCountedArray& otherArray) throw() | |||
| { | |||
| data.enter(); | |||
| otherArray.data.enter(); | |||
| const ScopedLockType lock1 (getLock()); | |||
| const ScopedLockType lock2 (otherArray.getLock()); | |||
| data.swapWith (otherArray.data); | |||
| swapVariables (numUsed, otherArray.numUsed); | |||
| otherArray.data.exit(); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -649,29 +600,19 @@ public: | |||
| @returns true only if the other array contains the same objects in the same order | |||
| */ | |||
| bool operator== (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const throw() | |||
| bool operator== (const ReferenceCountedArray& other) const throw() | |||
| { | |||
| other.lockArray(); | |||
| data.enter(); | |||
| const ScopedLockType lock2 (other.getLock()); | |||
| const ScopedLockType lock1 (getLock()); | |||
| bool result = numUsed == other.numUsed; | |||
| if (numUsed != other.numUsed) | |||
| return false; | |||
| if (result) | |||
| { | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (data.elements [i] != other.data.elements [i]) | |||
| { | |||
| result = false; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| data.exit(); | |||
| other.unlockArray(); | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (data.elements [i] != other.data.elements [i]) | |||
| return false; | |||
| return result; | |||
| return true; | |||
| } | |||
| /** Compares this array to another one. | |||
| @@ -717,9 +658,8 @@ public: | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| sortArray (comparator, (ObjectClass**) data.elements, 0, size() - 1, retainOrderOfEquivalentItems); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -731,35 +671,19 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.shrinkToNoMoreThan (numUsed); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Locks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see unlockArray | |||
| /** Returns the CriticalSection that locks this array. | |||
| To lock, you can call getLock().enter() and getLock().exit(), or preferably use | |||
| an object of ScopedLockType as an RAII lock for it. | |||
| */ | |||
| void lockArray() const throw() | |||
| { | |||
| data.enter(); | |||
| } | |||
| /** Unlocks the array's CriticalSection. | |||
| inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see lockArray | |||
| */ | |||
| void unlockArray() const throw() | |||
| { | |||
| data.exit(); | |||
| } | |||
| /** Returns the type of scoped lock to use for locking this array */ | |||
| typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; | |||
| //============================================================================== | |||
| @@ -71,13 +71,12 @@ public: | |||
| /** Creates a copy of another set. | |||
| @param other the set to copy | |||
| */ | |||
| SortedSet (const SortedSet<ElementType, TypeOfCriticalSectionToUse>& other) throw() | |||
| SortedSet (const SortedSet& other) throw() | |||
| { | |||
| other.lockSet(); | |||
| const ScopedLockType lock (other.getLock()); | |||
| numUsed = other.numUsed; | |||
| data.setAllocatedSize (other.numUsed); | |||
| memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); | |||
| other.unlockSet(); | |||
| } | |||
| /** Destructor. */ | |||
| @@ -88,20 +87,17 @@ public: | |||
| /** Copies another set over this one. | |||
| @param other the set to copy | |||
| */ | |||
| SortedSet <ElementType, TypeOfCriticalSectionToUse>& operator= (const SortedSet <ElementType, TypeOfCriticalSectionToUse>& other) throw() | |||
| SortedSet& operator= (const SortedSet& other) throw() | |||
| { | |||
| if (this != &other) | |||
| { | |||
| other.lockSet(); | |||
| data.enter(); | |||
| const ScopedLockType lock1 (other.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| data.ensureAllocatedSize (other.size()); | |||
| numUsed = other.numUsed; | |||
| memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); | |||
| minimiseStorageOverheads(); | |||
| data.exit(); | |||
| other.unlockSet(); | |||
| } | |||
| return *this; | |||
| @@ -117,24 +113,15 @@ public: | |||
| */ | |||
| bool operator== (const SortedSet<ElementType>& other) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (numUsed != other.numUsed) | |||
| { | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (data.elements [i] != other.data.elements [i]) | |||
| { | |||
| data.exit(); | |||
| if (data.elements[i] != other.data.elements[i]) | |||
| return false; | |||
| } | |||
| } | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| @@ -161,10 +148,9 @@ public: | |||
| */ | |||
| void clear() throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.setAllocatedSize (0); | |||
| numUsed = 0; | |||
| data.exit(); | |||
| } | |||
| /** Removes all elements from the set without freeing the array's allocated storage. | |||
| @@ -173,9 +159,8 @@ public: | |||
| */ | |||
| void clearQuick() throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| numUsed = 0; | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -199,13 +184,9 @@ public: | |||
| */ | |||
| inline ElementType operator[] (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) | |||
| ? data.elements [index] | |||
| : (ElementType) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return (((unsigned int) index) < (unsigned int) numUsed) ? data.elements [index] | |||
| : ElementType(); | |||
| } | |||
| /** Returns one of the elements in the set, without checking the index passed in. | |||
| @@ -218,12 +199,9 @@ public: | |||
| */ | |||
| inline ElementType getUnchecked (const int index) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| const ElementType result = data.elements [index]; | |||
| data.exit(); | |||
| return result; | |||
| return data.elements [index]; | |||
| } | |||
| /** Returns the first element in the set, or 0 if the set is empty. | |||
| @@ -232,12 +210,8 @@ public: | |||
| */ | |||
| inline ElementType getFirst() const throw() | |||
| { | |||
| data.enter(); | |||
| const ElementType result = (numUsed > 0) ? data.elements [0] | |||
| : (ElementType) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [0] : ElementType(); | |||
| } | |||
| /** Returns the last element in the set, or 0 if the set is empty. | |||
| @@ -246,12 +220,8 @@ public: | |||
| */ | |||
| inline ElementType getLast() const throw() | |||
| { | |||
| data.enter(); | |||
| const ElementType result = (numUsed > 0) ? data.elements [numUsed - 1] | |||
| : (ElementType) 0; | |||
| data.exit(); | |||
| return result; | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [numUsed - 1] : ElementType(); | |||
| } | |||
| //============================================================================== | |||
| @@ -265,7 +235,7 @@ public: | |||
| */ | |||
| int indexOf (const ElementType elementToLookFor) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end = numUsed; | |||
| @@ -274,12 +244,10 @@ public: | |||
| { | |||
| if (start >= end) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (elementToLookFor == data.elements [start]) | |||
| { | |||
| data.exit(); | |||
| return start; | |||
| } | |||
| else | |||
| @@ -287,10 +255,7 @@ public: | |||
| const int halfway = (start + end) >> 1; | |||
| if (halfway == start) | |||
| { | |||
| data.exit(); | |||
| return -1; | |||
| } | |||
| else if (elementToLookFor >= data.elements [halfway]) | |||
| start = halfway; | |||
| else | |||
| @@ -306,7 +271,7 @@ public: | |||
| */ | |||
| bool contains (const ElementType elementToLookFor) const throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end = numUsed; | |||
| @@ -315,12 +280,10 @@ public: | |||
| { | |||
| if (start >= end) | |||
| { | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| else if (elementToLookFor == data.elements [start]) | |||
| { | |||
| data.exit(); | |||
| return true; | |||
| } | |||
| else | |||
| @@ -328,10 +291,7 @@ public: | |||
| const int halfway = (start + end) >> 1; | |||
| if (halfway == start) | |||
| { | |||
| data.exit(); | |||
| return false; | |||
| } | |||
| else if (elementToLookFor >= data.elements [halfway]) | |||
| start = halfway; | |||
| else | |||
| @@ -348,7 +308,7 @@ public: | |||
| */ | |||
| void add (const ElementType newElement) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end = numUsed; | |||
| @@ -384,8 +344,6 @@ public: | |||
| end = halfway; | |||
| } | |||
| } | |||
| data.exit(); | |||
| } | |||
| /** Adds elements from an array to this set. | |||
| @@ -397,12 +355,10 @@ public: | |||
| void addArray (const ElementType* elementsToAdd, | |||
| int numElementsToAdd) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| while (--numElementsToAdd >= 0) | |||
| add (*elementsToAdd++); | |||
| data.exit(); | |||
| } | |||
| /** Adds elements from another set to this one. | |||
| @@ -419,8 +375,8 @@ public: | |||
| int startIndex = 0, | |||
| int numElementsToAdd = -1) throw() | |||
| { | |||
| setToAddFrom.lockSet(); | |||
| data.enter(); | |||
| const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| jassert (this != &setToAddFrom); | |||
| if (this != &setToAddFrom) | |||
| @@ -436,9 +392,6 @@ public: | |||
| addArray (setToAddFrom.elements + startIndex, numElementsToAdd); | |||
| } | |||
| data.exit(); | |||
| setToAddFrom.unlockSet(); | |||
| } | |||
| @@ -454,7 +407,7 @@ public: | |||
| */ | |||
| ElementType remove (const int indexToRemove) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| if (((unsigned int) indexToRemove) < (unsigned int) numUsed) | |||
| { | |||
| @@ -470,14 +423,10 @@ public: | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| data.exit(); | |||
| return removed; | |||
| } | |||
| else | |||
| { | |||
| data.exit(); | |||
| return 0; | |||
| } | |||
| return 0; | |||
| } | |||
| /** Removes an item from the set. | |||
| @@ -489,9 +438,8 @@ public: | |||
| */ | |||
| void removeValue (const ElementType valueToRemove) throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| remove (indexOf (valueToRemove)); | |||
| data.exit(); | |||
| } | |||
| /** Removes any elements which are also in another set. | |||
| @@ -502,8 +450,8 @@ public: | |||
| template <class OtherSetType> | |||
| void removeValuesIn (const OtherSetType& otherSet) throw() | |||
| { | |||
| otherSet.lockSet(); | |||
| data.enter(); | |||
| const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| if (this == &otherSet) | |||
| { | |||
| @@ -518,9 +466,6 @@ public: | |||
| remove (i); | |||
| } | |||
| } | |||
| data.exit(); | |||
| otherSet.unlockSet(); | |||
| } | |||
| /** Removes any elements which are not found in another set. | |||
| @@ -533,8 +478,8 @@ public: | |||
| template <class OtherSetType> | |||
| void removeValuesNotIn (const OtherSetType& otherSet) throw() | |||
| { | |||
| otherSet.lockSet(); | |||
| data.enter(); | |||
| const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| if (this != &otherSet) | |||
| { | |||
| @@ -549,9 +494,6 @@ public: | |||
| remove (i); | |||
| } | |||
| } | |||
| data.exit(); | |||
| otherSet.lockSet(); | |||
| } | |||
| //============================================================================== | |||
| @@ -563,35 +505,19 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() throw() | |||
| { | |||
| data.enter(); | |||
| const ScopedLockType lock (getLock()); | |||
| data.shrinkToNoMoreThan (numUsed); | |||
| data.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Locks the set's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see unlockSet | |||
| /** Returns the CriticalSection that locks this array. | |||
| To lock, you can call getLock().enter() and getLock().exit(), or preferably use | |||
| an object of ScopedLockType as an RAII lock for it. | |||
| */ | |||
| void lockSet() const throw() | |||
| { | |||
| data.enter(); | |||
| } | |||
| /** Unlocks the set's CriticalSection. | |||
| inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see lockSet | |||
| */ | |||
| void unlockSet() const throw() | |||
| { | |||
| data.exit(); | |||
| } | |||
| /** Returns the type of scoped lock to use for locking this array */ | |||
| typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; | |||
| //============================================================================== | |||
| @@ -229,28 +229,27 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw() | |||
| accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens | |||
| in Cocoa). | |||
| */ | |||
| class SharedLockingEvents : public ReferenceCountedObject | |||
| class MessageManagerLock::SharedEvents : public ReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedLockingEvents() throw() {} | |||
| ~SharedLockingEvents() {} | |||
| SharedEvents() {} | |||
| ~SharedEvents() {} | |||
| /* This class just holds a couple of events to communicate between the MMLockMessage | |||
| /* This class just holds a couple of events to communicate between the BlockingMessage | |||
| and the MessageManagerLock. Because both of these objects may be deleted at any time, | |||
| this shared data must be kept in a separate, ref-counted container. */ | |||
| WaitableEvent lockedEvent, releaseEvent; | |||
| private: | |||
| SharedEvents (const SharedEvents&); | |||
| SharedEvents& operator= (const SharedEvents&); | |||
| }; | |||
| class MMLockMessage : public CallbackMessage | |||
| class MessageManagerLock::BlockingMessage : public CallbackMessage | |||
| { | |||
| public: | |||
| MMLockMessage (SharedLockingEvents* const events_) throw() | |||
| : events (events_) | |||
| {} | |||
| ~MMLockMessage() throw() {} | |||
| ReferenceCountedObjectPtr <SharedLockingEvents> events; | |||
| BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} | |||
| ~BlockingMessage() throw() {} | |||
| void messageCallback() | |||
| { | |||
| @@ -260,21 +259,24 @@ public: | |||
| juce_UseDebuggingNewOperator | |||
| MMLockMessage (const MMLockMessage&); | |||
| const MMLockMessage& operator= (const MMLockMessage&); | |||
| private: | |||
| ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events; | |||
| BlockingMessage (const BlockingMessage&); | |||
| BlockingMessage& operator= (const BlockingMessage&); | |||
| }; | |||
| //============================================================================== | |||
| MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) throw() | |||
| : locked (false), | |||
| needsUnlocking (false) | |||
| : sharedEvents (0), | |||
| locked (false) | |||
| { | |||
| init (threadToCheck, 0); | |||
| } | |||
| MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw() | |||
| : locked (false), | |||
| needsUnlocking (false) | |||
| : sharedEvents (0), | |||
| locked (false) | |||
| { | |||
| init (0, jobToCheckForExitSignal); | |||
| } | |||
| @@ -305,19 +307,19 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| } | |||
| } | |||
| SharedLockingEvents* const events = new SharedLockingEvents(); | |||
| sharedEvents = events; | |||
| events->incReferenceCount(); | |||
| sharedEvents = new SharedEvents(); | |||
| sharedEvents->incReferenceCount(); | |||
| (new MMLockMessage (events))->post(); | |||
| (new BlockingMessage (sharedEvents))->post(); | |||
| while (! events->lockedEvent.wait (50)) | |||
| while (! sharedEvents->lockedEvent.wait (50)) | |||
| { | |||
| if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | |||
| || (job != 0 && job->shouldExit())) | |||
| { | |||
| events->releaseEvent.signal(); | |||
| events->decReferenceCount(); | |||
| sharedEvents->releaseEvent.signal(); | |||
| sharedEvents->decReferenceCount(); | |||
| sharedEvents = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| return; | |||
| } | |||
| @@ -327,22 +329,24 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); | |||
| locked = true; | |||
| needsUnlocking = true; | |||
| } | |||
| } | |||
| } | |||
| MessageManagerLock::~MessageManagerLock() throw() | |||
| { | |||
| if (needsUnlocking && MessageManager::instance != 0) | |||
| if (sharedEvents != 0) | |||
| { | |||
| jassert (MessageManager::instance->currentThreadHasLockedMessageManager()); | |||
| jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | |||
| sharedEvents->releaseEvent.signal(); | |||
| sharedEvents->decReferenceCount(); | |||
| ((SharedLockingEvents*) sharedEvents)->releaseEvent.signal(); | |||
| ((SharedLockingEvents*) sharedEvents)->decReferenceCount(); | |||
| MessageManager::instance->threadWithLock = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| if (MessageManager::instance != 0) | |||
| { | |||
| MessageManager::instance->threadWithLock = 0; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| } | |||
| } | |||
| } | |||
| @@ -305,13 +305,15 @@ public: | |||
| private: | |||
| bool locked, needsUnlocking; | |||
| void* sharedEvents; | |||
| class SharedEvents; | |||
| class BlockingMessage; | |||
| SharedEvents* sharedEvents; | |||
| bool locked; | |||
| void init (Thread* const thread, ThreadPoolJob* const job) throw(); | |||
| MessageManagerLock (const MessageManagerLock&); | |||
| const MessageManagerLock& operator= (const MessageManagerLock&); | |||
| MessageManagerLock& operator= (const MessageManagerLock&); | |||
| }; | |||
| @@ -79,11 +79,15 @@ public: | |||
| const int elapsed = now - lastTime; | |||
| lastTime = now; | |||
| lock.enter(); | |||
| decrementAllCounters (elapsed); | |||
| const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs | |||
| : 1000; | |||
| lock.exit(); | |||
| int timeUntilFirstTimer = 1000; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| decrementAllCounters (elapsed); | |||
| if (firstTimer != 0) | |||
| timeUntilFirstTimer = firstTimer->countdownMs; | |||
| } | |||
| if (timeUntilFirstTimer <= 0) | |||
| { | |||
| @@ -1168,16 +1168,19 @@ void TreeViewItem::addSubItem (TreeViewItem* const newItem, const int insertPosi | |||
| void TreeViewItem::removeSubItem (const int index, const bool deleteItem) | |||
| { | |||
| if (ownerView != 0) | |||
| ownerView->nodeAlterationLock.enter(); | |||
| { | |||
| const ScopedLock sl (ownerView->nodeAlterationLock); | |||
| if (((unsigned int) index) < (unsigned int) subItems.size()) | |||
| if (((unsigned int) index) < (unsigned int) subItems.size()) | |||
| { | |||
| subItems.remove (index, deleteItem); | |||
| treeHasChanged(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| subItems.remove (index, deleteItem); | |||
| treeHasChanged(); | |||
| } | |||
| if (ownerView != 0) | |||
| ownerView->nodeAlterationLock.exit(); | |||
| } | |||
| bool TreeViewItem::isOpen() const throw() | |||
| @@ -29,7 +29,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "juce_OutputStream.h" | |||
| #include "../../threads/juce_CriticalSection.h" | |||
| #include "../../threads/juce_ScopedLock.h" | |||
| #include "../../containers/juce_VoidArray.h" | |||
| @@ -54,18 +54,16 @@ void juce_CheckForDanglingStreams() | |||
| OutputStream::OutputStream() throw() | |||
| { | |||
| #if JUCE_DEBUG | |||
| activeStreamLock.enter(); | |||
| const ScopedLock sl (activeStreamLock); | |||
| activeStreams.add (this); | |||
| activeStreamLock.exit(); | |||
| #endif | |||
| } | |||
| OutputStream::~OutputStream() | |||
| { | |||
| #if JUCE_DEBUG | |||
| activeStreamLock.enter(); | |||
| const ScopedLock sl (activeStreamLock); | |||
| activeStreams.removeValue (this); | |||
| activeStreamLock.exit(); | |||
| #endif | |||
| } | |||
| @@ -205,9 +205,8 @@ public: | |||
| if (callback_ != 0) | |||
| callback_->audioDeviceAboutToStart (this); | |||
| callbackLock.enter(); | |||
| const ScopedLock sl (callbackLock); | |||
| callback = callback_; | |||
| callbackLock.exit(); | |||
| } | |||
| } | |||
| @@ -215,10 +214,13 @@ public: | |||
| { | |||
| if (isRunning) | |||
| { | |||
| callbackLock.enter(); | |||
| AudioIODeviceCallback* const lastCallback = callback; | |||
| callback = 0; | |||
| callbackLock.exit(); | |||
| AudioIODeviceCallback* lastCallback; | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| lastCallback = callback; | |||
| callback = 0; | |||
| } | |||
| if (lastCallback != 0) | |||
| lastCallback->audioDeviceStopped(); | |||
| @@ -538,9 +538,10 @@ public: | |||
| void stop (bool leaveInterruptRunning) | |||
| { | |||
| callbackLock.enter(); | |||
| callback = 0; | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| callback = 0; | |||
| } | |||
| if (started | |||
| && (deviceID != 0) | |||
| @@ -556,8 +557,7 @@ public: | |||
| #endif | |||
| started = false; | |||
| callbackLock.enter(); | |||
| callbackLock.exit(); | |||
| { const ScopedLock sl (callbackLock); } | |||
| // wait until it's definately stopped calling back.. | |||
| for (int i = 40; --i >= 0;) | |||
| @@ -578,8 +578,7 @@ public: | |||
| break; | |||
| } | |||
| callbackLock.enter(); | |||
| callbackLock.exit(); | |||
| const ScopedLock sl (callbackLock); | |||
| } | |||
| if (inputDevice != 0) | |||
| @@ -624,9 +624,10 @@ MidiInput::~MidiInput() | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| mpc->active = false; | |||
| callbackLock.enter(); | |||
| activeCallbacks.removeValue (mpc); | |||
| callbackLock.exit(); | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| activeCallbacks.removeValue (mpc); | |||
| } | |||
| if (mpc->portAndEndpoint->port != 0) | |||
| OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); | |||
| @@ -637,16 +638,14 @@ MidiInput::~MidiInput() | |||
| void MidiInput::start() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = true; | |||
| ((MidiPortAndCallback*) internal)->active = true; | |||
| } | |||
| void MidiInput::stop() | |||
| { | |||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) internal; | |||
| const ScopedLock sl (callbackLock); | |||
| mpc->active = false; | |||
| ((MidiPortAndCallback*) internal)->active = false; | |||
| } | |||
| #undef log | |||
| @@ -82,24 +82,25 @@ public: | |||
| return; | |||
| const int numBytes = MidiMessage::getMessageLengthFromFirstByte ((uint8) byte); | |||
| const double time = timeStampToTime (timeStamp); | |||
| lock.enter(); | |||
| if (pendingLength < midiBufferSize - 12) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = numBytes; | |||
| *(uint32*) (p + 12) = message; | |||
| pendingLength += 12 + numBytes; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| const ScopedLock sl (lock); | |||
| if (pendingLength < midiBufferSize - 12) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = numBytes; | |||
| *(uint32*) (p + 12) = message; | |||
| pendingLength += 12 + numBytes; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| } | |||
| } | |||
| lock.exit(); | |||
| notify(); | |||
| } | |||
| @@ -111,22 +112,23 @@ public: | |||
| { | |||
| const double time = timeStampToTime (timeStamp); | |||
| lock.enter(); | |||
| if (pendingLength < midiBufferSize - (8 + num)) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = num; | |||
| memcpy (p + 12, hdr->lpData, num); | |||
| pendingLength += 12 + num; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| const ScopedLock sl (lock); | |||
| if (pendingLength < midiBufferSize - (8 + num)) | |||
| { | |||
| char* const p = pending + pendingLength; | |||
| *(double*) p = time; | |||
| *(uint32*) (p + 8) = num; | |||
| memcpy (p + 12, hdr->lpData, num); | |||
| pendingLength += 12 + num; | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // midi buffer overflow! You might need to increase the size.. | |||
| } | |||
| } | |||
| lock.exit(); | |||
| notify(); | |||
| } | |||
| } | |||
| @@ -157,20 +159,22 @@ public: | |||
| } | |||
| } | |||
| lock.enter(); | |||
| int len = pendingLength; | |||
| int len; | |||
| if (len > 0) | |||
| { | |||
| pendingCopy.ensureSize (len); | |||
| pendingCopy.copyFrom (pending, 0, len); | |||
| pendingLength = 0; | |||
| } | |||
| const ScopedLock sl (lock); | |||
| lock.exit(); | |||
| len = pendingLength; | |||
| if (len > 0) | |||
| { | |||
| pendingCopy.ensureSize (len); | |||
| pendingCopy.copyFrom (pending, 0, len); | |||
| pendingLength = 0; | |||
| } | |||
| } | |||
| //xxx needs to figure out if blocks are broken up or not | |||
| //xxx needs to figure out if blocks are broken up or not | |||
| if (len == 0) | |||
| { | |||
| @@ -234,8 +238,7 @@ public: | |||
| activeMidiThreads.removeValue (this); | |||
| lock.enter(); | |||
| lock.exit(); | |||
| { const ScopedLock sl (lock); } | |||
| for (int i = numInHeaders; --i >= 0;) | |||
| { | |||
| @@ -26,6 +26,9 @@ | |||
| #ifndef __JUCE_CRITICALSECTION_JUCEHEADER__ | |||
| #define __JUCE_CRITICALSECTION_JUCEHEADER__ | |||
| class JUCE_API ScopedLock; | |||
| class JUCE_API ScopedUnlock; | |||
| //============================================================================== | |||
| /** | |||
| @@ -84,6 +87,13 @@ public: | |||
| void exit() const throw(); | |||
| //============================================================================== | |||
| /** Provides the type of scoped lock to use with this type of critical section object. */ | |||
| typedef ScopedLock ScopedLockType; | |||
| /** Provides the type of scoped unlocker to use with this type of critical section object. */ | |||
| typedef ScopedUnlock ScopedUnlockType; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -103,7 +113,7 @@ private: | |||
| #endif | |||
| CriticalSection (const CriticalSection&); | |||
| const CriticalSection& operator= (const CriticalSection&); | |||
| CriticalSection& operator= (const CriticalSection&); | |||
| }; | |||
| @@ -111,7 +121,7 @@ private: | |||
| /** | |||
| A class that can be used in place of a real CriticalSection object. | |||
| This is currently used by some templated array classes, and should get | |||
| This is currently used by some templated classes, and should get | |||
| optimised out by the compiler. | |||
| @see Array, OwnedArray, ReferenceCountedArray | |||
| @@ -124,6 +134,16 @@ public: | |||
| inline void enter() const throw() {} | |||
| inline void exit() const throw() {} | |||
| //============================================================================== | |||
| /** A dummy scoped-lock type to use with a dummy critical section. */ | |||
| struct ScopedLockType | |||
| { | |||
| ScopedLockType (const DummyCriticalSection&) throw() {} | |||
| }; | |||
| /** A dummy scoped-unlocker type to use with a dummy critical section. */ | |||
| typedef ScopedLockType ScopedUnlockType; | |||
| }; | |||
| @@ -31,7 +31,6 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "juce_Thread.h" | |||
| #include "juce_ScopedLock.h" | |||
| #include "../core/juce_Time.h" | |||
| #include "../containers/juce_VoidArray.h" | |||
| // these functions are implemented in the platform-specific code. | |||
| void* juce_createThread (void* userData); | |||
| @@ -42,9 +41,6 @@ void juce_setCurrentThreadName (const String& name); | |||
| void juce_CloseThreadHandle (void* handle); | |||
| #endif | |||
| //============================================================================== | |||
| static VoidArray runningThreads; | |||
| static CriticalSection runningThreadsLock; | |||
| //============================================================================== | |||
| void Thread::threadEntryPoint (Thread* const thread) | |||
| @@ -251,7 +247,7 @@ Thread* Thread::getCurrentThread() | |||
| for (int i = runningThreads.size(); --i >= 0;) | |||
| { | |||
| Thread* const t = (Thread*) runningThreads.getUnchecked(i); | |||
| Thread* const t = runningThreads.getUnchecked(i); | |||
| if (t->threadId_ == thisId) | |||
| return t; | |||
| @@ -266,20 +262,27 @@ void Thread::stopAllThreads (const int timeOutMilliseconds) | |||
| const ScopedLock sl (runningThreadsLock); | |||
| for (int i = runningThreads.size(); --i >= 0;) | |||
| ((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit(); | |||
| runningThreads.getUnchecked(i)->signalThreadShouldExit(); | |||
| } | |||
| for (;;) | |||
| { | |||
| runningThreadsLock.enter(); | |||
| Thread* const t = (Thread*) runningThreads[0]; | |||
| runningThreadsLock.exit(); | |||
| Thread* firstThread; | |||
| { | |||
| const ScopedLock sl (runningThreadsLock); | |||
| firstThread = runningThreads.getFirst(); | |||
| } | |||
| if (t == 0) | |||
| if (firstThread == 0) | |||
| break; | |||
| t->stopThread (timeOutMilliseconds); | |||
| firstThread->stopThread (timeOutMilliseconds); | |||
| } | |||
| } | |||
| Array<Thread*> Thread::runningThreads; | |||
| CriticalSection Thread::runningThreadsLock; | |||
| END_JUCE_NAMESPACE | |||
| @@ -28,6 +28,7 @@ | |||
| #include "juce_WaitableEvent.h" | |||
| #include "juce_CriticalSection.h" | |||
| #include "../containers/juce_Array.h" | |||
| //============================================================================== | |||
| @@ -281,6 +282,8 @@ private: | |||
| friend void JUCE_API juce_threadEntryPoint (void*); | |||
| static void threadEntryPoint (Thread* thread); | |||
| static Array<Thread*> runningThreads; | |||
| static CriticalSection runningThreadsLock; | |||
| Thread (const Thread&); | |||
| const Thread& operator= (const Thread&); | |||
| @@ -221,9 +221,11 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| const bool interruptIfRunning, | |||
| const int timeOutMs) | |||
| { | |||
| bool dontWait = true; | |||
| if (job != 0) | |||
| { | |||
| lock.enter(); | |||
| const ScopedLock sl (lock); | |||
| if (jobs.contains (job)) | |||
| { | |||
| @@ -232,20 +234,16 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job, | |||
| if (interruptIfRunning) | |||
| job->signalJobShouldExit(); | |||
| lock.exit(); | |||
| return waitForJobToFinish (job, timeOutMs); | |||
| dontWait = false; | |||
| } | |||
| else | |||
| { | |||
| jobs.removeValue (job); | |||
| } | |||
| } | |||
| lock.exit(); | |||
| } | |||
| return true; | |||
| return dontWait || waitForJobToFinish (job, timeOutMs); | |||
| } | |||
| bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, | |||
| @@ -54,9 +54,12 @@ void DeletedAtShutdown::deleteAll() | |||
| { | |||
| // make a local copy of the array, so it can't get into a loop if something | |||
| // creates another DeletedAtShutdown object during its destructor. | |||
| lock.enter(); | |||
| const VoidArray localCopy (objectsToDelete); | |||
| lock.exit(); | |||
| VoidArray localCopy; | |||
| { | |||
| const ScopedLock sl (lock); | |||
| localCopy = objectsToDelete; | |||
| } | |||
| for (int i = localCopy.size(); --i >= 0;) | |||
| { | |||