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 using namespace std;
00035
00036 #define INSTR_rktask_change_cpu LRTIME_INSTR
00037 #define INSTR_rktask_change_cpu_data "rktask_change_cpu", "The wall clock time needed to run ChangeTaskCPU"
00038
00039 #if defined(INSTR_rktask_change_cpu_data)
00040 static struct iPoint INSTR_rktask_change_cpu_point = {
00041 INSTR_rktask_change_cpu_data
00042 };
00043 #endif
00044
00045 #if !defined(__XSTRING)
00046
00047
00048
00049
00050
00051 #define __XSTRING(x) __STRING(x)
00052 #endif
00053
00054
00055
00056
00057
00058 static void rktRepairResourceSets(void)
00059 {
00060 #define MAX_RK_SETS 128
00061 static rk_resource_set_t rk_sets[MAX_RK_SETS];
00062
00063 unsigned int lpc, actual;
00064
00065 actual = rk_resource_sets_get_list(rk_sets, MAX_RK_SETS);
00066 for( lpc = 0; lpc < actual; lpc++ )
00067 {
00068 int proc_count = rk_resource_set_get_num_procs(rk_sets[lpc]);
00069 rk_reserve_t cr = rk_resource_set_get_cpu_rsv(rk_sets[lpc]);
00070
00071 if( (proc_count == 0) && (cr != NULL_RESERVE) )
00072 {
00073 rk_resource_set_destroy(rk_sets[lpc]);
00074 rk_sets[lpc] = NULL_RESOURCE_SET;
00075 }
00076 }
00077 #undef MAX_RK_SETS
00078 }
00079
00080 RKTask::RKTask(const Broker::TaskParameters &tp)
00081 throw (CORBA::SystemException,
00082 Broker::DuplicateTaskParameter,
00083 Broker::InvalidTaskParameter,
00084 Broker::MissingTaskParameter)
00085 {
00086 unsigned int lpc;
00087
00088 gettimeofday(&this->rkt_StartTime, NULL);
00089 this->rkt_LastReservationLog = this->rkt_StartTime;
00090 this->rkt_ReservationLog = NULL;
00091
00092 memset(&this->rkt_CPUReserveSpec, 0, sizeof(this->rkt_CPUReserveSpec));
00093 this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00094 this->rkt_CPUReserve = NULL_RESERVE;
00095
00096
00097 for( lpc = 0; lpc < tp.length(); lpc++ )
00098 {
00099 if( strcasecmp(tp[lpc].name.in(), "name") == 0 )
00100 {
00101 const char *name;
00102
00103 if( this->rkt_Name != NULL )
00104 {
00105 throw Broker::DuplicateTaskParameter("name");
00106 }
00107 else if( tp[lpc].value >>= name )
00108 {
00109 if( strlen(name) >= RK_NAME_LEN )
00110 {
00111 throw Broker::InvalidTaskParameter(
00112 "'name' is too long, only "
00113 __XSTRING(RK_NAME_LEN)
00114 " characters are allowed",
00115 tp[lpc]);
00116 }
00117 else
00118 {
00119 this->rkt_Name = name;
00120 }
00121 }
00122 else
00123 {
00124 throw Broker::InvalidTaskParameter("'name' not a string",
00125 tp[lpc]);
00126 }
00127 }
00128 else if( (strcasecmp(tp[lpc].name.in(), "res_log") == 0) ||
00129 (strcasecmp(tp[lpc].name.in(), "res-log") == 0) ||
00130 (strcasecmp(tp[lpc].name.in(), "res log") == 0) )
00131 {
00132 const char *res_log;
00133
00134 if( this->rkt_ReservationLog != NULL )
00135 {
00136 throw Broker::DuplicateTaskParameter("res log");
00137 }
00138 else if( tp[lpc].value >>= res_log )
00139 {
00140 this->rkt_ReservationLog = new ofstream(res_log);
00141 (*this->rkt_ReservationLog) << setfill('0');
00142 (*this->rkt_ReservationLog)
00143 << "# start: "
00144 << (long)this->rkt_StartTime.tv_sec
00145 << "."
00146 << setw(6) << (long)this->rkt_StartTime.tv_usec
00147 << endl;
00148 }
00149 else
00150 {
00151 throw Broker::InvalidTaskParameter("'res log' not a string",
00152 tp[lpc]);
00153 }
00154 }
00155 }
00156
00157
00158 if( this->rkt_Name == NULL )
00159 {
00160 throw Broker::MissingTaskParameter("name");
00161 }
00162 }
00163
00164 RKTask::~RKTask()
00165 {
00166 if( !CORBA::is_nil(this->rkt_Manager.in()) )
00167 {
00168 this->EndCPUScheduling();
00169 }
00170 if( this->rkt_ReservationLog != NULL )
00171 {
00172 delete this->rkt_ReservationLog;
00173 }
00174 }
00175
00176 char *RKTask::Name(void)
00177 throw (CORBA::SystemException)
00178 {
00179 CORBA::String_var retval;
00180
00181 retval = this->rkt_Name;
00182 return( retval._retn() );
00183 }
00184
00185 CORBA::ULong RKTask::Period(void)
00186 throw (CORBA::SystemException)
00187 {
00188 CORBA::ULong retval;
00189
00190 retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.period);
00191 return( retval );
00192 }
00193
00194 CORBA::ULong RKTask::Deadline(void)
00195 throw (CORBA::SystemException)
00196 {
00197 CORBA::ULong retval;
00198
00199 retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.deadline);
00200 return( retval );
00201 }
00202
00203 void RKTask::SetManager(Broker::Manager_ptr manager)
00204 throw (CORBA::SystemException)
00205 {
00206 this->rkt_Manager = Broker::Manager::_duplicate(manager);
00207 }
00208
00209 void RKTask::BeginCPUScheduling(const Broker::ScheduleParameters &cs)
00210 throw (CORBA::SystemException,
00211 Broker::DuplicateScheduleParameter,
00212 Broker::InvalidScheduleParameter,
00213 Broker::MissingScheduleParameter)
00214 {
00215 CORBA::ULongLong start = 0, period = ~0, deadline = ~0;
00216 rk_reserve_mode_t rsv_mode = RSV_SOFT;
00217 unsigned int lpc;
00218 const char *str;
00219 pid_t pid = -1;
00220
00221 if( this->rkt_CPUReserve != NULL_RESERVE )
00222 {
00223 throw CORBA::BAD_INV_ORDER();
00224 }
00225
00226
00227 for( lpc = 0; lpc < cs.length(); lpc++ )
00228 {
00229 if( strcasecmp(cs[lpc].name.in(), "reserve-mode") == 0 )
00230 {
00231 const char *str;
00232
00233 if( cs[lpc].value >>= str )
00234 {
00235 if( strcasecmp(str, "soft") == 0 )
00236 {
00237 rsv_mode = RSV_SOFT;
00238 }
00239 else if( strcasecmp(str, "hard") == 0 )
00240 {
00241 rsv_mode = RSV_HARD;
00242 }
00243 else
00244 {
00245 throw Broker::InvalidScheduleParameter(
00246 "'reserve-mode' not 'hard' or 'soft'", cs[lpc]);
00247 }
00248 }
00249 else
00250 {
00251 throw Broker::InvalidScheduleParameter(
00252 "'reserve-mode' not a string", cs[lpc]);
00253 }
00254 }
00255 else if( strcasecmp(cs[lpc].name.in(), "start") == 0 )
00256 {
00257 if( ((cs[lpc].value >>= str) && string_to_microsec(&start, str)) )
00258 {
00259 }
00260 else
00261 {
00262 throw Broker::InvalidScheduleParameter("'start' is not a time",
00263 cs[lpc]);
00264 }
00265 }
00266 else if( strcasecmp(cs[lpc].name.in(), "pid") == 0 )
00267 {
00268 CORBA::Long c_pid;
00269 const char *str;
00270
00271 if( pid != -1 )
00272 {
00273 throw Broker::DuplicateScheduleParameter("pid");
00274 }
00275 else if( cs[lpc].value >>= c_pid )
00276 {
00277 pid = c_pid;
00278 }
00279 else if( (cs[lpc].value >>= str) &&
00280 (sscanf(str, "%d", &pid) == 1) )
00281 {
00282 }
00283 else
00284 {
00285 throw Broker::InvalidScheduleParameter("'pid' not a long",
00286 cs[lpc]);
00287 }
00288 if( pid < 0 )
00289 {
00290 pid = -1;
00291 throw Broker::InvalidScheduleParameter("'pid' not a long",
00292 cs[lpc]);
00293 }
00294 }
00295 else if( strcasecmp(cs[lpc].name.in(), "period") == 0 )
00296 {
00297 CORBA::ULong period_ul;
00298
00299 if( period != ~0ULL )
00300 {
00301 throw Broker::DuplicateScheduleParameter("period");
00302 }
00303 else if( cs[lpc].value >>= period_ul )
00304 {
00305 period = period_ul;
00306 }
00307 else if( (cs[lpc].value >>= str) &&
00308 string_to_microsec(&period, str) )
00309 {
00310 }
00311 else
00312 {
00313 throw Broker::InvalidScheduleParameter(
00314 "'period' is not a time",
00315 cs[lpc]);
00316 }
00317 }
00318 else if( strcasecmp(cs[lpc].name.in(), "deadline") == 0 )
00319 {
00320 CORBA::ULong deadline_ul;
00321
00322 if( deadline != ~0ULL )
00323 {
00324 throw Broker::DuplicateScheduleParameter("deadline");
00325 }
00326 else if( cs[lpc].value >>= deadline_ul )
00327 {
00328 deadline = deadline_ul;
00329 }
00330 else if( (cs[lpc].value >>= str) &&
00331 string_to_microsec(&deadline, str) )
00332 {
00333 }
00334 else
00335 {
00336 throw Broker::InvalidScheduleParameter(
00337 "'deadline' is not a time",
00338 cs[lpc]);
00339 }
00340 }
00341 }
00342
00343
00344 if( period == ~0ULL )
00345 {
00346 throw Broker::MissingScheduleParameter("period");
00347 }
00348 if( pid == -1 )
00349 {
00350 throw Broker::MissingScheduleParameter("pid");
00351 }
00352
00353
00354 if( deadline == ~0ULL )
00355 {
00356 deadline = period;
00357 }
00358
00359
00360 rktRepairResourceSets();
00361
00362
00363 if( (this->rkt_ResourceSet = rk_proc_get_rset(pid)) != NULL_RESOURCE_SET )
00364 {
00365
00366 this->rkt_OwnsResourceSet = 0;
00367 }
00368 else if( (this->rkt_ResourceSet =
00369 rk_resource_set_get_by_name(this->rkt_Name.in())) !=
00370 NULL_RESOURCE_SET )
00371 {
00372 this->rkt_OwnsResourceSet = 0;
00373 }
00374 else if( (this->rkt_ResourceSet =
00375 rk_resource_set_create(this->rkt_Name.in())) !=
00376 NULL_RESOURCE_SET )
00377 {
00378 this->rkt_OwnsResourceSet = 1;
00379 }
00380 else
00381 {
00382 cerr << strerror(errno) << ": rk_resource_set_create" << endl;
00383 throw CORBA::NO_MEMORY();
00384 }
00385
00386 rk_reserve_t old_reserve;
00387
00388
00389 if( (old_reserve = rk_resource_set_get_cpu_rsv(this->rkt_ResourceSet))
00390 != NULL_RESERVE )
00391 {
00392 if( rk_resource_set_get_num_procs(this->rkt_ResourceSet) == 0 )
00393 {
00394
00395
00396
00397
00398 if( rk_cpu_reserve_delete(this->rkt_ResourceSet) == -1 )
00399 {
00400 cerr << strerror(errno)
00401 << ": rk_cpu_reserve_delete"
00402 << endl;
00403 }
00404 }
00405 else
00406 {
00407 Broker::NamedValue nv;
00408
00409
00410 this->rkt_ResourceSet = NULL_RESOURCE_SET;
00411 nv.name = "name";
00412 nv.value <<= this->rkt_Name;
00413 throw Broker::InvalidScheduleParameter("name", nv);
00414 }
00415 }
00416 if( rk_resource_set_attach_process(this->rkt_ResourceSet, pid) == 0 )
00417 {
00418
00419
00420
00421 }
00422 else if( errno != EBUSY )
00423 {
00424
00425 rk_resource_set_destroy(this->rkt_ResourceSet);
00426 this->rkt_ResourceSet = NULL_RESOURCE_SET;
00427 throw CORBA::NO_MEMORY();
00428 }
00429 else
00430 {
00431
00432 }
00433
00434
00435 if( (this->rkt_CPUReserveSpec.compute_time.tv_sec == 0) &&
00436 (this->rkt_CPUReserveSpec.compute_time.tv_nsec == 0) )
00437 {
00438 this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00439 }
00440 this->rkt_CPUReserveSpec.period = microsec_to_timespec(period);
00441 this->rkt_CPUReserveSpec.deadline = microsec_to_timespec(deadline);
00442 this->rkt_CPUReserveSpec.reserve_type.sch_mode = rsv_mode;
00443 this->rkt_CPUReserveSpec.reserve_type.enf_mode = rsv_mode;
00444 this->rkt_CPUReserveSpec.reserve_type.rep_mode = rsv_mode;
00445 this->rkt_CPUReserveSpec.processor = RK_ANY_CPU;
00446
00447 switch( int rc = rk_cpu_reserve_create(this->rkt_ResourceSet,
00448 &this->rkt_CPUReserve,
00449 &this->rkt_CPUReserveSpec) )
00450 {
00451 case 0:
00452 break;
00453 case -1:
00454 cerr << strerror(errno) << ":rk_cpu_reserve_create" << endl;
00455 throw Broker::InvalidScheduleParameter();
00456 default:
00457 cerr << rc << endl;
00458 throw Broker::Internal("Unhandled return value at: "
00459 __FILE__
00460 ":"
00461 __STRING(__LINE__));
00462 }
00463 }
00464
00465 void RKTask::EndCPUScheduling(void)
00466 throw (CORBA::SystemException)
00467 {
00468 if( this->rkt_CPUReserve == NULL_RESERVE )
00469 {
00470 throw CORBA::BAD_INV_ORDER();
00471 }
00472
00473 if( this->rkt_ReservationLog != NULL )
00474 {
00475 struct timeval tv, st, diff;
00476
00477 timersub(&this->rkt_LastReservationLog,
00478 &this->rkt_StartTime,
00479 &diff);
00480 st.tv_sec = 0;
00481 st.tv_usec = 0;
00482 gettimeofday(&tv, NULL);
00483 timersub(&tv, &this->rkt_StartTime, &diff);
00484 (*this->rkt_ReservationLog)
00485 << (long)diff.tv_sec
00486 << "."
00487 << setw(6) << (long)diff.tv_usec
00488 << " "
00489 << (long)st.tv_sec
00490 << "."
00491 << setw(6) << (long)st.tv_usec
00492 << endl;
00493 this->rkt_LastReservationLog = tv;
00494 }
00495
00496 rk_cpu_reserve_delete(this->rkt_ResourceSet);
00497 this->rkt_CPUReserve = NULL_RESERVE;
00498 if( this->rkt_OwnsResourceSet )
00499 {
00500 rk_resource_set_destroy(this->rkt_ResourceSet);
00501 }
00502 this->rkt_ResourceSet = NULL_RESOURCE_SET;
00503 }
00504
00505 CORBA::ULong RKTask::GetComputeTime(void)
00506 throw (CORBA::SystemException)
00507 {
00508 CORBA::ULong retval;
00509
00510 retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00511 return( retval );
00512 }
00513
00514 void RKTask::SetComputeTime(CORBA::ULong usecs)
00515 throw (CORBA::SystemException)
00516 {
00517 struct timespec old_ct;
00518
00519 if( usecs == 0 )
00520 {
00521 throw CORBA::BAD_PARAM();
00522 }
00523
00524 old_ct = this->rkt_CPUReserveSpec.compute_time;
00525 this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(usecs);
00526
00527 if( this->rkt_CPUReserve != NULL_RESERVE )
00528 {
00529 switch( rk_cpu_reserve_ctl(this->rkt_ResourceSet,
00530 &this->rkt_CPUReserveSpec) )
00531 {
00532 case 0:
00533 if( this->rkt_ReservationLog != NULL )
00534 {
00535 struct timeval tv, st, diff;
00536
00537 timersub(&this->rkt_LastReservationLog,
00538 &this->rkt_StartTime,
00539 &diff);
00540 st.tv_sec = usecs / 1000000;
00541 st.tv_usec = usecs % 1000000;
00542 gettimeofday(&tv, NULL);
00543 timersub(&tv, &this->rkt_StartTime, &diff);
00544 (*this->rkt_ReservationLog)
00545 << (long)diff.tv_sec
00546 << "."
00547 << setw(6) << (long)diff.tv_usec
00548 << " "
00549 << (long)st.tv_sec
00550 << "."
00551 << setw(6) << (long)st.tv_usec
00552 << endl;
00553 this->rkt_LastReservationLog = tv;
00554 }
00555 break;
00556 case -1:
00557 switch( errno )
00558 {
00559 case EINVAL:
00560 ensure(0);
00561 break;
00562 case ENODEV:
00563 ensure(0);
00564 break;
00565 case ENOSPC:
00566 cerr << "** SetComputeTime failed! "
00567 << usecs
00568 << endl;
00569 break;
00570 case EFAULT:
00571 ensure(0);
00572 break;
00573 case EACCES:
00574 cerr << "** No permission to change compute time? "
00575 << usecs
00576 << endl;
00577 break;
00578 case ENOSYS:
00579 ensure(0);
00580 break;
00581 }
00582 this->rkt_CPUReserveSpec.compute_time = old_ct;
00583 throw CORBA::BAD_PARAM();
00584 }
00585 }
00586 else
00587 {
00588
00589 if( this->rkt_ReservationLog != NULL )
00590 {
00591 struct timeval tv, st, diff;
00592
00593 timersub(&this->rkt_LastReservationLog,
00594 &this->rkt_StartTime,
00595 &diff);
00596 st.tv_sec = usecs / 1000000;
00597 st.tv_usec = usecs % 1000000;
00598 gettimeofday(&tv, NULL);
00599 timersub(&tv, &this->rkt_StartTime, &diff);
00600 (*this->rkt_ReservationLog)
00601 << (long)diff.tv_sec
00602 << "."
00603 << setw(6) << (long)diff.tv_usec
00604 << " "
00605 << (long)st.tv_sec
00606 << "."
00607 << setw(6) << (long)st.tv_usec
00608 << endl;
00609 this->rkt_LastReservationLog = tv;
00610 }
00611 }
00612 }
00613
00614 void RKTask::ReportCPU(Broker::RealTimeTask_ptr rtt,
00615 CORBA::ULong status,
00616 CORBA::ULong advice)
00617 throw (CORBA::SystemException)
00618 {
00619 INSTR_rktask_change_cpu(&INSTR_rktask_change_cpu_point, {
00620 CORBA::ULong ct;
00621
00622 if( CORBA::is_nil(this->rkt_Manager.in()) )
00623 {
00624 throw CORBA::BAD_INV_ORDER();
00625 }
00626 if( CORBA::is_nil(rtt) )
00627 {
00628 throw CORBA::BAD_PARAM();
00629 }
00630 if( advice == 0 )
00631 {
00632 throw CORBA::BAD_PARAM();
00633 }
00634
00635 ct = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00636 this->rkt_Manager->ChangeTaskCPU(rtt, ct, status, advice);
00637 });
00638 }