#include #include #include #include #include #include #include #include #include #include "litmus.h" #include "common.h" extern int main_job(void); static char* progname; static void usage(char *error) { fprintf(stderr, "Error: %s\n", error); fprintf(stderr, "Usage:\n" " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n" " rt_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n" " rt_spin -l\n" "\n" "COMMON-OPTS = [-w] [-s SCALE]\n" " [-p PARTITION/CLUSTER [-z CLUSTER SIZE]] [-c CLASS] [-m CRITICALITY LEVEL]\n" " [-X LOCKING-PROTOCOL] [-L CRITICAL SECTION LENGTH] [-Q RESOURCE-ID]\n" "\n" "WCET and PERIOD are milliseconds, DURATION is seconds.\n" "CRITICAL SECTION LENGTH is in milliseconds.\n"); exit(EXIT_FAILURE); } static int job(double exec_time, double program_end, int lock_od, double cs_length) { if (wctime() > program_end) return 0; else { main_job(); sleep_next_period(); return 1; } } #define OPTSTR "p:c:wves:q:X:L:Q:vh:m:i:b:" int main(int argc, char** argv) { int ret; lt_t wcet; lt_t period; lt_t hyperperiod; lt_t budget; double wcet_ms, period_ms, hyperperiod_ms, budget_ms; unsigned int priority = LITMUS_NO_PRIORITY; int migrate = 0; int cluster = 0; int opt; int wait = 0; int want_enforcement = 0; double duration = 0, start = 0; double scale = 1.0; task_class_t class = RT_CLASS_HARD; struct rt_task param; struct mc2_task mc2_param; struct reservation_config config; int res_type = PERIODIC_POLLING; int verbose = 0; unsigned int job_no; /* locking */ int lock_od = -1; int resource_id = 0; const char *lock_namespace = "./rtspin-locks"; int protocol = -1; double cs_length = 1; /* millisecond */ progname = argv[0]; /* default for reservation */ config.id = 0; config.priority = LITMUS_NO_PRIORITY; /* use EDF by default */ config.cpu = -1; mc2_param.crit = CRIT_LEVEL_C; hyperperiod_ms = 1000; budget_ms = 10; while ((opt = getopt(argc, argv, OPTSTR)) != -1) { switch (opt) { case 'w': wait = 1; break; case 'p': cluster = atoi(optarg); migrate = 1; config.cpu = cluster; break; case 'q': priority = atoi(optarg); if (!litmus_is_valid_fixed_prio(priority)) usage("Invalid priority."); break; case 'c': class = str2class(optarg); if (class == -1) usage("Unknown task class."); break; case 'e': want_enforcement = 1; break; case 's': scale = atof(optarg); break; case 'X': protocol = lock_protocol_for_name(optarg); if (protocol < 0) usage("Unknown locking protocol specified."); break; case 'L': cs_length = atof(optarg); if (cs_length <= 0) usage("Invalid critical section length."); break; case 'Q': resource_id = atoi(optarg); if (resource_id <= 0 && strcmp(optarg, "0")) usage("Invalid resource ID."); break; case 'v': verbose = 1; break; case 'm': mc2_param.crit = atoi(optarg); if (mc2_param.crit < CRIT_LEVEL_A || mc2_param.crit == NUM_CRIT_LEVELS) { usage("Invalid criticality level."); } res_type = PERIODIC_POLLING; break; case 'h': hyperperiod_ms = atof(optarg); break; case 'b': budget_ms = atof(optarg); break; case 'i': config.priority = atoi(optarg); break; case ':': usage("Argument missing."); break; case '?': default: usage("Bad argument."); break; } } if (mc2_param.crit > CRIT_LEVEL_A && config.priority != LITMUS_NO_PRIORITY) usage("Bad criticailty level or priority"); if (argc - optind < 3) usage("Arguments missing."); wcet_ms = atof(argv[optind + 0]); period_ms = atof(argv[optind + 1]); wcet = ms2ns(wcet_ms); period = ms2ns(period_ms); budget = ms2ns(budget_ms); hyperperiod = ms2ns(hyperperiod_ms); if (wcet <= 0) usage("The worst-case execution time must be a " "positive number."); if (period <= 0) usage("The period must be a positive number."); if (wcet > period) { usage("The worst-case execution time must not " "exceed the period."); } duration = atof(argv[optind + 2]); if (migrate) { ret = be_migrate_to_domain(cluster); if (ret < 0) bail_out("could not migrate to target partition or cluster."); } /* reservation config */ config.id = gettid(); if (hyperperiod%period != 0 ) { ;//bail_out("hyperperiod must be multiple of period"); } config.polling_params.budget = budget; config.polling_params.period = period; config.polling_params.offset = 0; config.polling_params.relative_deadline = 0; if (config.polling_params.budget > config.polling_params.period) { usage("The budget must not exceed the period."); } /* create a reservation */ ret = reservation_create(res_type, &config); if (ret < 0) { bail_out("failed to create reservation."); } init_rt_task_param(¶m); param.exec_cost = wcet; param.period = period; param.priority = priority; param.cls = class; param.release_policy = TASK_PERIODIC; param.budget_policy = (want_enforcement) ? PRECISE_ENFORCEMENT : NO_ENFORCEMENT; if (migrate) { param.cpu = gettid(); } ret = set_rt_task_param(gettid(), ¶m); if (ret < 0) bail_out("could not setup rt task params"); mc2_param.res_id = gettid(); ret = set_mc2_task_param(gettid(), &mc2_param); //printf("SET_MC2_TASK\n"); if (ret < 0) bail_out("could not setup mc2 task params"); init_litmus(); //printf("CALL\n"); //set_page_color(config.cpu); //printf("CALL\n"); //printf("INIT_LITMUS\n"); start = wctime(); ret = task_mode(LITMUS_RT_TASK); //printf("TASK_MODE\n"); if (ret != 0) bail_out("could not become RT task"); if (protocol >= 0) { lock_od = litmus_open_lock(protocol, resource_id, lock_namespace, &cluster); if (lock_od < 0) { perror("litmus_open_lock"); usage("Could not open lock."); } } if (wait) { //printf("BEFORE WAIT\n"); ret = wait_for_ts_release(); if (ret != 0) bail_out("wait_for_ts_release()"); start = wctime(); } do { if (verbose) { get_job_no(&job_no); printf("rtspin/%d:%u @ %.4fms\n", gettid(), job_no, (wctime() - start) * 1000); } } while (job(wcet_ms * 0.001 * scale, start + duration, lock_od, cs_length * 0.001)); printf("BEFORE BACK_TASK\n"); ret = task_mode(BACKGROUND_TASK); if (ret != 0) bail_out("could not become regular task (huh?)"); reservation_destroy(gettid(), config.cpu); return 0; }