/* C version of sense barrier */

typedef struct {
  atomic_t c;
  int sense;
} 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 barrier_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 barrier_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) {
    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() ;
  }
}
