| @@ -176,7 +176,7 @@ | |||
| #endif | |||
| #endif | |||
| #if ! JUCE_VC7_OR_EARLIER | |||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||
| #define JUCE_USE_INTRINSICS 1 | |||
| #endif | |||
| #else | |||
| @@ -17363,9 +17363,7 @@ BEGIN_JUCE_NAMESPACE | |||
| TimeSliceThread::TimeSliceThread (const String& threadName) | |||
| : Thread (threadName), | |||
| index (0), | |||
| clientBeingCalled (0), | |||
| clientsChanged (false) | |||
| clientBeingCalled (0) | |||
| { | |||
| } | |||
| @@ -17374,18 +17372,20 @@ TimeSliceThread::~TimeSliceThread() | |||
| stopThread (2000); | |||
| } | |||
| void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client) | |||
| void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting) | |||
| { | |||
| const ScopedLock sl (listLock); | |||
| clients.addIfNotAlreadyThere (client); | |||
| clientsChanged = true; | |||
| notify(); | |||
| if (client != 0) | |||
| { | |||
| const ScopedLock sl (listLock); | |||
| client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting); | |||
| clients.addIfNotAlreadyThere (client); | |||
| notify(); | |||
| } | |||
| } | |||
| void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client) | |||
| { | |||
| const ScopedLock sl1 (listLock); | |||
| clientsChanged = true; | |||
| // if there's a chance we're in the middle of calling this client, we need to | |||
| // also lock the outer lock.. | |||
| @@ -17415,52 +17415,76 @@ TimeSliceClient* TimeSliceThread::getClient (const int i) const | |||
| return clients [i]; | |||
| } | |||
| TimeSliceClient* TimeSliceThread::getNextClient (int index) const | |||
| { | |||
| Time soonest; | |||
| TimeSliceClient* client = 0; | |||
| for (int i = clients.size(); --i >= 0;) | |||
| { | |||
| TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size()); | |||
| if (client == 0 || c->nextCallTime < soonest) | |||
| { | |||
| client = c; | |||
| soonest = c->nextCallTime; | |||
| } | |||
| } | |||
| return client; | |||
| } | |||
| void TimeSliceThread::run() | |||
| { | |||
| int numCallsSinceBusy = 0; | |||
| int index = 0; | |||
| while (! threadShouldExit()) | |||
| { | |||
| int timeToWait = 500; | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| Time nextClientTime; | |||
| { | |||
| const ScopedLock sl2 (listLock); | |||
| if (clients.size() > 0) | |||
| { | |||
| index = (index + 1) % clients.size(); | |||
| index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0; | |||
| TimeSliceClient* const firstClient = getNextClient (index); | |||
| if (firstClient != 0) | |||
| nextClientTime = firstClient->nextCallTime; | |||
| } | |||
| const Time now (Time::getCurrentTime()); | |||
| if (nextClientTime > now) | |||
| { | |||
| timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds()); | |||
| } | |||
| else | |||
| { | |||
| timeToWait = index == 0 ? 1 : 0; | |||
| const ScopedLock sl (callbackLock); | |||
| clientBeingCalled = clients [index]; | |||
| } | |||
| else | |||
| { | |||
| index = 0; | |||
| clientBeingCalled = 0; | |||
| const ScopedLock sl2 (listLock); | |||
| clientBeingCalled = getNextClient (index); | |||
| } | |||
| if (clientsChanged) | |||
| if (clientBeingCalled != 0) | |||
| { | |||
| clientsChanged = false; | |||
| numCallsSinceBusy = 0; | |||
| } | |||
| } | |||
| const int msUntilNextCall = clientBeingCalled->useTimeSlice(); | |||
| if (clientBeingCalled != 0) | |||
| { | |||
| if (clientBeingCalled->useTimeSlice()) | |||
| numCallsSinceBusy = 0; | |||
| else | |||
| ++numCallsSinceBusy; | |||
| const ScopedLock sl2 (listLock); | |||
| if (numCallsSinceBusy >= clients.size()) | |||
| timeToWait = 500; | |||
| else if (index == 0) | |||
| timeToWait = 1; // throw in an occasional pause, to stop everything locking up | |||
| else | |||
| timeToWait = 0; | |||
| if (msUntilNextCall >= 0) | |||
| clientBeingCalled->nextCallTime += RelativeTime::milliseconds (msUntilNextCall); | |||
| else | |||
| clients.removeValue (clientBeingCalled); | |||
| clientBeingCalled = 0; | |||
| } | |||
| } | |||
| } | |||
| @@ -21509,7 +21533,7 @@ public: | |||
| isRunning = false; | |||
| timeSliceThread.removeTimeSliceClient (this); | |||
| while (useTimeSlice()) | |||
| while (useTimeSlice() == 0) | |||
| {} | |||
| } | |||
| @@ -21537,7 +21561,7 @@ public: | |||
| return true; | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| const int numToDo = getTotalSize() / 4; | |||
| @@ -21545,7 +21569,7 @@ public: | |||
| prepareToRead (numToDo, start1, size1, start2, size2); | |||
| if (size1 <= 0) | |||
| return false; | |||
| return 10; | |||
| writer->writeFromAudioSampleBuffer (buffer, start1, size1); | |||
| @@ -21566,7 +21590,7 @@ public: | |||
| } | |||
| finishedRead (size1 + size2); | |||
| return true; | |||
| return 0; | |||
| } | |||
| void setThumbnail (AudioThumbnail* thumb) | |||
| @@ -21913,8 +21937,7 @@ struct AudioThumbnail::MinMaxValue | |||
| } | |||
| }; | |||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient, | |||
| public Timer | |||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient | |||
| { | |||
| public: | |||
| LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | |||
| @@ -21934,7 +21957,7 @@ public: | |||
| owner.cache.removeTimeSliceClient (this); | |||
| } | |||
| enum { timeBeforeDeletingReader = 2000 }; | |||
| enum { timeBeforeDeletingReader = 1000 }; | |||
| void initialise (int64 numSamplesFinished_) | |||
| { | |||
| @@ -21950,9 +21973,9 @@ public: | |||
| numChannels = reader->numChannels; | |||
| sampleRate = reader->sampleRate; | |||
| if (lengthInSamples <= 0) | |||
| if (lengthInSamples <= 0 || isFullyLoaded()) | |||
| reader = 0; | |||
| else if (! isFullyLoaded()) | |||
| else | |||
| owner.cache.addTimeSliceClient (this); | |||
| } | |||
| } | |||
| @@ -21960,7 +21983,14 @@ public: | |||
| void getLevels (int64 startSample, int numSamples, Array<float>& levels) | |||
| { | |||
| const ScopedLock sl (readerLock); | |||
| createReader(); | |||
| if (reader == 0) | |||
| { | |||
| createReader(); | |||
| if (reader != 0) | |||
| owner.cache.addTimeSliceClient (this); | |||
| } | |||
| if (reader != 0) | |||
| { | |||
| @@ -21978,19 +22008,16 @@ public: | |||
| reader = 0; | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| if (isFullyLoaded()) | |||
| { | |||
| if (reader != 0 && source != 0) | |||
| startTimer (timeBeforeDeletingReader); | |||
| releaseResources(); | |||
| owner.cache.removeTimeSliceClient (this); | |||
| return false; | |||
| return -1; | |||
| } | |||
| stopTimer(); | |||
| bool justFinished = false; | |||
| { | |||
| @@ -22001,7 +22028,7 @@ public: | |||
| if (reader != 0) | |||
| { | |||
| if (! readNextBlock()) | |||
| return true; | |||
| return 0; | |||
| justFinished = true; | |||
| } | |||
| @@ -22010,13 +22037,7 @@ public: | |||
| if (justFinished) | |||
| owner.cache.storeThumb (owner, hashCode); | |||
| return false; | |||
| } | |||
| void timerCallback() | |||
| { | |||
| stopTimer(); | |||
| releaseResources(); | |||
| return timeBeforeDeletingReader; | |||
| } | |||
| bool isFullyLoaded() const throw() | |||
| @@ -57840,7 +57861,7 @@ void DirectoryContentsList::changed() | |||
| sendChangeMessage(); | |||
| } | |||
| bool DirectoryContentsList::useTimeSlice() | |||
| int DirectoryContentsList::useTimeSlice() | |||
| { | |||
| const uint32 startTime = Time::getApproximateMillisecondCounter(); | |||
| bool hasChanged = false; | |||
| @@ -57852,7 +57873,7 @@ bool DirectoryContentsList::useTimeSlice() | |||
| if (hasChanged) | |||
| changed(); | |||
| return false; | |||
| return 500; | |||
| } | |||
| if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | |||
| @@ -57862,7 +57883,7 @@ bool DirectoryContentsList::useTimeSlice() | |||
| if (hasChanged) | |||
| changed(); | |||
| return true; | |||
| return 0; | |||
| } | |||
| bool DirectoryContentsList::checkNextFile (bool& hasChanged) | |||
| @@ -58957,10 +58978,10 @@ public: | |||
| } | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| updateIcon (false); | |||
| return false; | |||
| return -1; | |||
| } | |||
| void handleAsyncUpdate() | |||
| @@ -59655,11 +59676,10 @@ public: | |||
| owner.sendSelectionChangeMessage(); | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| updateIcon (false); | |||
| thread.removeTimeSliceClient (this); | |||
| return false; | |||
| return -1; | |||
| } | |||
| void handleAsyncUpdate() | |||
| @@ -61201,7 +61221,7 @@ public: | |||
| component->setVisible (! useProxyComponent); | |||
| } | |||
| bool useTimeslice (const int elapsed) | |||
| int useTimeslice (const int elapsed) | |||
| { | |||
| Component* const c = proxy != 0 ? static_cast <Component*> (proxy) | |||
| : static_cast <Component*> (component); | |||
| @@ -61249,13 +61269,13 @@ public: | |||
| } | |||
| if (stillBusy) | |||
| return true; | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| moveToFinalDestination(); | |||
| return false; | |||
| return -1; | |||
| } | |||
| void moveToFinalDestination() | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 15 | |||
| #define JUCE_BUILDNUMBER 16 | |||
| /** Current Juce version number. | |||
| @@ -223,7 +223,7 @@ namespace JuceDummyNamespace {} | |||
| #endif | |||
| #endif | |||
| #if ! JUCE_VC7_OR_EARLIER | |||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||
| #define JUCE_USE_INTRINSICS 1 | |||
| #endif | |||
| #else | |||
| @@ -19825,6 +19825,8 @@ private: | |||
| #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ | |||
| #define __JUCE_TIMESLICETHREAD_JUCEHEADER__ | |||
| class TimeSliceThread; | |||
| /** | |||
| Used by the TimeSliceThread class. | |||
| @@ -19850,13 +19852,18 @@ public: | |||
| The implementation of this method should use its time-slice to do something that's | |||
| quick - never block for longer than absolutely necessary. | |||
| @returns Your method should return true if it needs more time, or false if it's | |||
| not too busy and doesn't need calling back urgently. If all the thread's | |||
| clients indicate that they're not busy, then it'll save CPU by sleeping for | |||
| up to half a second in between callbacks. You can force the TimeSliceThread | |||
| to wake up and poll again immediately by calling its notify() method. | |||
| @returns Your method should return the number of milliseconds which it would like to wait before being called | |||
| again. Returning 0 will make the thread call again as soon as possible (after possibly servicing | |||
| other busy clients). If you return a value below zero, your client will be removed from the list of clients, | |||
| and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the | |||
| thread - the actual time before the next callback may be more or less than specified. | |||
| You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. | |||
| */ | |||
| virtual bool useTimeSlice() = 0; | |||
| virtual int useTimeSlice() = 0; | |||
| private: | |||
| friend class TimeSliceThread; | |||
| Time nextCallTime; | |||
| }; | |||
| /** | |||
| @@ -19888,10 +19895,10 @@ public: | |||
| /** Adds a client to the list. | |||
| The client's callbacks will start immediately (possibly before the method | |||
| has returned). | |||
| The client's callbacks will start after the number of milliseconds specified | |||
| by millisecondsBeforeStarting (and this may happen before this method has returned). | |||
| */ | |||
| void addTimeSliceClient (TimeSliceClient* client); | |||
| void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0); | |||
| /** Removes a client from the list. | |||
| @@ -19912,9 +19919,9 @@ public: | |||
| private: | |||
| CriticalSection callbackLock, listLock; | |||
| Array <TimeSliceClient*> clients; | |||
| int index; | |||
| TimeSliceClient* clientBeingCalled; | |||
| bool clientsChanged; | |||
| TimeSliceClient* getNextClient (int index) const; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | |||
| }; | |||
| @@ -51277,7 +51284,7 @@ public: | |||
| const FileFilter* getFilter() const { return fileFilter; } | |||
| /** @internal */ | |||
| bool useTimeSlice(); | |||
| int useTimeSlice(); | |||
| /** @internal */ | |||
| TimeSliceThread& getTimeSliceThread() { return thread; } | |||
| /** @internal */ | |||
| @@ -201,7 +201,7 @@ public: | |||
| isRunning = false; | |||
| timeSliceThread.removeTimeSliceClient (this); | |||
| while (useTimeSlice()) | |||
| while (useTimeSlice() == 0) | |||
| {} | |||
| } | |||
| @@ -229,7 +229,7 @@ public: | |||
| return true; | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| const int numToDo = getTotalSize() / 4; | |||
| @@ -237,7 +237,7 @@ public: | |||
| prepareToRead (numToDo, start1, size1, start2, size2); | |||
| if (size1 <= 0) | |||
| return false; | |||
| return 10; | |||
| writer->writeFromAudioSampleBuffer (buffer, start1, size1); | |||
| @@ -258,7 +258,7 @@ public: | |||
| } | |||
| finishedRead (size1 + size2); | |||
| return true; | |||
| return 0; | |||
| } | |||
| void setThumbnail (AudioThumbnail* thumb) | |||
| @@ -82,8 +82,7 @@ struct AudioThumbnail::MinMaxValue | |||
| }; | |||
| //============================================================================== | |||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient, | |||
| public Timer | |||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient | |||
| { | |||
| public: | |||
| LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | |||
| @@ -103,7 +102,7 @@ public: | |||
| owner.cache.removeTimeSliceClient (this); | |||
| } | |||
| enum { timeBeforeDeletingReader = 2000 }; | |||
| enum { timeBeforeDeletingReader = 1000 }; | |||
| void initialise (int64 numSamplesFinished_) | |||
| { | |||
| @@ -119,9 +118,9 @@ public: | |||
| numChannels = reader->numChannels; | |||
| sampleRate = reader->sampleRate; | |||
| if (lengthInSamples <= 0) | |||
| if (lengthInSamples <= 0 || isFullyLoaded()) | |||
| reader = 0; | |||
| else if (! isFullyLoaded()) | |||
| else | |||
| owner.cache.addTimeSliceClient (this); | |||
| } | |||
| } | |||
| @@ -129,7 +128,14 @@ public: | |||
| void getLevels (int64 startSample, int numSamples, Array<float>& levels) | |||
| { | |||
| const ScopedLock sl (readerLock); | |||
| createReader(); | |||
| if (reader == 0) | |||
| { | |||
| createReader(); | |||
| if (reader != 0) | |||
| owner.cache.addTimeSliceClient (this); | |||
| } | |||
| if (reader != 0) | |||
| { | |||
| @@ -147,19 +153,16 @@ public: | |||
| reader = 0; | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| if (isFullyLoaded()) | |||
| { | |||
| if (reader != 0 && source != 0) | |||
| startTimer (timeBeforeDeletingReader); | |||
| releaseResources(); | |||
| owner.cache.removeTimeSliceClient (this); | |||
| return false; | |||
| return -1; | |||
| } | |||
| stopTimer(); | |||
| bool justFinished = false; | |||
| { | |||
| @@ -170,7 +173,7 @@ public: | |||
| if (reader != 0) | |||
| { | |||
| if (! readNextBlock()) | |||
| return true; | |||
| return 0; | |||
| justFinished = true; | |||
| } | |||
| @@ -179,13 +182,7 @@ public: | |||
| if (justFinished) | |||
| owner.cache.storeThumb (owner, hashCode); | |||
| return false; | |||
| } | |||
| void timerCallback() | |||
| { | |||
| stopTimer(); | |||
| releaseResources(); | |||
| return timeBeforeDeletingReader; | |||
| } | |||
| bool isFullyLoaded() const throw() | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 15 | |||
| #define JUCE_BUILDNUMBER 16 | |||
| /** Current Juce version number. | |||
| @@ -166,7 +166,7 @@ | |||
| #endif | |||
| #endif | |||
| #if ! JUCE_VC7_OR_EARLIER | |||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||
| #define JUCE_USE_INTRINSICS 1 | |||
| #endif | |||
| #else | |||
| @@ -165,7 +165,7 @@ void DirectoryContentsList::changed() | |||
| } | |||
| //============================================================================== | |||
| bool DirectoryContentsList::useTimeSlice() | |||
| int DirectoryContentsList::useTimeSlice() | |||
| { | |||
| const uint32 startTime = Time::getApproximateMillisecondCounter(); | |||
| bool hasChanged = false; | |||
| @@ -177,7 +177,7 @@ bool DirectoryContentsList::useTimeSlice() | |||
| if (hasChanged) | |||
| changed(); | |||
| return false; | |||
| return 500; | |||
| } | |||
| if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | |||
| @@ -187,7 +187,7 @@ bool DirectoryContentsList::useTimeSlice() | |||
| if (hasChanged) | |||
| changed(); | |||
| return true; | |||
| return 0; | |||
| } | |||
| bool DirectoryContentsList::checkNextFile (bool& hasChanged) | |||
| @@ -185,7 +185,7 @@ public: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| bool useTimeSlice(); | |||
| int useTimeSlice(); | |||
| /** @internal */ | |||
| TimeSliceThread& getTimeSliceThread() { return thread; } | |||
| /** @internal */ | |||
| @@ -165,10 +165,10 @@ public: | |||
| } | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| updateIcon (false); | |||
| return false; | |||
| return -1; | |||
| } | |||
| void handleAsyncUpdate() | |||
| @@ -173,11 +173,10 @@ public: | |||
| owner.sendSelectionChangeMessage(); | |||
| } | |||
| bool useTimeSlice() | |||
| int useTimeSlice() | |||
| { | |||
| updateIcon (false); | |||
| thread.removeTimeSliceClient (this); | |||
| return false; | |||
| return -1; | |||
| } | |||
| void handleAsyncUpdate() | |||
| @@ -34,9 +34,7 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| TimeSliceThread::TimeSliceThread (const String& threadName) | |||
| : Thread (threadName), | |||
| index (0), | |||
| clientBeingCalled (0), | |||
| clientsChanged (false) | |||
| clientBeingCalled (0) | |||
| { | |||
| } | |||
| @@ -46,18 +44,20 @@ TimeSliceThread::~TimeSliceThread() | |||
| } | |||
| //============================================================================== | |||
| void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client) | |||
| void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting) | |||
| { | |||
| const ScopedLock sl (listLock); | |||
| clients.addIfNotAlreadyThere (client); | |||
| clientsChanged = true; | |||
| notify(); | |||
| if (client != 0) | |||
| { | |||
| const ScopedLock sl (listLock); | |||
| client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting); | |||
| clients.addIfNotAlreadyThere (client); | |||
| notify(); | |||
| } | |||
| } | |||
| void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client) | |||
| { | |||
| const ScopedLock sl1 (listLock); | |||
| clientsChanged = true; | |||
| // if there's a chance we're in the middle of calling this client, we need to | |||
| // also lock the outer lock.. | |||
| @@ -88,52 +88,76 @@ TimeSliceClient* TimeSliceThread::getClient (const int i) const | |||
| } | |||
| //============================================================================== | |||
| TimeSliceClient* TimeSliceThread::getNextClient (int index) const | |||
| { | |||
| Time soonest; | |||
| TimeSliceClient* client = 0; | |||
| for (int i = clients.size(); --i >= 0;) | |||
| { | |||
| TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size()); | |||
| if (client == 0 || c->nextCallTime < soonest) | |||
| { | |||
| client = c; | |||
| soonest = c->nextCallTime; | |||
| } | |||
| } | |||
| return client; | |||
| } | |||
| void TimeSliceThread::run() | |||
| { | |||
| int numCallsSinceBusy = 0; | |||
| int index = 0; | |||
| while (! threadShouldExit()) | |||
| { | |||
| int timeToWait = 500; | |||
| { | |||
| const ScopedLock sl (callbackLock); | |||
| Time nextClientTime; | |||
| { | |||
| const ScopedLock sl2 (listLock); | |||
| if (clients.size() > 0) | |||
| { | |||
| index = (index + 1) % clients.size(); | |||
| index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0; | |||
| TimeSliceClient* const firstClient = getNextClient (index); | |||
| if (firstClient != 0) | |||
| nextClientTime = firstClient->nextCallTime; | |||
| } | |||
| const Time now (Time::getCurrentTime()); | |||
| if (nextClientTime > now) | |||
| { | |||
| timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds()); | |||
| } | |||
| else | |||
| { | |||
| timeToWait = index == 0 ? 1 : 0; | |||
| const ScopedLock sl (callbackLock); | |||
| clientBeingCalled = clients [index]; | |||
| } | |||
| else | |||
| { | |||
| index = 0; | |||
| clientBeingCalled = 0; | |||
| const ScopedLock sl2 (listLock); | |||
| clientBeingCalled = getNextClient (index); | |||
| } | |||
| if (clientsChanged) | |||
| if (clientBeingCalled != 0) | |||
| { | |||
| clientsChanged = false; | |||
| numCallsSinceBusy = 0; | |||
| } | |||
| } | |||
| const int msUntilNextCall = clientBeingCalled->useTimeSlice(); | |||
| if (clientBeingCalled != 0) | |||
| { | |||
| if (clientBeingCalled->useTimeSlice()) | |||
| numCallsSinceBusy = 0; | |||
| else | |||
| ++numCallsSinceBusy; | |||
| if (numCallsSinceBusy >= clients.size()) | |||
| timeToWait = 500; | |||
| else if (index == 0) | |||
| timeToWait = 1; // throw in an occasional pause, to stop everything locking up | |||
| else | |||
| timeToWait = 0; | |||
| const ScopedLock sl2 (listLock); | |||
| if (msUntilNextCall >= 0) | |||
| clientBeingCalled->nextCallTime += RelativeTime::milliseconds (msUntilNextCall); | |||
| else | |||
| clients.removeValue (clientBeingCalled); | |||
| clientBeingCalled = 0; | |||
| } | |||
| } | |||
| } | |||
| @@ -28,7 +28,8 @@ | |||
| #include "juce_Thread.h" | |||
| #include "../containers/juce_Array.h" | |||
| #include "../core/juce_Time.h" | |||
| class TimeSliceThread; | |||
| //============================================================================== | |||
| /** | |||
| @@ -56,13 +57,19 @@ public: | |||
| The implementation of this method should use its time-slice to do something that's | |||
| quick - never block for longer than absolutely necessary. | |||
| @returns Your method should return true if it needs more time, or false if it's | |||
| not too busy and doesn't need calling back urgently. If all the thread's | |||
| clients indicate that they're not busy, then it'll save CPU by sleeping for | |||
| up to half a second in between callbacks. You can force the TimeSliceThread | |||
| to wake up and poll again immediately by calling its notify() method. | |||
| @returns Your method should return the number of milliseconds which it would like to wait before being called | |||
| again. Returning 0 will make the thread call again as soon as possible (after possibly servicing | |||
| other busy clients). If you return a value below zero, your client will be removed from the list of clients, | |||
| and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the | |||
| thread - the actual time before the next callback may be more or less than specified. | |||
| You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. | |||
| */ | |||
| virtual bool useTimeSlice() = 0; | |||
| virtual int useTimeSlice() = 0; | |||
| private: | |||
| friend class TimeSliceThread; | |||
| Time nextCallTime; | |||
| }; | |||
| @@ -97,10 +104,10 @@ public: | |||
| //============================================================================== | |||
| /** Adds a client to the list. | |||
| The client's callbacks will start immediately (possibly before the method | |||
| has returned). | |||
| The client's callbacks will start after the number of milliseconds specified | |||
| by millisecondsBeforeStarting (and this may happen before this method has returned). | |||
| */ | |||
| void addTimeSliceClient (TimeSliceClient* client); | |||
| void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0); | |||
| /** Removes a client from the list. | |||
| @@ -123,9 +130,9 @@ public: | |||
| private: | |||
| CriticalSection callbackLock, listLock; | |||
| Array <TimeSliceClient*> clients; | |||
| int index; | |||
| TimeSliceClient* clientBeingCalled; | |||
| bool clientsChanged; | |||
| TimeSliceClient* getNextClient (int index) const; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | |||
| }; | |||