/*
 *
 *  simple locking test program
 *  (no paralles stuff)
 *
 *  Compile with: gcc -D__CPU_i386 -O3 on x86 machines and
 *                gcc -mips2 -O2 -D__CPU_mips  on mips machines.
 *  -- andrei
 *
 *
 */

#include <stdio.h>

typedef volatile int fl_lock_t;


int tsl(fl_lock_t *lock)
{
	long val;

#ifdef __CPU_mips
	long tmp = 0;

	asm volatile(".set noreorder\n\t"
				 "1:  ll %1, %2   \n\t"
				 "    li %0, 1 \n\t"
				 "    sc %0, %2  \n\t"
				 "    beqz %0, 1b \n\t"
				 "    nop \n\t"
				 ".set reorder\n\t"
				 : "=&r"(tmp), "=&r"(val), "=m"(*lock)
				 : "0"(tmp), "m"(*lock)
				 : "cc");
#elif defined __CPU_i386
	val = 1;
	asm volatile(" xchg %b1, %0" : "=q"(val), "=m"(*lock) : "0"(val));
#else
#error "cpu type not defined, add -D__CPU_<type> when compiling"
#endif

	return val;
}


void release_lock(fl_lock_t *lock)
{
#ifdef __CPU_mips
	int tmp;
	tmp = 0;
	asm volatile(".set noreorder \n\t"
				 "    sync \n\t"
				 "    sw $0, %0 \n\t"
				 ".set reorder \n\t"
				 : /*no output*/
				 : "m"(*lock)
				 : "memory");
#elif defined __CPU_i386
	asm volatile(" movb $0, (%0)" : /*no output*/ : "r"(lock) : "memory");
#else
#error "cpu type not defined, add -D__CPU_<type> when compiling"
#endif
}


int main(int argc, char **argv)
{
	fl_lock_t lock;
	int r;

	lock = 0;
	printf("starting locking basic tests...\n");

	r = tsl(&lock);
	printf(" tsl should return 0                 ... %d\n", r);
	printf("     lock should be 1 now            ... %d\n", lock);
	r = tsl(&lock);
	printf(" tsl should return 1                 ... %d\n", r);
	printf("     lock should still be 1 now      ... %d\n", lock);
	release_lock(&lock);
	printf(" release_lock: lock should be 0 now  ... %d\n", lock);
	printf("trying tsl once more...\n");
	r = tsl(&lock);
	printf(" tsl should return 0                 ... %d\n", r);
	printf("     lock should be 1 now            ... %d\n", lock);
	printf("\ndone.\n");
	return 0;
}
