// -*- Mode: CFA -*- // // 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.c -- // // Author : Thierry Delisle // Created On : Fri Jun 2 11:31:25 2017 // Last Modified By : Thierry Delisle // Last Modified On : -- // Update Count : 0 // extern "C" { #include #include #include #include #include #include } #include "libhdr.h" #include "alarm.h" #include "kernel_private.h" #include "preemption.h" //============================================================================================= // Clock logic //============================================================================================= __cfa_time_t __kernel_get_time() { timespec curr; clock_gettime( CLOCK_REALTIME, &curr ); __cfa_time_t curr_time = ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : current time is %lu\n", curr_time ); return curr_time; } void __kernel_set_timer( __cfa_time_t alarm ) { LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : set timer to %llu\n", (__cfa_time_t)alarm ); itimerval val; val.it_value.tv_sec = alarm / TIMEGRAN; // seconds val.it_value.tv_usec = max( (alarm % TIMEGRAN) / ( TIMEGRAN / 1_000_000L ), 1000 ); // microseconds val.it_interval.tv_sec = 0; val.it_interval.tv_usec = 0; setitimer( ITIMER_REAL, &val, NULL ); } //============================================================================================= // Alarm logic //============================================================================================= void ?{}( alarm_node_t * this, thread_desc * thrd, __cfa_time_t alarm = 0, __cfa_time_t period = 0 ) { this->thrd = thrd; this->alarm = alarm; this->period = period; this->next = 0; this->set = false; this->kernel_alarm = false; } void ?{}( alarm_node_t * this, processor * proc, __cfa_time_t alarm = 0, __cfa_time_t period = 0 ) { this->proc = proc; this->alarm = alarm; this->period = period; this->next = 0; this->set = false; this->kernel_alarm = true; } void ^?{}( alarm_node_t * this ) { if( this->set ) { unregister_self( this ); } } LIB_DEBUG_DO( bool validate( alarm_list_t * this ) { alarm_node_t ** it = &this->head; while( (*it) ) { it = &(*it)->next; } return it == this->tail; }) static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { verify( !n->next ); if( p == this->tail ) { this->tail = &n->next; } else { n->next = *p; } *p = n; verify( validate( this ) ); } void insert( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t ** it = &this->head; while( (*it) && (n->alarm > (*it)->alarm) ) { it = &(*it)->next; } insert_at( this, n, it ); verify( validate( this ) ); } alarm_node_t * pop( alarm_list_t * this ) { alarm_node_t * head = this->head; if( head ) { this->head = head->next; if( !head->next ) { this->tail = &this->head; } head->next = NULL; } verify( validate( this ) ); return head; } static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { verify( it ); verify( (*it) == n ); (*it) = n->next; if( !n-> next ) { this->tail = it; } n->next = NULL; verify( validate( this ) ); } static inline void remove( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t ** it = &this->head; while( (*it) && (*it) != n ) { it = &(*it)->next; } verify( validate( this ) ); if( *it ) { remove_at( this, n, it ); } verify( validate( this ) ); } void register_self( alarm_node_t * this ) { alarm_list_t * alarms = &event_kernel->alarms; disable_interrupts(); lock( &event_kernel->lock DEBUG_CTX2 ); { verify( validate( alarms ) ); bool first = !alarms->head; insert( alarms, this ); if( first ) { __kernel_set_timer( alarms->head->alarm - __kernel_get_time() ); } } unlock( &event_kernel->lock ); this->set = true; enable_interrupts( DEBUG_CTX ); } void unregister_self( alarm_node_t * this ) { disable_interrupts(); lock( &event_kernel->lock DEBUG_CTX2 ); { verify( validate( &event_kernel->alarms ) ); remove( &event_kernel->alarms, this ); } unlock( &event_kernel->lock ); enable_interrupts( DEBUG_CTX ); this->set = false; }