//
// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// alarm.h --
//
// Author           : Thierry Delisle
// Created On       : Fri Jun 2 11:31:25 2017
// Last Modified By : Peter A. Buhr
// Last Modified On : Sat Jul 22 09:59:27 2017
// Update Count     : 3
//

#pragma once

#include <stdbool.h>
#include <stdint.h>

#include <assert.h>

struct thread_desc;
struct processor;

struct timespec;
struct itimerval;

//=============================================================================================
// time type
//=============================================================================================

struct __cfa_time_t {
	uint64_t val;
};

// ctors
void ?{}( __cfa_time_t & this );
void ?{}( __cfa_time_t & this, zero_t zero );
void ?{}( __cfa_time_t & this, timespec * curr );
void ?{}( itimerval & this, __cfa_time_t * alarm );

__cfa_time_t ?=?( __cfa_time_t & this, zero_t rhs );

// logical ops
static inline bool ?==?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val == rhs.val; }
static inline bool ?!=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val != rhs.val; }
static inline bool ?>? ( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val >  rhs.val; }
static inline bool ?<? ( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val <  rhs.val; }
static inline bool ?>=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val >= rhs.val; }
static inline bool ?<=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val <= rhs.val; }

static inline bool ?==?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val == rhs; }
static inline bool ?!=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val != rhs; }
static inline bool ?>? ( __cfa_time_t lhs, zero_t rhs ) { return lhs.val >  rhs; }
static inline bool ?<? ( __cfa_time_t lhs, zero_t rhs ) { return lhs.val <  rhs; }
static inline bool ?>=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val >= rhs; }
static inline bool ?<=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val <= rhs; }

// addition/substract
static inline __cfa_time_t ?+?( __cfa_time_t lhs, __cfa_time_t rhs ) {
	__cfa_time_t ret;
	ret.val = lhs.val + rhs.val;
	return ret;
}

static inline __cfa_time_t ?-?( __cfa_time_t lhs, __cfa_time_t rhs ) {
	__cfa_time_t ret;
	ret.val = lhs.val - rhs.val;
	return ret;
}

__cfa_time_t from_s ( uint64_t );
__cfa_time_t from_ms( uint64_t );
__cfa_time_t from_us( uint64_t );
__cfa_time_t from_ns( uint64_t );

extern __cfa_time_t zero_time;

//=============================================================================================
// Clock logic
//=============================================================================================

__cfa_time_t __kernel_get_time();
void __kernel_set_timer( __cfa_time_t alarm );

//=============================================================================================
// Alarm logic
//=============================================================================================

struct alarm_node_t {
	__cfa_time_t alarm;		// time when alarm goes off
	__cfa_time_t period;		// if > 0 => period of alarm
	alarm_node_t * next;		// intrusive link list field

	union {
		thread_desc * thrd;	// thrd who created event
		processor * proc;		// proc who created event
	};

	bool set		:1;		// whether or not the alarm has be registered
	bool kernel_alarm	:1;		// true if this is not a user defined alarm
};

typedef alarm_node_t ** __alarm_it_t;

void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time );
void ?{}( alarm_node_t & this, processor   * proc, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time );
void ^?{}( alarm_node_t & this );

struct alarm_list_t {
	alarm_node_t * head;
	__alarm_it_t tail;
};

static inline void ?{}( alarm_list_t & this ) {
	this.head = 0;
	this.tail = &this.head;
}

void insert( alarm_list_t * this, alarm_node_t * n );
alarm_node_t * pop( alarm_list_t * this );

void register_self  ( alarm_node_t * this );
void unregister_self( alarm_node_t * this );

// Local Variables: //
// mode: c //
// tab-width: 6 //
// End: //
