/*
 * POSIX.4 Timers
 *
 * Written by J. Vidal, F. Vazquez
 * 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.
 *
 */

#include <rtl_sched.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/signal.h>

#ifdef CONFIG_OC_PTIMERS 

typedef struct rtl_sigevent{
  int sigev_notify; /* notification mechanism */
  int sigev_signo; /* signal number */
}rtl_sigevent_t;

struct rtl_itimerspec{
  hrtime_t it_value;
  hrtime_t it_interval;
};

/* POSIX.4 Timers struct definition*/ 
struct rtl_timer_struct {
  int id;
  clockid_t clock_id;
  struct rtl_itimerspec expires;
  pthread_t owner; 
  struct rtl_timer_struct *next;
  rtl_sigevent_t signal;
  int magic;
};

typedef struct rtl_timer_struct *timer_t;

#define RTL_TIMER_MAGIC 0x19061977

/* POSIX.4 Timers API.*/ 
/*
  timer_create & timer_delete must be called from 
  init_module & clean_module respectivelly. 
*/
/* One-Shot and Repeating Timers */ 
int timer_create(clockid_t clock_id, const struct sigevent *signal_specification, timer_t *timer_id);
int timer_delete(timer_t timer_id);
int timer_settime(timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting);
int timer_gettime(timer_t timer_id, struct itimerspec *ts_set);
int timer_getoverrun(timer_t timer_id);

/* Some usefull functions & macros */
#define TIMER_ARMED(t)  ((t->expires.it_value)? 1 : 0)
#define DISARME_TIMER(t) do {\
    t->expires.it_value=0;\
    t->expires.it_interval=0;\
} while (0)

#define PERIODIC_TIMER(t) ((t->expires.it_interval)? 1 : 0)

  /* 
     CLOCK_REALTIME & CLOCK_RTL_SCHED are the same since rtlinux version 3.1 
     In mode ONESHOT, CLOCK_REALTIME & CLOCK_MONOTONIC are the same.
     In periodic mode, CLOCK_MONOTONIC becomes local to the CPU. 
  */
extern inline int timer_expiration(timer_t t,hrtime_t rtl_sched_clock_time, int mode){
  hrtime_t now=rtl_sched_clock_time;

  if (TIMER_ARMED(t)) {
    if (t->clock_id == CLOCK_MONOTONIC && mode == RTL_CLOCK_MODE_PERIODIC){
      now=clock_gethrtime(CLOCK_MONOTONIC);
    }
    return (now>=t->expires.it_value) ? 1 : 0;
  }
  
  return 0;
  
}

#define CHECK_VALID_TIMER(timer) ((timer)->magic != RTL_TIMER_MAGIC)? 0:1

// It is supposed to be a valid signal, so timer_create checks it.
#define signal_generation(th,sig) do { if (sig) rtl_sigaddset(&th->pending,sig); } while(0) 

  /* notification mechanisms */
extern inline void expiration_notification(timer_t t)   {
  switch  (t->signal.sigev_notify){
  case SIGEV_SIGNAL: 
    signal_generation(t->owner,t->signal.sigev_signo); 
    break;
  default:
    return ;
  }
} 

extern inline void UPDATE_TIMER(timer_t t){
  /* Repeating timer ?*/
  if (PERIODIC_TIMER(t)){
    t->expires.it_value+=t->expires.it_interval;
  } else { 
    /* One-shot timer */
    DISARME_TIMER(t);
  }
}

#define UPDATE_TIMER_IN_DEBUG_MODE(t) do {\
  if (PERIODIC_TIMER(t)){\
    t->expires.it_value+=t->expires.it_interval;\
    rt_print_timer_request(events,t,FIFO);\
  } else { DISARME_TIMER(t);}\
} while(0)

extern struct rtl_timer_struct *timer_list_start;
extern spinlock_t rtl_timer_list_lock;
#define get_timer_list_start() timer_list_start
#define get_ptr_to_timer_list_start() &timer_list_start

#endif






































































