00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00037
00038
00039
00040 #define __XSTRING(x) __STRING(x)
00041 #endif
00042
00043
00044
00045
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
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
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
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
00305 if( period == ~0ULL )
00306 {
00307 throw Broker::MissingScheduleParameter("period");
00308 }
00309 if( pid == -1 )
00310 {
00311 throw Broker::MissingScheduleParameter("pid");
00312 }
00313
00314
00315 if( deadline == ~0ULL )
00316 {
00317 deadline = period;
00318 }
00319
00320
00321 rktRepairResourceSets();
00322
00323
00324 if( (this->rkt_ResourceSet = rk_proc_get_rset(pid)) != NULL_RESOURCE_SET )
00325 {
00326
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
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
00343
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
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
00367
00368 }
00369 else if( errno != EBUSY )
00370 {
00371
00372 rk_resource_set_destroy(this->rkt_ResourceSet);
00373 this->rkt_ResourceSet = NULL_RESOURCE_SET;
00374 throw CORBA::NO_MEMORY();
00375 }
00376 else
00377 {
00378
00379 }
00380 }
00381 else
00382 {
00383 cerr << strerror(errno) << ": rk_resource_set_create" << endl;
00384 throw CORBA::NO_MEMORY();
00385 }
00386
00387 this->rkt_Manager = Broker::Manager::_duplicate(manager);
00388
00389
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
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 }