By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
428,816 Members | 2,151 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 428,816 IT Pros & Developers. It's quick & easy.

Explanation of spin_lock function from net/socket.c

100+
P: 1,059
Expand|Select|Wrap|Line Numbers
  1. spin_lock(&net_family_lock);
  2.     if (net_families[ops->family])
  3.         err = -EEXIST;
  4.     else {
  5.         net_families[ops->family] = ops;
  6.         err = 0;
  7.     }
  8.     spin_unlock(&net_family_lock);
Please look at the above piece of code (got from net/socket.c). Its about spin_lock function. I tried to find the explanation. But its not that easy.

and here what I got a possible function definition of spin_lock and spin_unlock function got from wikipedia.
Expand|Select|Wrap|Line Numbers
  1. # Intel syntax
  2.  
  3. lock:                        # The lock variable. 1 = locked, 0 = unlocked.
  4.      dd      0
  5.  
  6. spin_lock:
  7.      mov     eax, 1          # Set the EAX register to 1.
  8.  
  9. loop:
  10.      xchg    eax, [lock]     # Atomically swap the EAX register with
  11.                              #  the lock variable.
  12.                              # This will always store 1 to the lock, leaving
  13.                              #  previous value in the EAX register.
  14.  
  15.      test    eax, eax        # Test EAX with itself. Among other things, this will
  16.                              #  set the processor's Zero Flag if EAX is 0.
  17.                              # If EAX is 0, then the lock was unlocked and
  18.                              #  we just locked it.
  19.                              # Otherwise, EAX is 1 and we didn't acquire the lock.
  20.  
  21.      jnz     loop            # Jump back to the XCHG instruction if the Zero Flag is
  22.                              #  not set, the lock was locked, and we need to spin.
  23.  
  24.      ret                     # The lock has been acquired, return to the calling
  25.                              #  function.
  26.  
  27. spin_unlock:
  28.      mov     eax, 0          # Set the EAX register to 0.
  29.  
  30.      xchg    eax, [lock]     # Atomically swap the EAX register with
  31.                              #  the lock variable.
  32.  
  33.      ret                     # The lock has been released.
  34.  
I have tried to understand the situation. How it is working.

in the first code when we call spin_lock it enters in a loop that which will continue until ZF is set to high. In that case how program will continue to next statements? If it dont get to next statements it wont get spin_unlock.

Or what I am missing here?
Sep 17 '10 #1
Share this Question
Share on Google+
5 Replies


Expert 100+
P: 2,398
The use of locks implies there are, or could be, multiple independent threads of execution. In this particular case, the lock is used to insure that only one thread at a time accesses the net_families array.
  1. The lock variable is initially 0.
  2. Thread 1 enters the code snippet.
  3. The lock variable is 0, so spin_lock returns immediately to Thread 1 after setting the lock variable to 1. Thread 1 enters the protected region.
  4. Thread 2 enters this same code snippet.
  5. The lock variable is 1, so spin_lock does not return to Thread 2.
  6. Thread 1 continues through the protected region. (Thread 2 is still stuck in spin_lock.)
  7. Thread 1 exits the protected region and calls spin_unlock. (Thread 2 is still stuck in spin_lock.)
  8. spin_unlock sets the lock variable to 0 from Thread 1.
  9. The next loop of spin_lock in Thread 2 finds the lock variable is 0, so it sets it back to 1 and returns.
  10. Thread 2 enters the protected region.
  11. Thread 2 exits the protected region and calls spin_unlock.
  12. spin_unlock sets the lock variable to 0 from Thread 2.
Notice that this spin lock only works if the operating system supports preemptive multitasking. Priority scheduling could result in a deadlock. That shouldn't be possible with round-robin scheduling. I encourage you to look up the italicized terms to find out why I made these statements.
Sep 17 '10 #2

100+
P: 1,059
I liked the explanation.
But it confused my knowledge.

It seems I need a little bit more knowledge on x86 Assembly.

Thanks for your thoughtful answer.
Sep 17 '10 #3

Expert 100+
P: 2,398
A C version of spin_lock might look something like this:
Expand|Select|Wrap|Line Numbers
  1. volatile int lock = 0;
  2. void spin_lock(void) {
  3.    while(lock != 0)
  4.        ;   /*sit and spin*/
  5.     lock = 1;
  6. }
Consider what might happen with this version of spin_lock in the previous Thread1/Thread2 example. Suppose execution is transferred from Thread1 to Thread2 after spin_lock detects that lock is zero, but before it has a chance to set the lock to 1. Thread2 runs its copy of spin_lock, who also finds the lock to be zero. Thread2 sets the lock and enters the protected region; but while there execution returns to Thread1, who finishes exiting spin_lock and enters the protected region. We end up with both threads in the protected region at the same time -- spin_lock did not do its job.

That's why it is so vital for lock functions to implement the lock-test and lock-set operations in an atomic, or non-interruptible / non-preemptible manner. Standard C does not provide an atomic test-and-set capability -- that's why spin_lock is written in assembly code. (It certainly isn't worth any effort to make this function run as fast as possible.)

Look at the original spin_lock listing. Line 10 atomically exchanges the contents of the EAX register with the lock variable, but line 7 had previously set EAX to "1". So as you enter line 15, the lock variable is "1" and EAX contains the old value of the lock variable. Lines 15 and 21 cause the subroutine to loop back if the old value of the lock variable is nonzero, but if the old value is zero the subroutine falls through to line 24 and returns.
Sep 17 '10 #4

100+
P: 1,059
In College I have learned 8086 Assembly language(turbo assembler). That is why a I was little confused.
Thanks for your reply.

This is a very good solution.

But the point that I am missing is this is a non interrupt able routine. Say a dumb programmer create a thread that that receive data from some source and which is busy. as example

Expand|Select|Wrap|Line Numbers
  1. spin_lock(&lock_var);
  2.  
  3. read_from_rs232(&variable);
  4.  
  5. spin_unlock(&lock_var);
  6.  
and say for some reason read_from_rs232 is stuck. in that case would processor get stuck forever(I don't have knowledge about it). It seems like a dead lock.
Sep 17 '10 #5

Expert 100+
P: 2,398
The possibility of deadlock is present any time you have locks. It is the job of the system architect to decide what resources need to be locked and conventions for how the locks are set and released. This job can be done well, or it can be done poorly.

A general principle is to keep the duration of a lock as short as possible.

Notice that spin locks do not allow a thread to do anything useful while it is waiting for a lock. An alternative is a lock function that returns a success or failure indication. The calling function can then choose to do something else until the lock function returns success.

Locks are really only needed to coordinate access to shared resources. Less sharing (more independence) between threads means fewer locks. Fewer locks means less brainpower need be expended on preventing deadlock.
Sep 17 '10 #6

Post your reply

Sign in to post your reply or Sign up for a free account.