main.c

Go to the documentation of this file.
00001 /*!
00002  * \file   cpu_reserve/server/src/main.c
00003  * \brief  CPU reservation daemon
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 <stdlib.h>
00014 #include <stdio.h>
00015 #include <l4/env/errno.h>
00016 #include <l4/log/l4log.h>
00017 #include <l4/sys/types.h>
00018 #include <l4/sys/ktrace.h>
00019 #include <l4/util/macros.h>
00020 #include <l4/util/parse_cmd.h>
00021 #include <l4/util/irq.h>
00022 #include <l4/sys/rt_sched.h>
00023 #include <l4/names/libnames.h>
00024 #include <l4/cpu_reserve/sched.h>
00025 #include "cpu_reserve-server.h"
00026 #include <l4/dm_mem/dm_mem.h>
00027 #include <l4/thread/thread.h>
00028 #include "sched.h"
00029 #include "granularity.h"
00030 #include "watch.h"
00031 #include "monitor.h"
00032 
00033 static int verbose;
00034 int watch_verbose;
00035 int monitor_enable;
00036 l4_ssize_t l4libc_heapsize = 64*1024;
00037 l4_threadid_t main_id;
00038 
00039 int l4cpu_reserve_add_component(l4_threadid_t *caller,
00040                                 const l4_threadid_t *thread,
00041                                 const char *name,
00042                                 int prio,
00043                                 int period,
00044                                 int *wcet,
00045                                 int deadline,
00046                                 int *id_p,
00047                                 CORBA_Server_Environment *env){
00048     int pos, check;
00049     sched_t *sched;
00050     const char*ncopy;
00051     int err=0, id=1;
00052 
00053     LOGd(verbose, l4util_idfmt " \"%s\": p=%d T=%d C=%d D=%d",
00054          l4util_idstr(*thread), name, prio, period, *wcet, deadline);
00055 
00056     *wcet = granularity_roundup(*wcet);
00057     if(period==0) return -L4_EINVAL;
00058     if(sched_cur_threads == sched_max_threads) return -L4_ENOMEM;
00059     /* do we habe other timeslices of the same thread, maybe even
00060      *  with a different period? */
00061     for(pos=0;pos<sched_cur_threads;pos++){
00062         if(!is_dp(scheds[pos]) &&
00063            l4_thread_equal(scheds[pos]->thread, *thread)){
00064             if(scheds[pos]->period != period) return -L4_EINVAL;
00065             id++;
00066         }
00067     }
00068 
00069     if((sched = (sched_t*)calloc(1,sizeof(sched_t)))==0){
00070         return -L4_ENOMEM;
00071     }
00072     if((ncopy = (const char*)malloc(strlen(name)+1))==0){
00073         return -L4_ENOMEM;
00074     }
00075     memcpy((char*)ncopy, name, strlen(name)+1);
00076 
00077     *sched = (sched_t){name:ncopy, thread:*thread, id:id,
00078                        creator:*caller,
00079                        prio:prio, period: period,
00080                        wcet:*wcet, deadline:deadline,
00081                        watcher:L4THREAD_INVALID_ID};
00082     pos = sched_index(prio);
00083     if(deadline){
00084         int w;
00085         w = sched_response_time(sched, pos, 0);
00086         if(verbose) printf("  reserved wcet: %d, response_time: %d\n",
00087                            *wcet, w);
00088         if(w<0){
00089             err = -L4_ETIME;
00090             goto e_sched;
00091         }
00092     }
00093 
00094     for(check=0; check<sched_cur_threads; check++){
00095         if(scheds[check]->prio > prio) break;
00096 
00097         /* check that all threads of prio p meet their deadline */
00098         if(!is_dp(scheds[check]) && scheds[check]->deadline){
00099             int p2 = sched_index(scheds[check]->prio);
00100             int w = sched_response_time(scheds[check], p2, sched);
00101             if(verbose) printf(
00102                 "  ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00103                 l4util_idstr(scheds[check]->thread),
00104                 scheds[check]->id,
00105                 scheds[check]->name,
00106                 scheds[check]->prio, scheds[check]->period,
00107                 scheds[check]->wcet, scheds[check]->deadline, w);
00108             if(w<0){
00109                 err = -L4_ETIME;
00110                 goto e_sched;
00111             }
00112         }
00113     }
00114 
00115     /* and do the reservation at the kernel */
00116     if((err = l4_rt_add_timeslice(*thread, prio, *wcet))!=0){
00117         LOG_Error("l4_rt_add_timeslice("l4util_idfmt", p=%d C=%d)=%d",
00118                   l4util_idstr(*thread), prio, *wcet, err);
00119         err = -L4_EPERM;
00120         goto e_sched;
00121     }
00122 
00123     if(id==1){
00124         // set period
00125         if(verbose) printf("  setting period at kernel to %d\n", period);
00126         l4_rt_set_period (*thread, period);
00127     }
00128 
00129     lock_scheds();
00130     /* insert into scheds */
00131     memmove(scheds+pos+1, scheds+pos,
00132             sizeof(sched_t*)*(sched_cur_threads-pos));
00133     sched_cur_threads++;
00134     scheds[pos]=sched;
00135     unlock_scheds();
00136     *id_p = id;
00137     return 0;
00138 
00139   e_sched:
00140     free((char*)sched->name);
00141     free(sched);
00142     return err;
00143 }
00144 
00145 int l4cpu_reserve_delayed_preempt_component(l4_threadid_t *caller,
00146                                             const l4_threadid_t *thread,
00147                                             int id,
00148                                             int prio,   /* ignored */
00149                                             int *delay,
00150                                             CORBA_Server_Environment *env){
00151     sched_t *sched, *dp;
00152     char*ncopy;
00153     int len, pos, err;
00154 
00155     LOGd(verbose, l4util_idfmt ": id=%d C=%d",
00156          l4util_idstr(*thread), id, *delay);
00157     /* Current kernel does not support DP anyway, and DP is handled at
00158      * client only. Thus, granularity is ideal. */
00159     
00160     if(sched_cur_threads == sched_max_threads) return -L4_ENOMEM;
00161     /* thread present, but not DP? */
00162     sched=0;
00163     for(pos=0;pos<sched_cur_threads;pos++){
00164         if(!l4_thread_equal(scheds[pos]->thread, *thread) ||
00165            id!=scheds[pos]->id) continue;
00166         if(is_dp(scheds[pos])) return -L4_EINVAL;
00167         sched=scheds[pos];
00168     }
00169     if(sched==0 && id) return -L4_EINVAL;
00170 
00171     if((dp = (sched_t*)calloc(1,sizeof(sched_t)))==0){
00172         return -L4_ENOMEM;
00173     }
00174     if(sched) len = strlen(sched->name);
00175     else len=0;
00176     if((ncopy = (char*)malloc(len+1+strlen(".dp")))==0){
00177         return -L4_ENOMEM;
00178     }
00179     if(sched)memcpy(ncopy, sched->name, len);
00180     memcpy(ncopy+len, ".dp", strlen(".dp")+1);
00181 
00182     *dp = (sched_t){name:ncopy, thread:*thread, id:id,
00183                     creator:*caller,
00184                     prio:sched?sched->prio:0, period: 0,
00185                     wcet:*delay, deadline:0,
00186                     watcher:L4THREAD_INVALID_ID};
00187 
00188     for(pos=0; pos<sched_cur_threads; pos++){
00189         if(!is_dp(scheds[pos]) && scheds[pos]->deadline){
00190             int p2 = sched_index(scheds[pos]->prio);
00191             int w = sched_response_time(scheds[pos], p2, dp);
00192             if(verbose) printf(
00193                 "  ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00194                 l4util_idstr(scheds[pos]->thread),
00195                 scheds[pos]->id,
00196                 scheds[pos]->name,
00197                 scheds[pos]->prio, scheds[pos]->period,
00198                 scheds[pos]->wcet, scheds[pos]->deadline, w);
00199             if(w<0){
00200                 err = -L4_ETIME;
00201                 goto e_dp;
00202             }
00203         }
00204     }
00205 
00206     /* insert into scheds */
00207     pos = sched_index(dp->prio);
00208     lock_scheds();
00209     memmove(scheds+pos+1, scheds+pos,
00210             sizeof(sched_t*)*(sched_cur_threads-pos));
00211     sched_cur_threads++;
00212     scheds[pos]=dp;
00213     unlock_scheds();
00214     return 0;
00215 
00216   e_dp:
00217     free((char*)dp->name);
00218     free(dp);
00219     return err;
00220 
00221 
00222 }
00223 
00224 int l4cpu_reserve_change_component(l4_threadid_t *caller,
00225                                    const l4_threadid_t *thread,
00226                                    int id,
00227                                    int new_prio,
00228                                    int *new_wcet,
00229                                    int new_deadline,
00230                                    CORBA_Server_Environment *env){
00231     sched_t *sched;
00232     int pos, err=0;
00233     int check_local=0, check_others=0;
00234     sched_t sched_copy;
00235 
00236     LOGd(verbose, l4util_idfmt ": p=%d C=%d D=%d",
00237          l4util_idstr(*thread), new_prio, *new_wcet, new_deadline);
00238     if(*new_wcet>=0) *new_wcet = granularity_roundup(*new_wcet);
00239     /* find the sched context */
00240     for(pos=0;pos<sched_cur_threads;pos++){
00241         if(!is_dp(scheds[pos]) &&
00242            l4_thread_equal(scheds[pos]->thread, *thread) &&
00243            scheds[pos]->id == id){
00244             break;
00245         }
00246     }
00247     if(pos==sched_cur_threads) return -L4_ENOTFOUND;
00248 
00249     sched = scheds[pos];
00250     memcpy(&sched_copy, sched, sizeof(sched_t));
00251 
00252     /* what can happen:
00253      * prio increases -> local times will be ok, check all others
00254      *                   below or equal new prio
00255      * prio decreases -> check local times and all below or equal new
00256      * wcet increases -> check local and all below or equal
00257      * wcet decreases -> ok
00258      * dl   increases -> ok
00259      * dl   decreases -> check local
00260      */
00261     if(new_prio>=0){
00262         sched->prio = new_prio;
00263         check_others=1;
00264         if(new_prio < sched_copy.prio) check_local=1;
00265     }
00266     if(*new_wcet>=0){
00267         sched->wcet = *new_wcet;
00268         if(*new_wcet > sched_copy.wcet){
00269             check_others = check_local = 1;
00270         }
00271     }
00272     if(new_deadline>=0){
00273         sched->deadline = new_deadline;
00274         if(!sched_copy.deadline || (new_deadline &&
00275                                     new_deadline < sched_copy.deadline)){
00276             check_local=1;
00277         }
00278     }
00279     /* if deadline is not "optional" now, check it */
00280     if(check_local && new_deadline){
00281         int w, i;
00282         i = sched_index(sched->prio);
00283         /* we changed sched it in-place, thus there is no new context */
00284         w = sched_response_time(sched, i, 0);
00285         if(verbose) printf("  reserved wcet: %d, response_time: %d\n",
00286                            sched->wcet, w);
00287         if(w<0){
00288             err = -L4_ETIME;
00289             goto e_back;
00290         }
00291     }
00292     if(check_others){
00293         int i;
00294 
00295         for(i=0; i<sched_cur_threads; i++){
00296             int p2, w;
00297 
00298             if(scheds[i]->prio > sched->prio) break;
00299             if(is_dp(scheds[i]) ||
00300                scheds[i]==sched ||
00301                scheds[i]->deadline==0 ) continue;
00302 
00303             p2 = sched_index(scheds[i]->prio);
00304             /* we changed sched in-place, thus there is no new context */
00305             w = sched_response_time(scheds[i], p2, 0);
00306             if(verbose)printf(
00307                 "  ->" l4util_idfmt "/%d \"%s\" p=%d T=%d C=%d D=%d: time=%d\n",
00308                 l4util_idstr(scheds[i]->thread),
00309                 scheds[i]->id,
00310                 scheds[i]->name,
00311                 scheds[i]->prio, scheds[i]->period,
00312                 scheds[i]->wcet, scheds[i]->deadline, w);
00313             if(w<0){
00314                 err = -L4_ETIME;
00315                 goto e_back;
00316             }
00317         }
00318     }
00319     /* all checks passed. Change at kernel, remove the old sched,
00320      * insert the new.
00321      */
00322     if(l4_rt_change_timeslice(sched->thread, sched->id,
00323                               sched->prio, sched->wcet)){
00324         err = -L4_EPERM;
00325         goto e_back;
00326     }
00327     /* if prio changed, remove sched at entry pos */
00328     if(new_prio>=0){
00329         int new_pos;
00330 
00331         lock_scheds();
00332         sched_cur_threads--;
00333         /* remove the old */
00334         if(pos!=sched_cur_threads){
00335             memmove(scheds+pos, scheds+pos+1,
00336                     sizeof(sched_t*)*(sched_cur_threads-pos));
00337         }
00338         /* insert the new */
00339         new_pos = sched_index(new_prio);
00340         memmove(scheds+new_pos+1, scheds+new_pos,
00341                 sizeof(sched_t*)*(sched_cur_threads-new_pos));
00342         sched_cur_threads++;
00343         scheds[new_pos]=sched;
00344         unlock_scheds();
00345     }
00346     /* and finally return */
00347     return 0;
00348 
00349   e_back:
00350     memcpy(sched, &sched_copy, sizeof(sched_t));
00351     return err;
00352 }
00353 
00354 
00355 
00356 int l4cpu_reserve_delete_thread_component(l4_threadid_t *caller,
00357                                           const l4_threadid_t *thread,
00358                                           CORBA_Server_Environment *env){
00359     int i, err;
00360 
00361     LOGd(verbose, l4util_idfmt, l4util_idstr(*thread));
00362 
00363     /* lookup thread to see if we know it */
00364     for(i=0;i<sched_cur_threads;i++){
00365         if(l4_thread_equal(scheds[i]->thread, *thread)) break;
00366     }
00367     if(i==sched_cur_threads) return -L4_ENOTFOUND;
00368 
00369     /* kill the reservation at fiasco */
00370     err = l4_rt_remove(*thread);
00371     if(err){
00372         LOG_Error("l4_rt_remove("l4util_idfmt")=%d",
00373                   l4util_idstr(*thread), err);
00374         return -L4_EPERM;
00375     }
00376 
00377     /* prepare the watcher threads to be killed, w/o holding a lock */
00378     for(i=0;i<sched_cur_threads;i++){
00379         if(l4_thread_equal(scheds[i]->thread, *thread)){
00380             sched_prepare_free(i);
00381         }
00382     }
00383     
00384     lock_scheds();
00385     /* remove the entries from our database */
00386     for(i=0;i<sched_cur_threads;i++){
00387         if(l4_thread_equal(scheds[i]->thread, *thread)){
00388             sched_free(i);
00389             i--;
00390         }
00391     }
00392     unlock_scheds();
00393     return 0;
00394 }
00395 
00396 int l4cpu_reserve_delete_task_component(l4_threadid_t *caller,
00397                                         const l4_threadid_t *task,
00398                                         CORBA_Server_Environment *env){
00399     int i, found=0;
00400 
00401     LOGd(verbose, l4util_idfmt, l4util_idstr(*task));
00402 
00403     /* prepare the watcher threads to be killed, w/o holding a lock */
00404     for(i=0;i<sched_cur_threads;i++){
00405         if(l4_task_equal(scheds[i]->thread, *task)){
00406             sched_prepare_free(i);
00407         }
00408     }
00409     lock_scheds();
00410     for(i=0;i<sched_cur_threads;i++){
00411         if(l4_task_equal(scheds[i]->thread, *task)){
00412             /* caution: the following may fail. This is bad, as
00413              * inconsistencies may occur. */
00414             l4_rt_remove(scheds[i]->thread);
00415             sched_free(i);
00416             i--;
00417             found=1;
00418         }
00419     }
00420     unlock_scheds();
00421     return found?0:-L4_ENOTFOUND;
00422 }
00423 
00424 int l4cpu_reserve_begin_strictly_periodic_component(
00425     l4_threadid_t *caller,
00426     const l4_threadid_t *thread,
00427     l4_kernel_clock_t clock,
00428     CORBA_Server_Environment *env){
00429 
00430     int err;
00431 
00432     LOGd(verbose, l4util_idfmt " at clock=%lld", l4util_idstr(*thread), clock);
00433 
00434     //l4_sleep(10);
00435     LOGk("start periodic("l4util_idfmt",%lld)...",
00436          l4util_idstr(*thread),clock);
00437     err = l4_rt_begin_strictly_periodic(*thread, clock);
00438     LOGk("periodic("l4util_idfmt")=%d", l4util_idstr(*thread), err);
00439     if(err){
00440         LOG_Error("l4_rt_begin_strictly_periodic("l4util_idfmt") failed",
00441                   l4util_idstr(*thread));
00442     }
00443     return err?-L4_EPERM:0;
00444 }
00445 
00446 int l4cpu_reserve_begin_minimal_periodic_component(
00447     l4_threadid_t *caller,
00448     const l4_threadid_t *thread,
00449     l4_kernel_clock_t clock,
00450     CORBA_Server_Environment *env){
00451 
00452     int err;
00453 
00454     LOGd(verbose, l4util_idfmt " at clock=%lld", l4util_idstr(*thread), clock);
00455 
00456     err = l4_rt_begin_minimal_periodic(*thread, clock);
00457     return err?-L4_EPERM:0;
00458 }
00459 
00460 int l4cpu_reserve_end_periodic_component(l4_threadid_t *caller,
00461                                          const l4_threadid_t *thread,
00462                                          CORBA_Server_Environment *env){
00463 
00464     int err;
00465 
00466     LOGd(verbose, l4util_idfmt, l4util_idstr(*thread));
00467 
00468     err = l4_rt_end_periodic(*thread);
00469     return err?-L4_EPERM:0;
00470 }
00471 
00472 int l4cpu_reserve_watch_component(l4_threadid_t *caller,
00473                                   const l4_threadid_t *thread,
00474                                   l4dm_dataspace_t *ds,
00475                                   l4_threadid_t *preempter,
00476                                   CORBA_Server_Environment *env){
00477     int i;
00478 
00479     LOGd(verbose,
00480          "thread="l4util_idfmt, l4util_idstr(*thread));
00481     /* find the thread-id. */
00482     for(i=0;i<sched_cur_threads;i++){
00483         if(l4_thread_equal(scheds[i]->thread, *thread) &&
00484            scheds[i]->id == 1 &&
00485            !is_dp(scheds[i])){
00486             void *addr;
00487             int err;
00488 
00489             /* we have the entry. We watch a thread only once. */
00490             if(scheds[i]->watch) return -L4_EBUSY;
00491 
00492             if((addr = l4dm_mem_ds_allocate_named(L4_PAGESIZE, 0, "watch",
00493                                                   ds))==0)
00494                 return -L4_EINVAL;
00495             memset(addr, 0, L4_PAGESIZE);
00496             /* share with caller */
00497             if((err = l4dm_share(ds, *caller, L4DM_RW))!=0){
00498                 goto e_mem;
00499             }
00500 
00501             /* generate monitor event, if monitoring is enabled */
00502             if(monitor_enable && (err = monitor_start(scheds[i], thread))!=0){
00503                 goto e_mem;
00504             }
00505             
00506             scheds[i]->watcher_end_sem = L4SEMAPHORE_LOCKED;
00507             if((err = l4thread_create_named(watcher_fn,
00508                                             ".watcher",
00509                                             &scheds[i]->watcher_end_sem,
00510                                             L4THREAD_CREATE_ASYNC))<0){
00511                 l4dm_mem_release(addr);
00512                 return err;
00513             }
00514             scheds[i]->watcher = err;
00515 
00516             /* set preempter */
00517             *preempter = l4thread_l4_id(scheds[i]->watcher);
00518             scheds[i]->watch = (unsigned*)addr;
00519             
00520             return 0;
00521 
00522           e_mem:
00523             l4dm_mem_release(addr);
00524             return err;
00525         }
00526     }
00527     return -L4_ENOTFOUND;
00528 
00529 }
00530 
00531 int l4cpu_reserve_scheds_count_component(l4_threadid_t *caller,
00532                                          CORBA_Server_Environment *env){
00533     LOGd_Enter(verbose, "returning %d", sched_cur_threads);
00534     return sched_cur_threads;
00535 }
00536 
00537 int l4cpu_reserve_scheds_get_component(l4_threadid_t *caller,
00538                                        int idx,
00539                                        char **name,
00540                                        l4_threadid_t *thread,
00541                                        l4_threadid_t *creator,
00542                                        int *id,
00543                                        int *prio,
00544                                        int *period,
00545                                        int *wcet,
00546                                        int *deadline,
00547                                        CORBA_Server_Environment *env){
00548     if(idx>=sched_cur_threads || idx<0) return -L4_EINVAL;
00549     *name       = (char*)scheds[idx]->name;
00550     *thread     = scheds[idx]->thread;
00551     *creator    = scheds[idx]->creator;
00552     *id         = scheds[idx]->id;
00553     *prio       = scheds[idx]->prio;
00554     *wcet       = scheds[idx]->wcet;
00555     *period     = scheds[idx]->period;
00556     *deadline   = scheds[idx]->deadline;
00557     return 0;
00558 }
00559 
00560 int l4cpu_reserve_time_demand_component(l4_threadid_t *caller,
00561                                         const l4_threadid_t *thread,
00562                                         int id,
00563                                         CORBA_Server_Environment *env){
00564     int i;
00565 
00566     /* find the thread-id. */
00567     for(i=0;i<sched_cur_threads;i++){
00568         if(l4_thread_equal(scheds[i]->thread, *thread) &&
00569            scheds[i]->id==id && !is_dp(scheds[i])){
00570             int delay;
00571             delay = sched_response_time(scheds[i], i, 0);
00572             return delay>=0?delay:-L4_ETIME;
00573         }
00574     }
00575     return -L4_EINVAL;
00576 }
00577 
00578 int main(int argc, const char**argv){
00579     int err;
00580 
00581     main_id = l4_myself();
00582     if(parse_cmdline(&argc, &argv,
00583                      't', "threads", "max number of threads to manage",
00584                      PARSE_CMD_INT, 1000, &sched_max_threads,
00585                      'v', "verbose", "verbose mode",
00586                      PARSE_CMD_SWITCH, 1, &verbose,
00587                      'w', "watch", "verbose: log watch preemptions",
00588                      PARSE_CMD_SWITCH, 1, &watch_verbose,
00589                      'm', "monitor", "monitor preemptions to rt_mon",
00590                      PARSE_CMD_SWITCH, 1, &monitor_enable,
00591                      0,0)) return 1;
00592     if((err = sched_init())!=0){
00593         l4env_perror("sched_init()", -err);
00594         return 1;
00595     }
00596 
00597     if(names_register(l4cpu_reserve_name)==0){
00598         LOG_Error("names_register failed");
00599         return 1;
00600     }
00601     printf("Scheduling granularity: %dµs\n", granularity());
00602     l4cpu_reserve_server_loop(0);
00603 }

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