| @@ -176,7 +176,7 @@ | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| #if ! JUCE_VC7_OR_EARLIER | |||||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||||
| #define JUCE_USE_INTRINSICS 1 | #define JUCE_USE_INTRINSICS 1 | ||||
| #endif | #endif | ||||
| #else | #else | ||||
| @@ -17363,9 +17363,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| TimeSliceThread::TimeSliceThread (const String& threadName) | TimeSliceThread::TimeSliceThread (const String& threadName) | ||||
| : Thread (threadName), | : Thread (threadName), | ||||
| index (0), | |||||
| clientBeingCalled (0), | |||||
| clientsChanged (false) | |||||
| clientBeingCalled (0) | |||||
| { | { | ||||
| } | } | ||||
| @@ -17374,18 +17372,20 @@ TimeSliceThread::~TimeSliceThread() | |||||
| stopThread (2000); | 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) | void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client) | ||||
| { | { | ||||
| const ScopedLock sl1 (listLock); | const ScopedLock sl1 (listLock); | ||||
| clientsChanged = true; | |||||
| // if there's a chance we're in the middle of calling this client, we need to | // if there's a chance we're in the middle of calling this client, we need to | ||||
| // also lock the outer lock.. | // also lock the outer lock.. | ||||
| @@ -17415,52 +17415,76 @@ TimeSliceClient* TimeSliceThread::getClient (const int i) const | |||||
| return clients [i]; | 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() | void TimeSliceThread::run() | ||||
| { | { | ||||
| int numCallsSinceBusy = 0; | |||||
| int index = 0; | |||||
| while (! threadShouldExit()) | while (! threadShouldExit()) | ||||
| { | { | ||||
| int timeToWait = 500; | int timeToWait = 500; | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | |||||
| Time nextClientTime; | |||||
| { | { | ||||
| const ScopedLock sl2 (listLock); | 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; | isRunning = false; | ||||
| timeSliceThread.removeTimeSliceClient (this); | timeSliceThread.removeTimeSliceClient (this); | ||||
| while (useTimeSlice()) | |||||
| while (useTimeSlice() == 0) | |||||
| {} | {} | ||||
| } | } | ||||
| @@ -21537,7 +21561,7 @@ public: | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| const int numToDo = getTotalSize() / 4; | const int numToDo = getTotalSize() / 4; | ||||
| @@ -21545,7 +21569,7 @@ public: | |||||
| prepareToRead (numToDo, start1, size1, start2, size2); | prepareToRead (numToDo, start1, size1, start2, size2); | ||||
| if (size1 <= 0) | if (size1 <= 0) | ||||
| return false; | |||||
| return 10; | |||||
| writer->writeFromAudioSampleBuffer (buffer, start1, size1); | writer->writeFromAudioSampleBuffer (buffer, start1, size1); | ||||
| @@ -21566,7 +21590,7 @@ public: | |||||
| } | } | ||||
| finishedRead (size1 + size2); | finishedRead (size1 + size2); | ||||
| return true; | |||||
| return 0; | |||||
| } | } | ||||
| void setThumbnail (AudioThumbnail* thumb) | void setThumbnail (AudioThumbnail* thumb) | ||||
| @@ -21913,8 +21937,7 @@ struct AudioThumbnail::MinMaxValue | |||||
| } | } | ||||
| }; | }; | ||||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient, | |||||
| public Timer | |||||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient | |||||
| { | { | ||||
| public: | public: | ||||
| LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | ||||
| @@ -21934,7 +21957,7 @@ public: | |||||
| owner.cache.removeTimeSliceClient (this); | owner.cache.removeTimeSliceClient (this); | ||||
| } | } | ||||
| enum { timeBeforeDeletingReader = 2000 }; | |||||
| enum { timeBeforeDeletingReader = 1000 }; | |||||
| void initialise (int64 numSamplesFinished_) | void initialise (int64 numSamplesFinished_) | ||||
| { | { | ||||
| @@ -21950,9 +21973,9 @@ public: | |||||
| numChannels = reader->numChannels; | numChannels = reader->numChannels; | ||||
| sampleRate = reader->sampleRate; | sampleRate = reader->sampleRate; | ||||
| if (lengthInSamples <= 0) | |||||
| if (lengthInSamples <= 0 || isFullyLoaded()) | |||||
| reader = 0; | reader = 0; | ||||
| else if (! isFullyLoaded()) | |||||
| else | |||||
| owner.cache.addTimeSliceClient (this); | owner.cache.addTimeSliceClient (this); | ||||
| } | } | ||||
| } | } | ||||
| @@ -21960,7 +21983,14 @@ public: | |||||
| void getLevels (int64 startSample, int numSamples, Array<float>& levels) | void getLevels (int64 startSample, int numSamples, Array<float>& levels) | ||||
| { | { | ||||
| const ScopedLock sl (readerLock); | const ScopedLock sl (readerLock); | ||||
| createReader(); | |||||
| if (reader == 0) | |||||
| { | |||||
| createReader(); | |||||
| if (reader != 0) | |||||
| owner.cache.addTimeSliceClient (this); | |||||
| } | |||||
| if (reader != 0) | if (reader != 0) | ||||
| { | { | ||||
| @@ -21978,19 +22008,16 @@ public: | |||||
| reader = 0; | reader = 0; | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| if (isFullyLoaded()) | if (isFullyLoaded()) | ||||
| { | { | ||||
| if (reader != 0 && source != 0) | if (reader != 0 && source != 0) | ||||
| startTimer (timeBeforeDeletingReader); | |||||
| releaseResources(); | |||||
| owner.cache.removeTimeSliceClient (this); | |||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| stopTimer(); | |||||
| bool justFinished = false; | bool justFinished = false; | ||||
| { | { | ||||
| @@ -22001,7 +22028,7 @@ public: | |||||
| if (reader != 0) | if (reader != 0) | ||||
| { | { | ||||
| if (! readNextBlock()) | if (! readNextBlock()) | ||||
| return true; | |||||
| return 0; | |||||
| justFinished = true; | justFinished = true; | ||||
| } | } | ||||
| @@ -22010,13 +22037,7 @@ public: | |||||
| if (justFinished) | if (justFinished) | ||||
| owner.cache.storeThumb (owner, hashCode); | owner.cache.storeThumb (owner, hashCode); | ||||
| return false; | |||||
| } | |||||
| void timerCallback() | |||||
| { | |||||
| stopTimer(); | |||||
| releaseResources(); | |||||
| return timeBeforeDeletingReader; | |||||
| } | } | ||||
| bool isFullyLoaded() const throw() | bool isFullyLoaded() const throw() | ||||
| @@ -57840,7 +57861,7 @@ void DirectoryContentsList::changed() | |||||
| sendChangeMessage(); | sendChangeMessage(); | ||||
| } | } | ||||
| bool DirectoryContentsList::useTimeSlice() | |||||
| int DirectoryContentsList::useTimeSlice() | |||||
| { | { | ||||
| const uint32 startTime = Time::getApproximateMillisecondCounter(); | const uint32 startTime = Time::getApproximateMillisecondCounter(); | ||||
| bool hasChanged = false; | bool hasChanged = false; | ||||
| @@ -57852,7 +57873,7 @@ bool DirectoryContentsList::useTimeSlice() | |||||
| if (hasChanged) | if (hasChanged) | ||||
| changed(); | changed(); | ||||
| return false; | |||||
| return 500; | |||||
| } | } | ||||
| if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | ||||
| @@ -57862,7 +57883,7 @@ bool DirectoryContentsList::useTimeSlice() | |||||
| if (hasChanged) | if (hasChanged) | ||||
| changed(); | changed(); | ||||
| return true; | |||||
| return 0; | |||||
| } | } | ||||
| bool DirectoryContentsList::checkNextFile (bool& hasChanged) | bool DirectoryContentsList::checkNextFile (bool& hasChanged) | ||||
| @@ -58957,10 +58978,10 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| updateIcon (false); | updateIcon (false); | ||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| void handleAsyncUpdate() | void handleAsyncUpdate() | ||||
| @@ -59655,11 +59676,10 @@ public: | |||||
| owner.sendSelectionChangeMessage(); | owner.sendSelectionChangeMessage(); | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| updateIcon (false); | updateIcon (false); | ||||
| thread.removeTimeSliceClient (this); | |||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| void handleAsyncUpdate() | void handleAsyncUpdate() | ||||
| @@ -61201,7 +61221,7 @@ public: | |||||
| component->setVisible (! useProxyComponent); | component->setVisible (! useProxyComponent); | ||||
| } | } | ||||
| bool useTimeslice (const int elapsed) | |||||
| int useTimeslice (const int elapsed) | |||||
| { | { | ||||
| Component* const c = proxy != 0 ? static_cast <Component*> (proxy) | Component* const c = proxy != 0 ? static_cast <Component*> (proxy) | ||||
| : static_cast <Component*> (component); | : static_cast <Component*> (component); | ||||
| @@ -61249,13 +61269,13 @@ public: | |||||
| } | } | ||||
| if (stillBusy) | if (stillBusy) | ||||
| return true; | |||||
| return 0; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| moveToFinalDestination(); | moveToFinalDestination(); | ||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| void moveToFinalDestination() | void moveToFinalDestination() | ||||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 15 | |||||
| #define JUCE_BUILDNUMBER 16 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -223,7 +223,7 @@ namespace JuceDummyNamespace {} | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| #if ! JUCE_VC7_OR_EARLIER | |||||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||||
| #define JUCE_USE_INTRINSICS 1 | #define JUCE_USE_INTRINSICS 1 | ||||
| #endif | #endif | ||||
| #else | #else | ||||
| @@ -19825,6 +19825,8 @@ private: | |||||
| #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ | #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ | ||||
| #define __JUCE_TIMESLICETHREAD_JUCEHEADER__ | #define __JUCE_TIMESLICETHREAD_JUCEHEADER__ | ||||
| class TimeSliceThread; | |||||
| /** | /** | ||||
| Used by the TimeSliceThread class. | 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 | The implementation of this method should use its time-slice to do something that's | ||||
| quick - never block for longer than absolutely necessary. | 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. | /** 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. | /** Removes a client from the list. | ||||
| @@ -19912,9 +19919,9 @@ public: | |||||
| private: | private: | ||||
| CriticalSection callbackLock, listLock; | CriticalSection callbackLock, listLock; | ||||
| Array <TimeSliceClient*> clients; | Array <TimeSliceClient*> clients; | ||||
| int index; | |||||
| TimeSliceClient* clientBeingCalled; | TimeSliceClient* clientBeingCalled; | ||||
| bool clientsChanged; | |||||
| TimeSliceClient* getNextClient (int index) const; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | ||||
| }; | }; | ||||
| @@ -51277,7 +51284,7 @@ public: | |||||
| const FileFilter* getFilter() const { return fileFilter; } | const FileFilter* getFilter() const { return fileFilter; } | ||||
| /** @internal */ | /** @internal */ | ||||
| bool useTimeSlice(); | |||||
| int useTimeSlice(); | |||||
| /** @internal */ | /** @internal */ | ||||
| TimeSliceThread& getTimeSliceThread() { return thread; } | TimeSliceThread& getTimeSliceThread() { return thread; } | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -201,7 +201,7 @@ public: | |||||
| isRunning = false; | isRunning = false; | ||||
| timeSliceThread.removeTimeSliceClient (this); | timeSliceThread.removeTimeSliceClient (this); | ||||
| while (useTimeSlice()) | |||||
| while (useTimeSlice() == 0) | |||||
| {} | {} | ||||
| } | } | ||||
| @@ -229,7 +229,7 @@ public: | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| const int numToDo = getTotalSize() / 4; | const int numToDo = getTotalSize() / 4; | ||||
| @@ -237,7 +237,7 @@ public: | |||||
| prepareToRead (numToDo, start1, size1, start2, size2); | prepareToRead (numToDo, start1, size1, start2, size2); | ||||
| if (size1 <= 0) | if (size1 <= 0) | ||||
| return false; | |||||
| return 10; | |||||
| writer->writeFromAudioSampleBuffer (buffer, start1, size1); | writer->writeFromAudioSampleBuffer (buffer, start1, size1); | ||||
| @@ -258,7 +258,7 @@ public: | |||||
| } | } | ||||
| finishedRead (size1 + size2); | finishedRead (size1 + size2); | ||||
| return true; | |||||
| return 0; | |||||
| } | } | ||||
| void setThumbnail (AudioThumbnail* thumb) | void setThumbnail (AudioThumbnail* thumb) | ||||
| @@ -82,8 +82,7 @@ struct AudioThumbnail::MinMaxValue | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient, | |||||
| public Timer | |||||
| class AudioThumbnail::LevelDataSource : public TimeSliceClient | |||||
| { | { | ||||
| public: | public: | ||||
| LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash) | ||||
| @@ -103,7 +102,7 @@ public: | |||||
| owner.cache.removeTimeSliceClient (this); | owner.cache.removeTimeSliceClient (this); | ||||
| } | } | ||||
| enum { timeBeforeDeletingReader = 2000 }; | |||||
| enum { timeBeforeDeletingReader = 1000 }; | |||||
| void initialise (int64 numSamplesFinished_) | void initialise (int64 numSamplesFinished_) | ||||
| { | { | ||||
| @@ -119,9 +118,9 @@ public: | |||||
| numChannels = reader->numChannels; | numChannels = reader->numChannels; | ||||
| sampleRate = reader->sampleRate; | sampleRate = reader->sampleRate; | ||||
| if (lengthInSamples <= 0) | |||||
| if (lengthInSamples <= 0 || isFullyLoaded()) | |||||
| reader = 0; | reader = 0; | ||||
| else if (! isFullyLoaded()) | |||||
| else | |||||
| owner.cache.addTimeSliceClient (this); | owner.cache.addTimeSliceClient (this); | ||||
| } | } | ||||
| } | } | ||||
| @@ -129,7 +128,14 @@ public: | |||||
| void getLevels (int64 startSample, int numSamples, Array<float>& levels) | void getLevels (int64 startSample, int numSamples, Array<float>& levels) | ||||
| { | { | ||||
| const ScopedLock sl (readerLock); | const ScopedLock sl (readerLock); | ||||
| createReader(); | |||||
| if (reader == 0) | |||||
| { | |||||
| createReader(); | |||||
| if (reader != 0) | |||||
| owner.cache.addTimeSliceClient (this); | |||||
| } | |||||
| if (reader != 0) | if (reader != 0) | ||||
| { | { | ||||
| @@ -147,19 +153,16 @@ public: | |||||
| reader = 0; | reader = 0; | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| if (isFullyLoaded()) | if (isFullyLoaded()) | ||||
| { | { | ||||
| if (reader != 0 && source != 0) | if (reader != 0 && source != 0) | ||||
| startTimer (timeBeforeDeletingReader); | |||||
| releaseResources(); | |||||
| owner.cache.removeTimeSliceClient (this); | |||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| stopTimer(); | |||||
| bool justFinished = false; | bool justFinished = false; | ||||
| { | { | ||||
| @@ -170,7 +173,7 @@ public: | |||||
| if (reader != 0) | if (reader != 0) | ||||
| { | { | ||||
| if (! readNextBlock()) | if (! readNextBlock()) | ||||
| return true; | |||||
| return 0; | |||||
| justFinished = true; | justFinished = true; | ||||
| } | } | ||||
| @@ -179,13 +182,7 @@ public: | |||||
| if (justFinished) | if (justFinished) | ||||
| owner.cache.storeThumb (owner, hashCode); | owner.cache.storeThumb (owner, hashCode); | ||||
| return false; | |||||
| } | |||||
| void timerCallback() | |||||
| { | |||||
| stopTimer(); | |||||
| releaseResources(); | |||||
| return timeBeforeDeletingReader; | |||||
| } | } | ||||
| bool isFullyLoaded() const throw() | bool isFullyLoaded() const throw() | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 15 | |||||
| #define JUCE_BUILDNUMBER 16 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -166,7 +166,7 @@ | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| #if ! JUCE_VC7_OR_EARLIER | |||||
| #if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER) | |||||
| #define JUCE_USE_INTRINSICS 1 | #define JUCE_USE_INTRINSICS 1 | ||||
| #endif | #endif | ||||
| #else | #else | ||||
| @@ -165,7 +165,7 @@ void DirectoryContentsList::changed() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| bool DirectoryContentsList::useTimeSlice() | |||||
| int DirectoryContentsList::useTimeSlice() | |||||
| { | { | ||||
| const uint32 startTime = Time::getApproximateMillisecondCounter(); | const uint32 startTime = Time::getApproximateMillisecondCounter(); | ||||
| bool hasChanged = false; | bool hasChanged = false; | ||||
| @@ -177,7 +177,7 @@ bool DirectoryContentsList::useTimeSlice() | |||||
| if (hasChanged) | if (hasChanged) | ||||
| changed(); | changed(); | ||||
| return false; | |||||
| return 500; | |||||
| } | } | ||||
| if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) | ||||
| @@ -187,7 +187,7 @@ bool DirectoryContentsList::useTimeSlice() | |||||
| if (hasChanged) | if (hasChanged) | ||||
| changed(); | changed(); | ||||
| return true; | |||||
| return 0; | |||||
| } | } | ||||
| bool DirectoryContentsList::checkNextFile (bool& hasChanged) | bool DirectoryContentsList::checkNextFile (bool& hasChanged) | ||||
| @@ -185,7 +185,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** @internal */ | /** @internal */ | ||||
| bool useTimeSlice(); | |||||
| int useTimeSlice(); | |||||
| /** @internal */ | /** @internal */ | ||||
| TimeSliceThread& getTimeSliceThread() { return thread; } | TimeSliceThread& getTimeSliceThread() { return thread; } | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -165,10 +165,10 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| updateIcon (false); | updateIcon (false); | ||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| void handleAsyncUpdate() | void handleAsyncUpdate() | ||||
| @@ -173,11 +173,10 @@ public: | |||||
| owner.sendSelectionChangeMessage(); | owner.sendSelectionChangeMessage(); | ||||
| } | } | ||||
| bool useTimeSlice() | |||||
| int useTimeSlice() | |||||
| { | { | ||||
| updateIcon (false); | updateIcon (false); | ||||
| thread.removeTimeSliceClient (this); | |||||
| return false; | |||||
| return -1; | |||||
| } | } | ||||
| void handleAsyncUpdate() | void handleAsyncUpdate() | ||||
| @@ -34,9 +34,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| TimeSliceThread::TimeSliceThread (const String& threadName) | TimeSliceThread::TimeSliceThread (const String& threadName) | ||||
| : Thread (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) | void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client) | ||||
| { | { | ||||
| const ScopedLock sl1 (listLock); | const ScopedLock sl1 (listLock); | ||||
| clientsChanged = true; | |||||
| // if there's a chance we're in the middle of calling this client, we need to | // if there's a chance we're in the middle of calling this client, we need to | ||||
| // also lock the outer lock.. | // 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() | void TimeSliceThread::run() | ||||
| { | { | ||||
| int numCallsSinceBusy = 0; | |||||
| int index = 0; | |||||
| while (! threadShouldExit()) | while (! threadShouldExit()) | ||||
| { | { | ||||
| int timeToWait = 500; | int timeToWait = 500; | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | |||||
| Time nextClientTime; | |||||
| { | { | ||||
| const ScopedLock sl2 (listLock); | 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 "juce_Thread.h" | ||||
| #include "../containers/juce_Array.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 | The implementation of this method should use its time-slice to do something that's | ||||
| quick - never block for longer than absolutely necessary. | 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. | /** 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. | /** Removes a client from the list. | ||||
| @@ -123,9 +130,9 @@ public: | |||||
| private: | private: | ||||
| CriticalSection callbackLock, listLock; | CriticalSection callbackLock, listLock; | ||||
| Array <TimeSliceClient*> clients; | Array <TimeSliceClient*> clients; | ||||
| int index; | |||||
| TimeSliceClient* clientBeingCalled; | TimeSliceClient* clientBeingCalled; | ||||
| bool clientsChanged; | |||||
| TimeSliceClient* getNextClient (int index) const; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); | ||||
| }; | }; | ||||