/* * alarm.c - timer based kernel alarm implementation * * Author Alain Greiner (2016,2017,2018,2019,2020) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH 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.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////////////////// // This static function registers the alarm identified ny the argument // in the list of alarms rooted in the core identified by the argument. // When the existing list of alarms is not empty, it scan the list to insert the new // alarm in the right place to respect the absolute dates ordering. //////////////////////////////////////////////////////////////////////////////////////////// // @ new_alarm : local pointer on the new alarm. // @ core : local pointer on the target core. //////////////////////////////////////////////////////////////////////////////////////////// static void alarm_register( alarm_t * new_alarm, core_t * core ) { list_entry_t * current; // pointer on current list_entry in existing list list_entry_t * previous; // pointer on previous list_entry in existing list alarm_t * current_alarm; // pointer on current alarm in existing list cycle_t current_date; // date of current alarm in existing list bool_t done = false; // get pointers on root of alarms and lock list_entry_t * root = &core->alarms_root; busylock_t * lock = &core->alarms_lock; // get pointer on new_alarm list_entry list_entry_t * new_entry = &new_alarm->list; // get new_alarm date cycle_t new_date = new_alarm->date; // take the lock busylock_acquire( lock ); // insert new alarm to respect dates order if( list_is_empty( root ) ) // list empty { list_add_first( root , new_entry ); } else // list non empty { for( current = root->next ; (current != root) && (done == false) ; current = current->next ) { // get pointer on previous entry in existing list previous = current->pred; // get pointer on current alarm current_alarm = LIST_ELEMENT( current , alarm_t , list ); // get date for current alarm current_date = current_alarm->date; if( current_date > new_date ) // insert new alarm just before current { new_entry->next = current; new_entry->pred = previous; current->pred = new_entry; previous->next = new_entry; done = true; } } // end for if( done == false ) // new_date is larger than all registered dates { list_add_last( root , new_entry ); } } // release the lock busylock_release( lock ); } // end alarm_register() ////////////////////////////////////// void alarm_start( cycle_t date, void * func_ptr, xptr_t args_xp, thread_t * thread ) { // get pointer on alarm alarm_t * alarm = &thread->alarm; // initialize alarm descriptor alarm->date = date; alarm->func_ptr = func_ptr; alarm->args_xp = args_xp; // register alarm in core list alarm_register( alarm , thread->core ); } // end alarm_start() ///////////////////////////////////// void alarm_update( thread_t * thread, cycle_t new_date ) { // get pointer on alarm alarm_t * alarm = &thread->alarm; // get pointer on core core_t * core = thread->core; // get pointer on lock protecting the alarms list busylock_t * lock = &core->alarms_lock; // unlink the alarm from the core list busylock_acquire( lock ); list_unlink( &alarm->list ); busylock_release( lock ); // update the alarm date alarm->date = new_date; // register alarm in core list alarm_register( alarm , core ); } // end alarm_update() //////////////////////////////////// void alarm_stop( thread_t * thread ) { // get pointer on alarm alarm_t * alarm = &thread->alarm; // get pointer on core core_t * core = thread->core; // get pointer on lock protecting the alarms list busylock_t * lock = &core->alarms_lock; // unlink the alarm from the list rooted in core busylock_acquire( lock ); list_unlink( &alarm->list ); busylock_release( lock ); } // end alarm_stop()