title: Spin Lock using xchg
body: <p>I'm trying to implement the simplest spinlock (using TAS) in C using inline assembly with the command xchg. Since my compiler error messages are getting more and more exotic and I'm starting to grow grey hairs I've decided to ask here. Also I'm sorry if this question was already answered since I haven't found anything.</p>
  
  <p>What might needs to be said about my programming experience concerning this topic. I'm doing pretty fine with C (in my opinion, considering standard problems). Also I believe to know the basics about x86 but I'm totally lost when it comes to constraints in inline assembler. What I found doing some googling is even more confusing to me since many sources say very different stuff.</p>
  
  <p>My code so far:</p>
  
  <pre><code>int acquire_lock(int* lock){
      int val = 1;
      int lock_cont;
      while((lock_cont = *lock) != 0){
              __asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));
      }
      return 0;
  }
  </code></pre>
  
  <p>This doesn't work for reasons that are probably obvious but are making me go nuts. I've also tried some other variants but none of them even compiled. You can probably tell by now that I don't really know what I'm doing so I'd be more than happy for any kind of advice.</p>
  
  <p>Here my compiler messages in case this helps: </p>
  
  <pre><code>my_lock.c:17:11: error: unexpected token in argument list
              __asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));
                      ^
  &lt;inline asm&gt;:1:12: note: instantiated into assembly here
      xchg %eax -16(%rbp)
                ^
  1 error generated.
  </code></pre>
  
  <p>Thanks in advance</p>
  
  <p>A desperate student</p>
  
  <p>EDIT:</p>
  
  <p>I got the lock to work.. a do while loop and the comma did the trick. Now I have a new problem that my lock implementation still doesn't seem to guarantee exclusive access.. I'll post the whole code and would be happy for any suggestions/critics.</p>
  
  <pre><code>#include &lt;pthread.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  
  //shared variable
  int x;
  
  //new lock instance that's consistent over function calls
  int* new_lock(){
          int* ptr = (int*)(malloc(sizeof(int)));
          *ptr = 0;
          return ptr;
  }
  
  //set content of lock atomically to 1
  int acquire_lock(int* lock){
          int val = 1;
          do{
                  __asm__("xchg %0, %1" : "+q" (val), "+m" (*lock));
          }while(val - (*lock) == 0);
          return 0;
  }
  
  //release the lock
  int release_lock(int* lock){
          *lock = 0;
          return 0;
  }
  
  //free lock
  int delete_lock(int* ptr){
          free(ptr);
          return 0;
  }
  
  //thread counts to 10^6
  void* thread_do(void* arg){
          int* lock = (int*) arg;
          for(int i = 0; i &lt; 100000; i++){
                  acquire_lock(lock);
                  x++;
                  release_lock(lock);
          }
          return NULL;
  }
  
  int main(int argc, char** argv){
          pthread_t thread0, thread1;
          int* lock = new_lock();
          pthread_create(&amp;thread0, NULL, thread_do, lock);
          pthread_create(&amp;thread1, NULL, thread_do, lock);
          pthread_join(thread0, NULL);
          pthread_join(thread1, NULL);
          printf("%d\n",x);
          return 0;
  }
  </code></pre>
  
  <p>EDIT2:</p>
  
  <p>My lock actually DOES work as can be seen when locking the whole loop inside the thread_do function. Not quite happy with this result since this locks x for quite a long time but I guess I'll have to live with this.. I assume the problem is that between my asm instruction and the comparison from the while I can't guarantee atomicity when the locking and unlocking is such a fast stream of instructions (for loop in thread_do) since I don't see a workaround in C (suggestions are welcome), I'll stick to this implementations since the general idea seems to be right.</p>