/*
 * rtl_barrier.c
 *
 * Written by Patricia Balbastre <patricia@disca.upv.es>
 * Copyright (C) Dec, 2002 OCERA Consortium.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation version 2.
 *
 *
 * RTLinux barrier implementation
 */
#include <rtl_sched.h>
#include <rtl_barrier.h>

#ifdef CONFIG_OC_PBARRIERS
int  pthread_barrierattr_init(pthread_barrierattr_t *attr)
{

  attr->pshared = PTHREAD_PROCESS_SHARED;
  attr->valid = 1;
  return 0;
}

int pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
{
  return 0;
}

int pthread_barrier_destroy(pthread_barrier_t *barrier)
{

  if (barrier-> busy){
    return EBUSY;
  }

  if (!barrier->valid){
    return EINVAL;
  }

  barrier->valid = 0;

  return 0;
}

int pthread_barrier_init(pthread_barrier_t *barrier,
          const pthread_barrierattr_t *attr, unsigned count)
{
  pthread_barrierattr_t defattr;

  if (barrier->busy){
    return EBUSY;
  }

  if (!attr) {
    pthread_barrierattr_init(&defattr);
    attr = &defattr;
  }

  if ((count <= 1) || (!attr->valid)) {
    return EINVAL;
  }

  rtl_wait_init(&barrier->wait);

  barrier->valid   = attr -> valid;
  barrier->count   = count;
  barrier->busy    = 0;
  barrier->waiting = 0;

  return 0;
}

extern int pthread_barrier_wait(pthread_barrier_t *barrier)
{
  int ret;
  unsigned long interrupt_state;
  
  
  /* The barrier is not initialized */
  if (barrier->valid!=1) {
    return EINVAL;
  }

  rtl_no_interrupts(interrupt_state);
  
  if (barrier->waiting >= barrier->count-1) { /* Wake up all threads  */ 
	  	
    barrier->waiting = 0;
    barrier->busy    = 0;
	  
    rtl_wait_wakeup(&barrier->wait);
    rtl_restore_interrupts(interrupt_state);
    rtl_schedule();
    return PTHREAD_BARRIER_SERIAL_THREAD;
  }

	else {
	  barrier->waiting++;
	  if (!barrier->busy) {
	    barrier->busy = 1;
	  }
	  ret = rtl_wait_sleep (&barrier->wait, &barrier->lock);
//	  pthread_testcancel();
	  rtl_restore_interrupts(interrupt_state);
	  return 0;
	}
	
}
#endif /*CONFIG_OC_PBARRIERS*/
