Browse Source

Changed the return type of TimeSliceThreadClient::useTimeSlice().

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
7bfa419f17
12 changed files with 224 additions and 170 deletions
  1. +92
    -72
      juce_amalgamated.cpp
  2. +21
    -14
      juce_amalgamated.h
  3. +4
    -4
      src/audio/audio_file_formats/juce_AudioFormatWriter.cpp
  4. +17
    -20
      src/audio/audio_file_formats/juce_AudioThumbnail.cpp
  5. +1
    -1
      src/core/juce_StandardHeader.h
  6. +1
    -1
      src/core/juce_TargetPlatform.h
  7. +3
    -3
      src/gui/components/filebrowser/juce_DirectoryContentsList.cpp
  8. +1
    -1
      src/gui/components/filebrowser/juce_DirectoryContentsList.h
  9. +2
    -2
      src/gui/components/filebrowser/juce_FileListComponent.cpp
  10. +2
    -3
      src/gui/components/filebrowser/juce_FileTreeComponent.cpp
  11. +61
    -37
      src/threads/juce_TimeSliceThread.cpp
  12. +19
    -12
      src/threads/juce_TimeSliceThread.h

+ 92
- 72
juce_amalgamated.cpp View File

@@ -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()


+ 21
- 14
juce_amalgamated.h View File

@@ -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 */


+ 4
- 4
src/audio/audio_file_formats/juce_AudioFormatWriter.cpp View File

@@ -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)


+ 17
- 20
src/audio/audio_file_formats/juce_AudioThumbnail.cpp View File

@@ -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()


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -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.


+ 1
- 1
src/core/juce_TargetPlatform.h View File

@@ -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


+ 3
- 3
src/gui/components/filebrowser/juce_DirectoryContentsList.cpp View File

@@ -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)


+ 1
- 1
src/gui/components/filebrowser/juce_DirectoryContentsList.h View File

@@ -185,7 +185,7 @@ public:
//==============================================================================
/** @internal */
bool useTimeSlice();
int useTimeSlice();
/** @internal */
TimeSliceThread& getTimeSliceThread() { return thread; }
/** @internal */


+ 2
- 2
src/gui/components/filebrowser/juce_FileListComponent.cpp View File

@@ -165,10 +165,10 @@ public:
}
}
bool useTimeSlice()
int useTimeSlice()
{
updateIcon (false);
return false;
return -1;
}
void handleAsyncUpdate()


+ 2
- 3
src/gui/components/filebrowser/juce_FileTreeComponent.cpp View File

@@ -173,11 +173,10 @@ public:
owner.sendSelectionChangeMessage();
}
bool useTimeSlice()
int useTimeSlice()
{
updateIcon (false);
thread.removeTimeSliceClient (this);
return false;
return -1;
}
void handleAsyncUpdate()


+ 61
- 37
src/threads/juce_TimeSliceThread.cpp View File

@@ -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;
}
}
}


+ 19
- 12
src/threads/juce_TimeSliceThread.h View File

@@ -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);
};


Loading…
Cancel
Save