// CrossWorks Tasking Library.
//
// Copyright (c) 2004 Rowley Associates Limited.
//
// This file may be distributed under the terms of the License Agreement
// provided with this software.
//
// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "ctl_api.h"
#include "ctl_impl.h"

void
ctl_semaphore_init(CTL_SEMAPHORE_t *s,
                   unsigned value)
{
  int enabled = ctl_global_interrupts_disable();
  *s = value;
  ctl_global_interrupts_set(enabled);
}

unsigned 
ctl_semaphore_wait(CTL_SEMAPHORE_t *s,
                   unsigned use_timeout, // if non-zero use timeout
                   CTL_TIME_t timeout)
{  
  ctl_global_interrupts_disable();
  if (ctl_interrupt_count)
    ctl_handle_error(CTL_WAIT_CALLED_FROM_ISR);
  ctl_task_executing->timeout = 0;
  if (*s)
    {
      (*s)--;
      ctl_task_executing->timeout = 1;
    }
  else
    {
      ctl_task_executing->timeout = timeout;  
      ctl_task_executing->wait_object = s;
      ctl_task_executing->u.wait_events = 0;
      ctl_task_executing->state = use_timeout ? (CTL_STATE_SEMAPHORE_WAIT | CTL_STATE_TIMER_WAIT) : CTL_STATE_SEMAPHORE_WAIT;          
    }
  ctl_task_reschedule();
  return ctl_task_executing->timeout;
}

void 
ctl_semaphore_signal(CTL_SEMAPHORE_t *s)
{
  int enabled = ctl_global_interrupts_disable();
  if (*(CTL_SEMAPHORE_t*)s)
    {
      (*(CTL_SEMAPHORE_t*)s)++;
    }
  else
    {
      CTL_TASK_t *t;
      for (t=ctl_task_list; t; t=t->next)
        if ((t->state & CTL_STATE_SEMAPHORE_WAIT) && (t->wait_object == s))
          {
            t->timeout = 1;
            t->state = CTL_STATE_RUNNABLE;
            break;
          }
      if (!t)
        (*(CTL_SEMAPHORE_t*)s)++;
    }
  if (ctl_interrupt_count==0)
    ctl_task_reschedule();
  else
    ctl_global_interrupts_set(enabled);
}
