sched.c

Go to the documentation of this file.
00001 /*!
00002  * \file   cpu_reserve/server/src/sched.c
00003  * \brief  management of the scheduling data
00004  *
00005  * \date   09/04/2004
00006  * \author Jork Loeser <jork.loeser@inf.tu-dresden.de>
00007  *
00008  */
00009 /* (c) 2004 Technische Universitaet Dresden
00010  * This file is part of DROPS, which is distributed under the terms of the
00011  * GNU General Public License 2. Please see the COPYING file for details.
00012  */
00013 #include <string.h>
00014 #include <stdlib.h>
00015 #include <l4/env/errno.h>
00016 #include <l4/log/l4log.h>
00017 #include <l4/dm_mem/dm_mem.h>
00018 #include "sched.h"
00019 
00020 int sched_cur_threads, sched_max_threads;
00021 sched_t **scheds;
00022 l4semaphore_t scheds_lock = L4SEMAPHORE_UNLOCKED;
00023 
00024 /*!\brief initalize arrays
00025  *
00026  * \retval 0            OK
00027  * \retval -L4_ENOMEM   out of memory
00028  */
00029 int sched_init(void){
00030     return (scheds = calloc(sizeof(sched_t*),
00031                             sched_max_threads))!=0?0:-L4_ENOMEM;
00032 }
00033 
00034 /*\brief return position where a thread with prio had to be inserted
00035  *
00036  * All threads below the returned position have a lower prio,
00037  * all threads at or above the position have a higher or equal prio.
00038  *
00039  * The function returns cur_threads if the given prio is the highest so far.
00040  */
00041 int sched_index(int prio){
00042     int pos, min_pos, end_pos;
00043 
00044     if(sched_cur_threads==0) return 0;
00045     if(prio>scheds[sched_cur_threads-1]->prio) return sched_cur_threads;
00046     end_pos = sched_cur_threads;      /* all threads >=end_pos have
00047                                        * higher or equal prio */
00048     min_pos=0;
00049     pos=0;
00050     while(1){
00051         pos = (min_pos+end_pos)/2;
00052         if(pos==min_pos){
00053             if(scheds[pos]->prio < prio) return pos+1;
00054             return pos;
00055         }
00056         if(scheds[pos]->prio < prio){
00057             min_pos = pos;
00058         } else {
00059             end_pos = pos;
00060         }
00061     }
00062 }
00063 
00064 /*!\brief Get max blocking time due to non-preemption for a thread
00065  *
00066  * \param prio          prio of the thread to analyze
00067  * \param new_          optional additional thread, not in #scheds yet
00068  *
00069  * \return              max blocking time due to non-preemption by
00070  *                      lower-prioritized threads
00071  *
00072  * This function gets the max blocking time due to non-preemption for
00073  * a thread of the given priority. Note that only threads with *lower*
00074  * priority are taken into account, as others do not lead to blocking
00075  * due to non-preemption but to normal preemption. Normal preemption
00076  * is handled elsewhere.
00077  */
00078 static int get_max_dp(int prio, sched_t *new_){
00079     int i, maxdp=0;
00080 
00081     for(i=0; i<sched_cur_threads; i++){
00082         
00083         if(scheds[i]->prio>=prio) break;
00084         if(is_dp(scheds[i]) && scheds[i]->wcet>maxdp)
00085             maxdp = scheds[i]->wcet;
00086     }
00087     if(new_ && is_dp(new_) && new_->prio<prio && new_->wcet>maxdp){
00088         maxdp = new_->wcet;
00089     }
00090     return maxdp;
00091 }
00092 
00093 /*!\brief Get the response time of the thread s
00094  *
00095  * we do response-time analysis based on the wcet of the higher-prioritized
00096  * threads with (period T, wcet C) (sometimes called time-demand analysis):
00097  * Iterative proces: 
00098  *  r_j+1 = sum_i { ceil(r_j/T_i)*C_i }
00099  * until fixpoint is found
00100  *
00101  * \param  sched        contains sched params. If found in scheds, it is
00102  *                      not included again
00103  * \param  from         consider all threads at and above pos
00104  * \param  new_         a new thread, that is not in scheds yet, but has
00105  *                      higher prio than s. maybe 0.
00106  * \retval >0           response time, <=deadline
00107  * \retval -1           respones time would be>deadline
00108  */
00109 int sched_response_time(sched_t *sched, int from, sched_t *new_){
00110     int r, r_j, pos;
00111 
00112     /* find max delayed preemption due to lower-priorizied threads 
00113      * and add it to the start value. */
00114     r = sched->wcet + get_max_dp(sched->prio, new_);
00115     for(;;){
00116         r_j = sched->wcet + get_max_dp(sched->prio, new_);
00117         for(pos=from; pos<sched_cur_threads; pos++){
00118             if(scheds[pos]==sched) continue;
00119             if(!is_dp(scheds[pos])){
00120                 r_j += ( ((r+scheds[pos]->period-1)/scheds[pos]->period)
00121                          * scheds[pos]->wcet );
00122             } else {
00123                 /* DP */
00124             }
00125         }
00126         if(new_ && !is_dp(new_)){
00127             r_j += ((r+new_->period-1)/new_->period) * new_->wcet;
00128         }
00129         if(r_j > (sched->deadline?sched->deadline:sched->period))
00130             return -1;
00131         if(r_j == r) return r_j;
00132 
00133         r = r_j;
00134     }
00135 }
00136 
00137 /*!\brief Free an element at the given position
00138  */
00139 int sched_free(int pos){
00140     sched_t *sched;
00141 
00142     if(pos>=sched_cur_threads) return -L4_EINVAL;
00143     sched = scheds[pos];
00144     sched_cur_threads--;
00145     memmove(scheds+pos, scheds+pos+1,
00146             sizeof(sched_t*)*(sched_cur_threads-pos));
00147     if(sched->watch) l4dm_mem_release(sched->watch);
00148     if(sched->watcher!=L4THREAD_INVALID_ID){
00149         l4thread_shutdown(sched->watcher);
00150     }
00151     if(sched->dl_hist) rt_mon_hist_free(sched->dl_hist);
00152     free((char*)sched->name);
00153     free(sched);
00154     return 0;
00155 }
00156 
00157 /*!\brief Ask the watcher of a sched-entry to stop and wait for its readiness
00158  */
00159 int sched_prepare_free(int pos){
00160     sched_t *sched;
00161     l4_msgdope_t result;
00162 
00163     if(pos>=sched_cur_threads) return -L4_EINVAL;
00164     sched = scheds[pos];
00165 
00166     if(sched->watcher!=L4THREAD_INVALID_ID){
00167         /* wake the watcher fn and wait for its readyness to be killed */
00168         l4_ipc_send(l4thread_l4_id(sched->watcher), L4_IPC_SHORT_MSG, 0, 0,
00169                     L4_IPC_NEVER, &result);
00170         l4semaphore_down(&sched->watcher_end_sem);
00171     }
00172     return 0;
00173 }
00174 
00175 void lock_scheds(void){
00176     l4semaphore_down(&scheds_lock);
00177 }
00178 
00179 void unlock_scheds(void){
00180     l4semaphore_up(&scheds_lock);
00181 }

CPU reservation server Reference Manual, written by Jork Loeser  © 2004