1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-05 03:50:07 +00:00

Changed the Message class to be reference-counted, and used this to tighten up some messaging code. Minor tweaks to AudioThumbnail, ReferenceCountedArray.

This commit is contained in:
Julian Storer 2010-12-19 19:33:52 +00:00
parent 1a887cda63
commit d60f661789
22 changed files with 573 additions and 527 deletions

View file

@ -21666,7 +21666,7 @@ public:
void setThumbnail (AudioThumbnail* thumb)
{
if (thumb != 0)
thumb->reset (buffer.getNumChannels(), writer->getSampleRate());
thumb->reset (buffer.getNumChannels(), writer->getSampleRate(), 0);
const ScopedLock sl (thumbnailLock);
thumbnailToUpdate = thumb;
@ -22475,14 +22475,15 @@ void AudioThumbnail::clear()
sendChangeMessage();
}
void AudioThumbnail::reset (int newNumChannels, double newSampleRate)
void AudioThumbnail::reset (int newNumChannels, double newSampleRate, int64 totalSamplesInSource)
{
clear();
numChannels = newNumChannels;
sampleRate = newSampleRate;
totalSamples = totalSamplesInSource;
createChannels (0);
createChannels (1 + (int) (totalSamplesInSource / samplesPerThumbSample));
}
void AudioThumbnail::createChannels (const int length)
@ -38416,28 +38417,34 @@ END_JUCE_NAMESPACE
/*** Start of inlined file: juce_AsyncUpdater.cpp ***/
BEGIN_JUCE_NAMESPACE
class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage
class AsyncUpdaterMessage : public CallbackMessage
{
public:
AsyncUpdaterMessage (AsyncUpdater& owner_)
: owner (owner_)
{
setMessageIsDeletedOnDelivery (false);
}
void messageCallback()
{
if (owner.pendingMessage.compareAndSetBool (0, this))
if (shouldDeliver.compareAndSetBool (0, 1))
owner.handleAsyncUpdate();
}
Atomic<int> shouldDeliver;
private:
AsyncUpdater& owner;
};
AsyncUpdater::AsyncUpdater()
: message (new AsyncUpdaterMessage (*this))
{
message = new AsyncUpdaterMessage (*this);
}
inline Atomic<int>& AsyncUpdater::getDeliveryFlag() const throw()
{
return static_cast <AsyncUpdaterMessage*> (message.getObject())->shouldDeliver;
}
AsyncUpdater::~AsyncUpdater()
@ -38448,19 +38455,18 @@ AsyncUpdater::~AsyncUpdater()
// deleting this object, or find some other way to avoid such a race condition.
jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager());
if (pendingMessage.exchange (0) != 0)
message.release()->setMessageIsDeletedOnDelivery (true);
getDeliveryFlag().set (0);
}
void AsyncUpdater::triggerAsyncUpdate()
{
if (pendingMessage.compareAndSetBool (message, 0))
if (getDeliveryFlag().compareAndSetBool (1, 0))
message->post();
}
void AsyncUpdater::cancelPendingUpdate() throw()
{
pendingMessage = 0;
getDeliveryFlag().set (0);
}
void AsyncUpdater::handleUpdateNowIfNeeded()
@ -38468,13 +38474,13 @@ void AsyncUpdater::handleUpdateNowIfNeeded()
// This can only be called by the event thread.
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
if (pendingMessage.exchange (0) != 0)
if (getDeliveryFlag().exchange (0) != 0)
handleAsyncUpdate();
}
bool AsyncUpdater::isUpdatePending() const throw()
{
return pendingMessage.value != 0;
return getDeliveryFlag().value != 0;
}
END_JUCE_NAMESPACE
@ -39088,10 +39094,10 @@ MessageManager* MessageManager::getInstance() throw()
void MessageManager::postMessageToQueue (Message* const message)
{
if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
delete message;
Message::Ptr deleter (message); // (this will delete messages that were just created with a 0 ref count)
}
CallbackMessage::CallbackMessage() throw() : deleteOnDelivery (true) {}
CallbackMessage::CallbackMessage() throw() {}
CallbackMessage::~CallbackMessage() {}
void CallbackMessage::post()
@ -39105,7 +39111,6 @@ void MessageManager::deliverMessage (Message* const message)
{
JUCE_TRY
{
ScopedPointer <Message> messageDeleter (message);
MessageListener* const recipient = message->messageRecipient;
if (recipient == 0)
@ -39115,9 +39120,6 @@ void MessageManager::deliverMessage (Message* const message)
if (callbackMessage != 0)
{
callbackMessage->messageCallback();
if (! callbackMessage->isMessageDeletedOnDelivery())
messageDeleter.release();
}
else if (message->intParameter1 == quitMessageId)
{
@ -39200,9 +39202,11 @@ bool MessageManager::isThisTheMessageThread() const throw()
void MessageManager::setCurrentThreadAsMessageThread()
{
if (messageThreadId != Thread::getCurrentThreadId())
const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
if (messageThreadId != thisThread)
{
messageThreadId = Thread::getCurrentThreadId();
messageThreadId = thisThread;
// This is needed on windows to make sure the message window is created by this thread
doPlatformSpecificShutdown();
@ -39225,47 +39229,31 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw()
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
in Cocoa).
*/
class MessageManagerLock::SharedEvents : public ReferenceCountedObject
{
public:
SharedEvents() {}
/* 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:
JUCE_DECLARE_NON_COPYABLE (SharedEvents);
};
class MessageManagerLock::BlockingMessage : public CallbackMessage
{
public:
BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {}
BlockingMessage() {}
void messageCallback()
{
events->lockedEvent.signal();
events->releaseEvent.wait();
lockedEvent.signal();
releaseEvent.wait();
}
private:
ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events;
WaitableEvent lockedEvent, releaseEvent;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage);
};
MessageManagerLock::MessageManagerLock (Thread* const threadToCheck)
: sharedEvents (0),
locked (false)
: locked (false)
{
init (threadToCheck, 0);
}
MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal)
: sharedEvents (0),
locked (false)
: locked (false)
{
init (0, jobToCheckForExitSignal);
}
@ -39296,19 +39284,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
}
}
sharedEvents = new SharedEvents();
sharedEvents->incReferenceCount();
blockingMessage = new BlockingMessage();
blockingMessage->post();
(new BlockingMessage (sharedEvents))->post();
while (! sharedEvents->lockedEvent.wait (50))
while (! blockingMessage->lockedEvent.wait (20))
{
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|| (job != 0 && job->shouldExit()))
{
sharedEvents->releaseEvent.signal();
sharedEvents->decReferenceCount();
sharedEvents = 0;
blockingMessage->releaseEvent.signal();
blockingMessage = 0;
MessageManager::instance->lockingLock.exit();
return;
}
@ -39324,12 +39309,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
MessageManagerLock::~MessageManagerLock() throw()
{
if (sharedEvents != 0)
if (blockingMessage != 0)
{
jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager());
sharedEvents->releaseEvent.signal();
sharedEvents->decReferenceCount();
blockingMessage->releaseEvent.signal();
blockingMessage = 0;
if (MessageManager::instance != 0)
{
@ -39478,6 +39463,7 @@ public:
void run()
{
uint32 lastTime = Time::getMillisecondCounter();
Message::Ptr message (new Message());
while (! threadShouldExit())
{
@ -39503,7 +39489,7 @@ public:
*/
if (callbackNeeded.compareAndSetBool (1, 0))
{
postMessage (new Message());
postMessage (message);
/* Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
when the app has a modal loop), so this is how long to wait before assuming the
@ -41290,6 +41276,10 @@ void Component::exitModalState (const int returnValue)
}
else
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
class ExitModalStateMessage : public CallbackMessage
{
public:
@ -41854,6 +41844,10 @@ void Component::parentSizeChanged()
void Component::addComponentListener (ComponentListener* const newListener)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
componentListeners.add (newListener);
}
@ -41895,6 +41889,10 @@ void Component::paintOverChildren (Graphics&)
void Component::postCommandMessage (const int commandId)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
class CustomCommandMessage : public CallbackMessage
{
public:
@ -239896,7 +239894,9 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h,
// here in case there are windows modal dialog boxes doing their own
// dispatch loop and not calling our version
MessageManager::getInstance()->deliverMessage ((Message*) lParam);
Message* const message = reinterpret_cast <Message*> (lParam);
MessageManager::getInstance()->deliverMessage (message);
message->decReferenceCount();
return 0;
}
else if (message == broadcastId)
@ -239984,7 +239984,9 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
{
if (m.message == specialId && m.hwnd == juce_messageWindowHandle)
{
MessageManager::getInstance()->deliverMessage ((Message*) (void*) m.lParam);
Message* const message = reinterpret_cast <Message*> (m.lParam);
MessageManager::getInstance()->deliverMessage (message);
message->decReferenceCount();
}
else if (m.message == WM_QUIT)
{
@ -240014,6 +240016,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
bool juce_postMessageToSystemQueue (Message* message)
{
message->incReferenceCount();
return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0;
}
@ -255883,7 +255886,7 @@ public:
private:
CriticalSection lock;
OwnedArray <Message> queue;
ReferenceCountedArray <Message> queue;
int fd[2];
int bytesInSocket;
int totalEventCount;
@ -255923,15 +255926,15 @@ private:
return true;
}
Message* popNextMessage()
const Message::Ptr popNextMessage()
{
ScopedLock sl (lock);
const ScopedLock sl (lock);
if (bytesInSocket > 0)
{
--bytesInSocket;
ScopedUnlock ul (lock);
const ScopedUnlock ul (lock);
unsigned char x;
size_t numBytes = read (fd[1], &x, 1);
(void) numBytes;
@ -255942,7 +255945,7 @@ private:
bool dispatchNextInternalMessage()
{
ScopedPointer <Message> msg (popNextMessage());
const Message::Ptr msg (popNextMessage());
if (msg == 0)
return false;
@ -255958,7 +255961,7 @@ private:
else
{
// Handle "normal" messages
MessageManager::getInstance()->deliverMessage (msg.release());
MessageManager::getInstance()->deliverMessage (msg);
}
return true;
@ -262337,6 +262340,73 @@ namespace
}
}
class MessageQueue
{
public:
MessageQueue()
{
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 && ! JUCE_IOS
runLoop = CFRunLoopGetMain();
#else
runLoop = CFRunLoopGetCurrent();
#endif
CFRunLoopSourceContext sourceContext;
zerostruct (sourceContext);
sourceContext.info = this;
sourceContext.perform = runLoopSourceCallback;
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
}
~MessageQueue()
{
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
CFRunLoopSourceInvalidate (runLoopSource);
CFRelease (runLoopSource);
}
void post (Message* const message)
{
messages.add (message);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
private:
ReferenceCountedArray <Message, CriticalSection> messages;
CriticalSection lock;
CFRunLoopRef runLoop;
CFRunLoopSourceRef runLoopSource;
bool deliverNextMessage()
{
const Message::Ptr nextMessage (messages.removeAndReturn (0));
if (nextMessage == 0)
return false;
const ScopedAutoReleasePool pool;
MessageManager::getInstance()->deliverMessage (nextMessage);
return true;
}
void runLoopCallback()
{
for (int i = 4; --i >= 0;)
if (! deliverNextMessage())
return;
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
static void runLoopSourceCallback (void* info)
{
static_cast <MessageQueue*> (info)->runLoopCallback();
}
};
#define JUCE_INCLUDED_FILE 1
// Now include the actual code files..
@ -264281,12 +264351,12 @@ const File File::getSpecialLocation (const SpecialLocationType type)
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
#if JUCE_IOS
case userDocumentsDirectory: resultPath = getIOSSystemLocation (NSDocumentDirectory); break;
case userDesktopDirectory: resultPath = getIOSSystemLocation (NSDesktopDirectory); break;
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
case tempDirectory:
{
File tmp (getIOSSystemLocation (NSCachesDirectory));
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
@ -267433,79 +267503,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
return ! quitMessagePosted;
}
namespace iOSMessageLoopHelpers
struct MessageDispatchSystem
{
static CFRunLoopRef runLoop = 0;
static CFRunLoopSourceRef runLoopSource = 0;
static OwnedArray <Message, CriticalSection>* pendingMessages = 0;
static JuceCustomMessageHandler* juceCustomMessageHandler = 0;
void runLoopSourceCallback (void*)
MessageDispatchSystem()
: juceCustomMessageHandler (0)
{
if (pendingMessages != 0)
{
int numDispatched = 0;
do
{
Message* const nextMessage = pendingMessages->removeAndReturn (0);
if (nextMessage == 0)
return;
const ScopedAutoReleasePool pool;
MessageManager::getInstance()->deliverMessage (nextMessage);
} while (++numDispatched <= 4);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
}
}
~MessageDispatchSystem()
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
[juceCustomMessageHandler release];
}
JuceCustomMessageHandler* juceCustomMessageHandler;
MessageQueue messageQueue;
};
static MessageDispatchSystem* dispatcher = 0;
void MessageManager::doPlatformSpecificInitialisation()
{
using namespace iOSMessageLoopHelpers;
pendingMessages = new OwnedArray <Message, CriticalSection>();
runLoop = CFRunLoopGetCurrent();
CFRunLoopSourceContext sourceContext;
zerostruct (sourceContext);
sourceContext.perform = runLoopSourceCallback;
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
if (juceCustomMessageHandler == 0)
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
if (dispatcher == 0)
dispatcher = new MessageDispatchSystem();
}
void MessageManager::doPlatformSpecificShutdown()
{
using namespace iOSMessageLoopHelpers;
CFRunLoopSourceInvalidate (runLoopSource);
CFRelease (runLoopSource);
runLoopSource = 0;
deleteAndZero (pendingMessages);
if (juceCustomMessageHandler != 0)
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
[juceCustomMessageHandler release];
juceCustomMessageHandler = 0;
}
deleteAndZero (dispatcher);
}
bool juce_postMessageToSystemQueue (Message* message)
{
using namespace iOSMessageLoopHelpers;
if (pendingMessages != 0)
{
pendingMessages->add (message);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
if (dispatcher != 0)
dispatcher->messageQueue.post (message);
return true;
}
@ -267516,14 +267548,14 @@ void MessageManager::broadcastMessage (const String& value)
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data)
{
using namespace iOSMessageLoopHelpers;
if (isThisTheMessageThread())
{
return (*callback) (data);
}
else
{
jassert (dispatcher != 0); // trying to call this when the juce system isn't initialised..
// If a thread has a MessageManagerLock and then tries to call this method, it'll
// deadlock because the message manager is blocked from running, so can never
// call your function..
@ -267537,11 +267569,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call
cmp.result = 0;
cmp.hasBeenExecuted = false;
[juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
withObject: [NSData dataWithBytesNoCopy: &cmp
length: sizeof (cmp)
freeWhenDone: NO]
waitUntilDone: YES];
[dispatcher->juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
withObject: [NSData dataWithBytesNoCopy: &cmp
length: sizeof (cmp)
freeWhenDone: NO]
waitUntilDone: YES];
return cmp.result;
}
@ -275660,24 +275692,10 @@ class AppDelegateRedirector
public:
AppDelegateRedirector()
{
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
runLoop = CFRunLoopGetMain();
#else
runLoop = CFRunLoopGetCurrent();
#endif
CFRunLoopSourceContext sourceContext;
zerostruct (sourceContext);
sourceContext.info = this;
sourceContext.perform = runLoopSourceCallback;
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
}
virtual ~AppDelegateRedirector()
{
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
CFRunLoopSourceInvalidate (runLoopSource);
CFRelease (runLoopSource);
}
virtual NSApplicationTerminateReply shouldTerminate()
@ -275753,40 +275771,13 @@ public:
void postMessage (Message* const m)
{
messages.add (m);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
messageQueue.post (m);
}
private:
CFRunLoopRef runLoop;
CFRunLoopSourceRef runLoopSource;
OwnedArray <Message, CriticalSection> messages;
void runLoopCallback()
{
int numDispatched = 0;
do
{
Message* const nextMessage = messages.removeAndReturn (0);
if (nextMessage == 0)
return;
const ScopedAutoReleasePool pool;
MessageManager::getInstance()->deliverMessage (nextMessage);
} while (++numDispatched <= 4);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
static void runLoopSourceCallback (void* info)
{
static_cast <AppDelegateRedirector*> (info)->runLoopCallback();
}
MessageQueue messageQueue;
};
END_JUCE_NAMESPACE