/*
 * RTLinux wait API.
 * 
 * StandAlone RTLinux integration 
 * written by Vicente Esteve LLoret <viesllo@inf.upv.es> 
 * Copyright (C) Feb, 2003 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.
 *
 * This is used by IPC functions.
 * 
 */



#include <rtl_conf.h>
#include <rtl_sched.h>
#include <rtl_mutex.h>
#include <rtl_sync.h>

//
//     These functions are used by mutex and posix sems
//

#if _RTL_POSIX_SEMS || _RTL_POSIX_MUTEXS || CONFIG_OC_PBARRIERS


static void rtl_wait_abort(void *data)
{
  pthread_t self = pthread_self();
  struct rtl_wait_struct *t;
  rtl_wait_t *wait = (rtl_wait_t*) data;
  rtl_irqstate_t flags;

  rtl_spin_lock_irqsave (wait->p_lock, flags);
  if (!wait->queue) 
  {
    goto done;
  }

  if (wait->queue->waiter == self) 
  {
    wait->queue = wait->queue->next;
    goto done;
  }
  
  for (t = wait->queue; t->next; t = t->next) 
  {
    if (t->magic != RTL_WAIT_MAGIC) 
    {
//			BUG();
    }
    if (t->next->waiter == self) 
    {
      t->next = t->next->next;
      break;
    }
  }
done:	
  self->abort = 0;
  self->abortdata = 0;
  rtl_spin_unlock_irqrestore(wait->p_lock, flags);
}

int rtl_wait_sleep (rtl_wait_t *wait, spinlock_t *lock)
{
  pthread_t self = pthread_self();
  struct rtl_wait_struct wait_struct;

  self->abort = &rtl_wait_abort;
  self->abortdata = wait;

  wait_struct.magic = RTL_WAIT_MAGIC;
  wait_struct.waiter = self;
  wait_struct.next = wait->queue;
  wait->queue = &wait_struct;
  wait->p_lock = lock;

  RTL_MARK_SUSPENDED (self);

  rtl_spin_unlock(lock);

  return rtl_schedule();
}


int rtl_wait_wakeup (rtl_wait_t *wait)
{
  struct rtl_wait_struct *t;
  for (t = wait->queue; t; t = t->next) 
  {
    if (t->magic != RTL_WAIT_MAGIC) 
    {
//      BUG();
    }
    pthread_kill (t->waiter, RTL_SIGNAL_WAKEUP);
  }
  wait->queue = NULL;
  return 0;
}


#endif // _RTL_POSIX_SEMS || _RTL_POSIX_MUTEXS
