标签

, ,

When learning spin lock implementation in kernel, I came across this macro.After reading some info I found it’s interesting.

The macro is like this(in include/linux/compiler.h):

    #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))

It works by turning a variable into a volatile one temporarily.The macro serves for 3 reasons:

  1. Assure there must be one read in the code.Consider the following code:
    for (;;)
    {
        struct task_struct *owner;
    
        owner = ACCESS_ONCE(lock->owner);
        if (owner && !mutex_spin_on_owner(lock, owner))
            break;
        /* ... */
    

    This could be potentially optimized by the gcc to this:

        owner = ACCESS_ONCE(lock->owner);
        for (;;) {
    	if (owner && !mutex_spin_on_owner(lock, owner))
    	    break;
    

    If the lock->owner is modified by the other thread,this optimized code leads to wrong results.

  2. If the code is like this:

    	if (a > MEMORY) {
    		do1;
    		do2;
    		do3;
    	} else {
    		do2;
    	}
    

    This might be optimized to:

    	if (a > MEMORY)
    		do1;
    	do2;
    	if (a > MEMORY)
    		do3;
    

    If ‘a’ changes in a second thread, do1 could be called without d3 be.This is a more subtle problem.

  3. ACCESS_ONCE() serves another purpose that remind the program that this varible is not protect by any lock mechanism,I just want a value, wheter it’s old or new.

See links:

  1. https://lwn.net/Articles/508991/
  2. http://yarchive.net/comp/linux/ACCESS_ONCE.html
Advertisements