• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Sound Manager & MIDI callbacks, interrupts and threads
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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.
  • Prev by Date: Re: Sound Manager & MIDI callbacks, interrupts and threads
  • Next by Date: Re: Multiple devices
  • Previous by thread: Re: Sound Manager & MIDI callbacks, interrupts and threads
  • Next by thread: Re: Sound Manager & MIDI callbacks, interrupts and threads
  • Index(es):
    • Date
    • Thread