Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

RKTask.cc

Go to the documentation of this file.
00001 /*
00002  * RKTask.cc
00003  *
00004  * Copyright (c) 2003 The University of Utah and the Flux Group.
00005  * All rights reserved.
00006  *
00007  * This file is licensed under the terms of the GNU Public License.  
00008  * See the file "license.terms" for restrictions on redistribution 
00009  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00010  */
00011 
00012 /**
00013  * @file RKTask.cc
00014  *
00015  * Implementation of the RKTask class.
00016  */
00017 
00018 #include "config.h"
00019 
00020 #include <string.h>
00021 
00022 #include <iostream>
00023 #include <fstream>
00024 #include <iomanip>
00025 
00026 #include <assert_pp.h>
00027 #include <time_util.h>
00028 #include <instrumentation.h>
00029 
00030 #include "RKTask.hh"
00031 
00032 #include "rk_util.h"
00033 
00034 #if !defined(__XSTRING)
00035 /**
00036  * Convert a macro argument to a string.
00037  *
00038  * @param x The macro to expand to a string.
00039  */
00040 #define __XSTRING(x) __STRING(x)
00041 #endif
00042 
00043 /**
00044  * "Repair" the system by deleting any resource sets that have a CPU reserve
00045  * but no processes.
00046  */
00047 static void rktRepairResourceSets(void)
00048 {
00049 #define MAX_RK_SETS 128
00050     static rk_resource_set_t rk_sets[MAX_RK_SETS];
00051     
00052     unsigned int lpc, actual;
00053 
00054     actual = rk_resource_sets_get_list(rk_sets, MAX_RK_SETS);
00055     for( lpc = 0; lpc < actual; lpc++ )
00056     {
00057         int proc_count = rk_resource_set_get_num_procs(rk_sets[lpc]);
00058         rk_reserve_t cr = rk_resource_set_get_cpu_rsv(rk_sets[lpc]);
00059         
00060         if( (proc_count == 0) && (cr != NULL_RESERVE) )
00061         {
00062             rk_resource_set_destroy(rk_sets[lpc]);
00063             rk_sets[lpc] = NULL_RESOURCE_SET;
00064         }
00065     }
00066 #undef MAX_RK_SETS
00067 }
00068 
00069 RKTask::RKTask(const Broker::TaskParameters &tp)
00070     throw (CORBA::SystemException,
00071            Broker::DuplicateTaskParameter,
00072            Broker::InvalidTaskParameter,
00073            Broker::MissingTaskParameter)
00074 {
00075     unsigned int lpc;
00076 
00077     gettimeofday(&this->rkt_StartTime, NULL);
00078     this->rkt_LastReservationLog = this->rkt_StartTime;
00079     this->rkt_ReservationLog = NULL;
00080     
00081     memset(&this->rkt_CPUReserveSpec, 0, sizeof(this->rkt_CPUReserveSpec));
00082     this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00083     this->rkt_CPUReserve = NULL_RESERVE;
00084 
00085     /* Process the arguments */
00086     for( lpc = 0; lpc < tp.length(); lpc++ )
00087     {
00088         if( strcasecmp(tp[lpc].name.in(), "name") == 0 )
00089         {
00090             const char *name;
00091 
00092             if( this->rkt_Name != NULL )
00093             {
00094                 throw Broker::DuplicateTaskParameter("name");
00095             }
00096             else if( tp[lpc].value >>= name )
00097             {
00098                 if( strlen(name) >= RK_NAME_LEN )
00099                 {
00100                     throw Broker::InvalidTaskParameter(
00101                         "'name' is too long, only "
00102                         __XSTRING(RK_NAME_LEN)
00103                         " characters are allowed",
00104                         tp[lpc]);
00105                 }
00106                 else
00107                 {
00108                     this->rkt_Name = name;
00109                 }
00110             }
00111             else
00112             {
00113                 throw Broker::InvalidTaskParameter("'name' not a string",
00114                                                    tp[lpc]);
00115             }
00116         }
00117         else if( (strcasecmp(tp[lpc].name.in(), "res_log") == 0) ||
00118                  (strcasecmp(tp[lpc].name.in(), "res-log") == 0) ||
00119                  (strcasecmp(tp[lpc].name.in(), "res log") == 0) )
00120         {
00121             const char *res_log;
00122             
00123             if( this->rkt_ReservationLog != NULL )
00124             {
00125                 throw Broker::DuplicateTaskParameter("res log");
00126             }
00127             else if( tp[lpc].value >>= res_log )
00128             {
00129                 this->rkt_ReservationLog = new ofstream(res_log);
00130                 (*this->rkt_ReservationLog) << setfill('0');
00131                 (*this->rkt_ReservationLog)
00132                     << "# start: "
00133                     << (long)this->rkt_StartTime.tv_sec
00134                     << "."
00135                     << setw(6) << (long)this->rkt_StartTime.tv_usec
00136                     << endl;
00137             }
00138             else
00139             {
00140                 throw Broker::InvalidTaskParameter("'res log' not a string",
00141                                                    tp[lpc]);
00142             }
00143         }
00144     }
00145     
00146     /* Make sure we have everything we need. */
00147     if( this->rkt_Name == NULL )
00148     {
00149         throw Broker::MissingTaskParameter("name");
00150     }
00151 }
00152 
00153 RKTask::~RKTask()
00154 {
00155     if( !CORBA::is_nil(this->rkt_Manager.in()) )
00156     {
00157         this->EndCPUScheduling();
00158     }
00159     if( this->rkt_ReservationLog != NULL )
00160     {
00161         delete this->rkt_ReservationLog;
00162     }
00163 }
00164 
00165 char *RKTask::Name(void)
00166     throw (CORBA::SystemException)
00167 {
00168     CORBA::String_var retval;
00169 
00170     retval = this->rkt_Name;
00171     return( retval._retn() );
00172 }
00173 
00174 CORBA::ULong RKTask::Period(void)
00175     throw (CORBA::SystemException)
00176 {
00177     CORBA::ULong retval;
00178 
00179     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.period);
00180     return( retval );
00181 }
00182 
00183 CORBA::ULong RKTask::Deadline(void)
00184     throw (CORBA::SystemException)
00185 {
00186     CORBA::ULong retval;
00187 
00188     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.deadline);
00189     return( retval );
00190 }
00191 
00192 void RKTask::BeginCPUScheduling(Broker::Manager_ptr manager,
00193                                 const Broker::ScheduleParameters &cs)
00194     throw (CORBA::SystemException,
00195            Broker::DuplicateScheduleParameter,
00196            Broker::InvalidScheduleParameter,
00197            Broker::MissingScheduleParameter)
00198 {
00199     CORBA::ULongLong start = 0, period = ~0, deadline = ~0;
00200     unsigned int lpc;
00201     const char *str;
00202     pid_t pid = -1;
00203     
00204     if( this->rkt_CPUReserve != NULL_RESERVE )
00205     {
00206         throw CORBA::BAD_INV_ORDER();
00207     }
00208     
00209     /* Process the arguments */
00210     if( CORBA::is_nil(manager) )
00211     {
00212         throw CORBA::BAD_PARAM();
00213     }
00214     for( lpc = 0; lpc < cs.length(); lpc++ )
00215     {
00216         if( strcasecmp(cs[lpc].name.in(), "start") == 0 )
00217         {
00218             if( ((cs[lpc].value >>= str) && string_to_microsec(&start, str)) )
00219             {
00220             }
00221             else
00222             {
00223                 throw Broker::InvalidScheduleParameter("'start' is not a time",
00224                                                        cs[lpc]);
00225             }
00226         }
00227         else if( strcasecmp(cs[lpc].name.in(), "pid") == 0 )
00228         {
00229             CORBA::Long c_pid;
00230             const char *str;
00231 
00232             if( pid != -1 )
00233             {
00234                 throw Broker::DuplicateScheduleParameter("pid");
00235             }
00236             else if( cs[lpc].value >>= c_pid )
00237             {
00238                 pid = c_pid;
00239             }
00240             else if( (cs[lpc].value >>= str) &&
00241                      (sscanf(str, "%d", &pid) == 1) )
00242             {
00243             }
00244             else
00245             {
00246                 throw Broker::InvalidScheduleParameter("'pid' not a long",
00247                                                        cs[lpc]);
00248             }
00249             if( pid < 0 )
00250             {
00251                 pid = -1;
00252                 throw Broker::InvalidScheduleParameter("'pid' not a long",
00253                                                        cs[lpc]);
00254             }
00255         }
00256         else if( strcasecmp(cs[lpc].name.in(), "period") == 0 )
00257         {
00258             CORBA::ULong period_ul;
00259             
00260             if( period != ~0ULL )
00261             {
00262                 throw Broker::DuplicateScheduleParameter("period");
00263             }
00264             else if( cs[lpc].value >>= period_ul )
00265             {
00266                 period = period_ul;
00267             }
00268             else if( (cs[lpc].value >>= str) &&
00269                      string_to_microsec(&period, str) )
00270             {
00271             }
00272             else
00273             {
00274                 throw Broker::InvalidScheduleParameter(
00275                         "'period' is not a time",
00276                         cs[lpc]);
00277             }
00278         }
00279         else if( strcasecmp(cs[lpc].name.in(), "deadline") == 0 )
00280         {
00281             CORBA::ULong deadline_ul;
00282             
00283             if( deadline != ~0ULL )
00284             {
00285                 throw Broker::DuplicateScheduleParameter("deadline");
00286             }
00287             else if( cs[lpc].value >>= deadline_ul )
00288             {
00289                 deadline = deadline_ul;
00290             }
00291             else if( (cs[lpc].value >>= str) &&
00292                      string_to_microsec(&deadline, str) )
00293             {
00294             }
00295             else
00296             {
00297                 throw Broker::InvalidScheduleParameter(
00298                         "'deadline' is not a time",
00299                         cs[lpc]);
00300             }
00301         }
00302     }
00303     
00304     /* Make sure we have everything we need */
00305     if( period == ~0ULL )
00306     {
00307         throw Broker::MissingScheduleParameter("period");
00308     }
00309     if( pid == -1 )
00310     {
00311         throw Broker::MissingScheduleParameter("pid");
00312     }
00313     
00314     /* ... and derive the rest. */
00315     if( deadline == ~0ULL )
00316     {
00317         deadline = period;
00318     }
00319 
00320     /* Clean house first, then */
00321     rktRepairResourceSets();
00322 
00323     /* ... go ahead and create/find a resource set for the process. */
00324     if( (this->rkt_ResourceSet = rk_proc_get_rset(pid)) != NULL_RESOURCE_SET )
00325     {
00326         /* We'll just manage the existing resource set. */
00327     }
00328     else if( ((this->rkt_ResourceSet =
00329                rk_resource_set_get_by_name(this->rkt_Name.in())) != NULL) ||
00330              ((this->rkt_ResourceSet =
00331                rk_resource_set_create(this->rkt_Name.in())) != NULL) )
00332     {
00333         rk_reserve_t old_reserve;
00334 
00335         /* Check for an existing reserve. */
00336         if( (old_reserve = rk_resource_set_get_cpu_rsv(this->rkt_ResourceSet))
00337             != NULL_RESERVE )
00338         {
00339             if( rk_resource_set_get_num_procs(this->rkt_ResourceSet) == 0 )
00340             {
00341                 /*
00342                  * Assume something went horribly wrong.  Destroy the reserve
00343                  * in preparation for adding our own reserve.
00344                  */
00345                 if( rk_cpu_reserve_delete(this->rkt_ResourceSet) == -1 )
00346                 {
00347                     cerr << strerror(errno)
00348                          << ": rk_cpu_reserve_delete"
00349                          << endl;
00350                 }
00351             }
00352             else
00353             {
00354                 Broker::NamedValue nv;
00355                 
00356                 /* Someone else is using this set... */
00357                 this->rkt_ResourceSet = NULL_RESOURCE_SET;
00358                 nv.name = "name";
00359                 nv.value <<= this->rkt_Name;
00360                 throw Broker::InvalidScheduleParameter("name", nv);
00361             }
00362         }
00363         if( rk_resource_set_attach_process(this->rkt_ResourceSet, pid) == 0 )
00364         {
00365             /*
00366              * Joy, we'll attach a CPU reservation later in BeginCPUScheduling
00367              */
00368         }
00369         else if( errno != EBUSY )
00370         {
00371             /* No joy, something went wrong. */
00372             rk_resource_set_destroy(this->rkt_ResourceSet);
00373             this->rkt_ResourceSet = NULL_RESOURCE_SET;
00374             throw CORBA::NO_MEMORY(); // XXX
00375         }
00376         else
00377         {
00378             /* This process is already attached. */
00379         }
00380     }
00381     else
00382     {
00383         cerr << strerror(errno) << ": rk_resource_set_create" << endl;
00384         throw CORBA::NO_MEMORY(); // XXX
00385     }
00386     
00387     this->rkt_Manager = Broker::Manager::_duplicate(manager);
00388 
00389     /* XXX Do more checking here... */
00390     if( (this->rkt_CPUReserveSpec.compute_time.tv_sec == 0) &&
00391         (this->rkt_CPUReserveSpec.compute_time.tv_nsec == 0) )
00392     {
00393         this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00394     }
00395     this->rkt_CPUReserveSpec.period = microsec_to_timespec(period);
00396     this->rkt_CPUReserveSpec.deadline = microsec_to_timespec(deadline);
00397     this->rkt_CPUReserveSpec.reserve_type.sch_mode = RSV_SOFT;
00398     this->rkt_CPUReserveSpec.reserve_type.enf_mode = RSV_SOFT;
00399     this->rkt_CPUReserveSpec.reserve_type.rep_mode = RSV_SOFT;
00400     this->rkt_CPUReserveSpec.processor = RK_ANY_CPU;
00401 
00402     switch( int rc = rk_cpu_reserve_create(this->rkt_ResourceSet,
00403                                            &this->rkt_CPUReserve,
00404                                            &this->rkt_CPUReserveSpec) )
00405     {
00406     case 0:
00407         break;
00408     case -1:
00409         cerr << strerror(errno) << ":rk_cpu_reserve_create" << endl;
00410         throw Broker::InvalidScheduleParameter();
00411     default:
00412         cerr << rc << endl;
00413         throw Broker::Internal("Unhandled return value at: "
00414                                __FILE__
00415                                ":"
00416                                __STRING(__LINE__));
00417     }
00418 }
00419 
00420 void RKTask::EndCPUScheduling(void)
00421     throw (CORBA::SystemException)
00422 {
00423     if( this->rkt_CPUReserve == NULL_RESERVE )
00424     {
00425         throw CORBA::BAD_INV_ORDER();
00426     }
00427 
00428     rk_resource_set_destroy(this->rkt_ResourceSet);
00429     this->rkt_ResourceSet = NULL_RESOURCE_SET;
00430     this->rkt_CPUReserve = NULL_RESERVE;
00431     this->rkt_Manager = Broker::Manager::_nil();
00432 }
00433 
00434 CORBA::ULong RKTask::GetComputeTime(void)
00435     throw (CORBA::SystemException)
00436 {
00437     CORBA::ULong retval;
00438 
00439     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00440     return( retval );
00441 }
00442 
00443 void RKTask::SetComputeTime(CORBA::ULong usecs)
00444     throw (CORBA::SystemException)
00445 {
00446     struct timespec old_ct;
00447 
00448     if( usecs == 0 )
00449     {
00450         throw CORBA::BAD_PARAM();
00451     }
00452     
00453     old_ct = this->rkt_CPUReserveSpec.compute_time;
00454     this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(usecs);
00455 
00456     if( this->rkt_CPUReserve != NULL_RESERVE )
00457     {
00458         switch( rk_cpu_reserve_ctl(this->rkt_ResourceSet,
00459                                    &this->rkt_CPUReserveSpec) )
00460         {
00461         case 0:
00462             if( this->rkt_ReservationLog != NULL )
00463             {
00464                 struct timeval tv, st, diff;
00465                 
00466                 timersub(&this->rkt_LastReservationLog,
00467                          &this->rkt_StartTime,
00468                          &diff);
00469                 st.tv_sec = usecs / 1000000;
00470                 st.tv_usec = usecs % 1000000;
00471                 gettimeofday(&tv, NULL);
00472                 timersub(&tv, &this->rkt_StartTime, &diff);
00473                 (*this->rkt_ReservationLog)
00474                     << (long)diff.tv_sec
00475                     << "."
00476                     << setw(6) << (long)diff.tv_usec
00477                     << " "
00478                     << (long)st.tv_sec
00479                     << "."
00480                     << setw(6) << (long)st.tv_usec
00481                     << endl;
00482                 this->rkt_LastReservationLog = tv;
00483             }
00484             break;
00485         case -1:
00486             switch( errno )
00487             {
00488             case EINVAL:
00489                 ensure(0);
00490                 break;
00491             case ENODEV:
00492                 ensure(0);
00493                 break;
00494             case ENOSPC:
00495                 cerr << "** SetComputeTime failed! "
00496                      << usecs
00497                      << endl;
00498                 break;
00499             case EFAULT:
00500                 ensure(0);
00501                 break;
00502             case EACCES:
00503                 cerr << "** No permission to change compute time? "
00504                      << usecs
00505                      << endl;
00506                 break;
00507             case ENOSYS:
00508                 ensure(0);
00509                 break;
00510             }
00511             this->rkt_CPUReserveSpec.compute_time = old_ct;
00512             throw CORBA::BAD_PARAM();
00513         }
00514     }
00515     else
00516     {
00517         /* We're not scheduling at the moment, just remember the value. */
00518         if( this->rkt_ReservationLog != NULL )
00519         {
00520             struct timeval tv, st, diff;
00521             
00522             timersub(&this->rkt_LastReservationLog,
00523                      &this->rkt_StartTime,
00524                      &diff);
00525             st.tv_sec = usecs / 1000000;
00526             st.tv_usec = usecs % 1000000;
00527             gettimeofday(&tv, NULL);
00528             timersub(&tv, &this->rkt_StartTime, &diff);
00529             (*this->rkt_ReservationLog)
00530                 << (long)diff.tv_sec
00531                 << "."
00532                 << setw(6) << (long)diff.tv_usec
00533                 << " "
00534                 << (long)st.tv_sec
00535                 << "."
00536                 << setw(6) << (long)st.tv_usec
00537                 << endl;
00538             this->rkt_LastReservationLog = tv;
00539         }
00540     }
00541 }
00542 
00543 void RKTask::ReportCPU(Broker::RealTimeTask_ptr rtt,
00544                        CORBA::ULong status,
00545                        CORBA::ULong advice)
00546     throw (CORBA::SystemException)
00547 {
00548     CORBA::ULong ct;
00549 
00550     if( CORBA::is_nil(this->rkt_Manager) )
00551     {
00552         throw CORBA::BAD_INV_ORDER();
00553     }
00554     if( CORBA::is_nil(rtt) )
00555     {
00556         throw CORBA::BAD_PARAM();
00557     }
00558     if( advice == 0 )
00559     {
00560         throw CORBA::BAD_PARAM();
00561     }
00562     ct = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00563     this->rkt_Manager->ChangeTaskCPU(rtt, ct, status, advice);
00564 }

Generated on Mon Dec 1 16:29:07 2003 for CPU Broker by doxygen 1.3.4