Reputation: 6517
If I have an integer x, which of the following statements are atomic on the ARM architecture on an iPhone?
int x;
int y;
x = 92; // . . . . . . A
x++; // . . . . . . B
y = ++x; // . . . . . . C
printf("x = %d\n", x); // D
I know, that on the i386 platform, statements A, B and D are atomic, while C is not. I'm pretty sure that C is not atomic in iOS. I suspect that basic load and store operations (D and A) are atomic in iOS too, but I'm not sure. Does anyone know more?
How is it with 16 bit and 8 bit values? Or with 64 bit values on the iPhone 5S and with 64 bit values on the iPhone 5 and below?
(If the answer is as I suspect... Is there any platform where basic load and store operations are not atomic?)
Upvotes: 4
Views: 1233
Reputation: 22430
You don't give enough context on the declaration of x
and y
. If there are locals within a function, then they will be assigned to registers and other threads can not touch them. So I assume you mean they are global (or at least static).
The ARM is a load-store architecture. It does not have memory to memory instructions. So really only lines A/D are atomic. You have unconditionally wrote the value. It is not ordered versus another thread. If one thread writes 92
and another writes 29
, there will be no way to know what is written without a mutex of some sort.
Early ARM cpus have swp
; but most iOS products will use ldrex
and strex
. You must use these instructions to have any sort of atomic updates.
The ARM can write 8/16/32/64 bits at a time and most system designs will have the caches synchronized so that a write by one CPU is seen by another. A ring buffer structure could be used with a producer/consumer where only one CPU writes to the ring head and the other to the ring tail; Ie, this would be an atomic structure you can use without swp
or ldrex
and strex
.
It is possible that if you manually allocate a 64bit value, you could mess things up. You would have to try hard to do this. For instance, if a page fault occurs between the upper/lower 32 bits of the 64 bit value. Obviously, un-aligned values may also have issue depending on the CPU type. If you declare things normally, they should be well aligned by the compiler. This is also possible with unaligned 32 bit and 16 bit values. iOS may make these accesses look atomic to user space. Generally, if you rely on atomic behavior, you should not do any strange casts, and declare the variables normally.
Edit:
(If the answer is as I suspect... Is there any platform where basic load and store operations are not atomic?)
Yes, there are many platforms where larger values load/stores are not atomic; especially for all data types. Pragmatically, most CPUs are at least 8-bits (although even 4bit CPUs exist), so a char
load and store are usually atomic. For smaller CPUs, the load/store of larger values may take several cycles. In these cases, the compiler will take multiple cycles to update a value. This is the idea behind sig_atomic_t
; it is a variable size that can be updated atomically. sig_atomic_t
should be available on all Posix systems, but there is no general guarantee in plain C99. C11 adds the _Atomic
type qualifier.
Upvotes: 3