// This file contains stuff that needs to be in a separate file to prevent it
// from being inlined.


#ifdef USE_FUTEX

// The futex code has an inline part and a non-inline part.  This is the latter.
// The first problem is that, AFAICS, the futex system call is not exported as
// a function by the C library.  So we have this to work around that:

#include <sys/syscall.h>
#include <unistd.h>

static int futex(int  *uaddr,  int  op, int val, void *timeout, int *uaddr2, int val3) {
  return syscall(__NR_futex,uaddr,op,val,timeout,uaddr2,val3);
}


// futex() has lots of parameters that we don't care about.  Here are a couple
// of simplified versions:

#include <linux/futex.h>
#include <stddef.h>

static inline int futex_wait(int* p, int expected) {
  return futex(p,FUTEX_WAIT,expected,NULL,NULL,0);
}

static inline int futex_wake(int* p, int num) {
  return futex(p,FUTEX_WAKE,num,NULL,NULL,0);
}


// Here are the bodies of the lock and unlock methods:

#include "atomic.hh"

void futex_lock_body(int* futexp, int c) {
  if (c != 2) {
    c = atomic_swap(*futexp,2);
  }
  while (c != 0) {
    futex_wait(futexp,2);
    c = atomic_swap(*futexp,2);
  }
}

void futex_unlock_body(int* futexp) {
  atomic_write(*futexp,0);
  futex_wake(futexp,1);
}

#endif



// This is used to increment the data in the benchmark.
// Not doing this can let the x86 compiler to use a single instruction
// to do the increment, which is atomic in some sense on a uniprocessor.

int increment(int i) {
  return i+1;
}
