Re: Sound Manager & MIDI callbacks, interrupts and threads
Re: Sound Manager & MIDI callbacks, interrupts and threads
- Subject: Re: Sound Manager & MIDI callbacks, interrupts and threads
- From: Herbie Robinson <email@hidden>
- Date: Sat, 16 Feb 2002 21:08:51 -0500
I have a couple of callbacks in an app I'm now converting to OS-X Mach-
O, which I'm worried about. They work fine but I'm worried about
possible collision/crashes.
One is Sound Manager - I'm doing audio output, so I pass a callback func
to SndNewChannel which gets notified when a block is consumed.
The other is MIDI input, where we give a callback to MIDIInputPortCreate
which gets called when MIDI data arrives.
Both these callbacks communicate with the main app code via queues, so
there are brief moments of queue-manipulation when it would be fatal for
one to interrupt the other and access the queue.
On classic Mac (AFAI understand it) these callbacks were called at
"interrupt time" so there was never any danger of the main app
interrupting the callback. To prevent the callback interrupting the main
app I would briefly disable interrupts using InterruptDisableLib.c as
provided by Apple. This uses assembly code which doesn't work on Mach-O.
I'm not at all clear what the situation is now. Is the callback running
in some pre-emptive thread? Do I need to worry about the main app
interrupting the callback?
That's the million dollar question. It depends on what the main
app's execution environment is and how the I/O is being done. In
many cases, there is a single thread using something called CFRunLoop
to schedule everything, but it doesn't have to be that way (and in
fact, I think it changes from release to release). This is a guess,
but I think Apple has been non-specific about this precisely because
it is a moving target. It is probably safest to assume the callbacks
are in different threads. If the callbacks are in different threads,
the callback could be running one CPU while the application is
running on another. You can probably assume that a given callback
will always come from the same thread; so, multiple instances of the
same callback can't happen in parallel (if one is writing interrupt
code on an MP machine, one is not that lucky). The thread context on
OS X is also much more robust than the interrupt context: It can
block.
The only exception I know for this is that the MIDI Server has
specified which threads the MIDI driver calls are done from.
And how can I prevent (for brief moments) the callback interrupting
the main app?
You have two choices here:
1. Use a queue structure that doesn't require locking (i.e., one way
circular lists with one producer and one consumer).
2. Hold a lock while threading and un-threading.
Getting away without a lock is really tricky. Whatever mechanism you
use must be able to commit and remove messages from the queue with a
single bus transaction (not necessarily even a single instruction).
The only queue I know of that works is a circular buffer.
Using a lock is the other way to go. The idea is to define a lock to
protect a particular data structure (in this case, a queue). You
lock the lock before accessing the data structure and unlock the lock
when you are done. It's the OS's job to make sure only one thread
can execute with the lock held.
I believe there are at least two different implementations of locks in OS X:
The carbon interface includes locks in the Multi-processor support
package. I have used these. The documentation for these is on
Apple's web site someplace (search for MPCreateCriticalRegion). This
API also includes some messaging interfaces which might let you avoid
using your queues altogether (and might perform better, because MACH
uses message passing as the primitive kernel interface -- everything
else is built using message passing).
The Unix thread implementation includes locks (they call them
mutex's, but it's the same thing). Outside of the POSIX standard, I
don't know where to find documentation on these (I'm looking, too).
I broke down and bought Stevens a few weeks ago, because it was
supposed to be a complete Unix/POSIX reference, but it doesn't have
threads in it (!@#$%^).
Some things to be aware of:
If the callback requires extremely low latency (the MIDI one probably
doesn't, but the Sound one might), then you need to make sure the
code doesn't take page faults (a page fault will take a few msec if
it needs to go to disk). The API should have taken care of wiring
the thread it's running on and any buffers passed to the callback.
[Wiring means marking memory so it can't be paged out.] Any other
structures touched by the callback should also be wired. Now, here's
the tricky part: The code, stack and heap that gets touched while
the lock is held also has to be wired (at least while the lock is
held).
--
-*****************************************
**
http://www.curbside-recording.com/ **
******************************************
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.