C volatile equivalent

The use of Locks and mutexes is illegal in hard real-time callbacks. Lock free variables can be read and written in different threads. In C, the language definition may or may not be broken, but most compilers (llvm included) spit out usable assembly code given that a C variable is declared volatile (the reader thread treats the variable as as hardware register and thus actually issues load instructions before using the variable, which works well enough on most cache-coherent multiprocessor systems, e.g. iOS devices.) Can this type of variable access be stated in Swift? Or does in-line assembly language or data cache flush/invalidate hints need to be added to the Swift language instead?

Replies

Swift does not (yet) have a well-defined memory model, so there’s no direct equivalent of C’s

volatile
.

Having said that, C didn’t have a well-defined memory model until C11 either, so you can go a long way without one (-:

However, in most cases

volatile
is completely pointless when it comes to lock-free data structures. There are two aspects to those:
  • the compiler

  • the CPU

volatile
only affects the compiler, and you can achieve similar results by calling a non-inlined function (that is, the compiler has to ensure that changes are pushed to memory before the function call and are read from memory after). The more gnarly case is the CPU, and
volatile
does not help there at all.

iOS devices use a very weak memory model (similar to PowerPC, that is, as weak than anything else except DEC Alpha) and thus the order of load and store instructions issued to the CPU by the compiler has no effect on the order they’re seen in memory. To control that you need a memory barrier (technically, one of N different styles of memory barrier).

The traditional approach to fixing this in C is to define atomic functions that can’t be inlined (avoids compiler problems) and that use a memory barrier (avoids CPU problems). You could apply similar logic to Swift code but, as in traditional C, there’s no guarantees.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

So then the question becomes:


Is there a way to tell Swift not to inline a function and thus require memory load/store instructions before and/or after a non-inlined function call?


Are there any ways to specify any memory barriers before or after function calls in Swift? Or is a call from Swift to a small C function containing a C11 atomic intrinsic a possible solution?


Or is there another solution to using lock-free structures inside Audio Unit callbacks? (especially those with tiny sample buffers and thus very short absolute latency bounds...)

Given Swift’s lack of a memory model, there are no concrete answers here; essentially you’ll be relying on implementation details of the tool chain. You’ll have to decide whether that’s a deal breaker for you. Personally, if I were implementing an audio render function, I’d implement that small part of my app in C (or C++). More on that below.

Is there a way to tell Swift not to inline a function and thus require memory load/store instructions before and/or after a non-inlined function call?

Not explicitly. The obvious way to do this is to put the functions in a separate framework.

Are there any ways to specify any memory barriers before or after function calls in Swift?

Not that I’m aware of.

Or is a call from Swift to a small C function containing a C11 atomic intrinsic a possible solution?

Yes.

Or is there another solution to using lock-free structures inside Audio Unit callbacks?

Not that I’m aware of.

(especially those with tiny sample buffers and thus very short absolute latency bounds...)

Honestly, I think you have bigger concerns here than your lock-free data structure. Swift makes no guarantees about what language constructs will trigger memory allocation. All of the potential locking overhead pales in comparison to that.

Note that Objective-C has similar issues (you can’t guarantee a message send won’t allocate memory) and thus the received wisdom is that you should avoid Objective-C in these situations as well.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"