extern void abort(void);
void assume_abort_if_not(int cond) {
  if(!cond) {abort();}
}
extern void abort(void);
#include <assert.h>
void reach_error() { assert(0); }
extern void __VERIFIER_atomic_begin();
extern void __VERIFIER_atomic_end();

//Ticket lock with proportional backoff
//
//From Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors, 1991 (Fig. 2).
//Also available as pseudo-code here: http://www.cs.rochester.edu/research/synchronization/pseudocode/ss.html#ticket

#include <pthread.h>

#define assume(e) assume_abort_if_not(e)
#undef assert
#define assert(e) { if(!(e)) { ERROR: {reach_error();abort();}(void)0; } }

volatile unsigned next_ticket = 0;
volatile unsigned now_serving = 0;

#define FAILED 3 //this is already and the limit of what we can handle

#define NEXT(e) ((e + 1) % FAILED)
// #define NEXT(e) ((e+1 == FAILED)?0:e+1)

unsigned fetch_and_increment__next_ticket(){
	__VERIFIER_atomic_begin();
	unsigned value;

		if(NEXT(next_ticket) == now_serving){ 
			value = FAILED;
		}
		else
		{
			value = next_ticket;
			next_ticket = NEXT(next_ticket);
		}

	__VERIFIER_atomic_end();
	return value;
}

inline void acquire_lock(){
	unsigned my_ticket; 

	my_ticket = fetch_and_increment__next_ticket(); //returns old value; arithmetic overflow is harmless (Alex: it is not if we have 2^64 threads)

	if(my_ticket == FAILED){
		assume(0);
	}else{
		while(1){
			//pause(my_ticket - now_serving);
			// consume this many units of time
			// on most machines, subtraction works correctly despite overflow
			if(now_serving == my_ticket){
				break;
			}
		}
	}

	return;
}

inline void release_lock(){
	now_serving++;
}

int c = 0;
void* thr1(void* arg){
	acquire_lock();
	c++;
	assert(c == 1);
	c--;
	release_lock();

  return 0;
}

int main(){
  pthread_t t;

	while(1) { pthread_create(&t, 0, thr1, 0); }
}

