/* C version of sense barrier */

typedef struct {
  atomic_t c;
  int sense;
#ifdef TIMEBASE
  tb_t tb;
#endif
} sense_t;

static void free_sense(sense_t *p) {
  if (!p) return;
  kfree(p);
}

static sense_t *alloc_sense(void) {
  sense_t *r = kmalloc(sizeof(sense_t),GFP_KERNEL);
  if (!r) return NULL;
  return r;
}

static void sense_init (sense_t *p) {
  atomic_set(&(p->c),nthreads) ;
  p->sense = 0;
}

static const int busy_n1_0 = 64*1024;
static const int busy_n2_0 = 1024;

static void sense_wait(sense_t *p) {
  int sense = READ_ONCE(p->sense) ;
  int last ;

  smp_mb() ;
  last = atomic_dec_and_test(&(p->c)) ;
  smp_mb() ;
  if (last) {
#ifdef TIMEBASE
  p->tb = read_timebase();
#endif
    atomic_set(&p->c,nthreads) ;
    smp_mb() ;
    WRITE_ONCE(p->sense,1-sense);
    smp_mb() ;
  } else {
    int n1=busy_n1_0, n2=busy_n2_0;
    while (READ_ONCE(p->sense) == sense) {
      if (--n1 <= 0) {
        n1 = busy_n1_0;
        if (--n2 <= 0) {
           n2 = busy_n2_0;
           schedule();
        }
      }
    }
    smp_mb() ;
  }
#ifdef TIMEBASE
  tb_t limit = p->tb + delay_tb;
  for ( ; ; ) {
    if (read_timebase() >= limit) break;
  }
#endif
}
