1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 /* 19 * FUNCTIONS: Scheduler Test Suite 20 */ 21 22 /*---------------------------------------------------------------------+ 23 | sched_tc6 | 24 | ==================================================================== | 25 | | 26 | Description: Creates short-term disk I/O bound process | 27 | | 28 | Creates a situation where a real time process is | 29 | waiting on a file lock owned by a user process. The | 30 | scheduler should elevate the user process priority to | 31 | the same level as the real time process to avoid | 32 | deadlock situations and to decrease wait time | 33 | required of the real time process. | 34 | | 35 | Algorithm: o Set process priority | 36 | o Continuously multiply matrices together until | 37 | interrupted. | 38 | | 39 | To compile: cc -o sched_tc6 sched_tc6.c -L. -lpsc | 40 | | 41 | Usage: sched_tc6 [-t priority_type] [-p priority] | 42 | [-l log] [-f] [-v] [-d] | 43 | | 44 | Last update: Ver. 1.3, 4/10/94 23:05:03 | 45 | | 46 | Change Activity | 47 | | 48 | Version Date Name Reason | 49 | 0.1 050689 CTU Initial version | 50 | 0.2 010402 Manoj Iyer Ported to Linux | 51 | | 52 +---------------------------------------------------------------------*/ 53 54 #include <fcntl.h> 55 #include <stdlib.h> 56 #include <sys/time.h> 57 #include <time.h> 58 #include <sys/resource.h> 59 #include "sched.h" 60 61 /* 62 * Defines: 63 * 64 * USAGE: usage statement 65 * 66 * DEFAULT_PRIORITY_TYPE: default priority 67 * 68 * BLOCK_SIZE: block size (in bytes) for raw I/O 69 * 70 * TIMES: number of times to read raw I/O device (~25MB) 71 * 72 */ 73 #define DEFAULT_PRIORITY_TYPE "variable" 74 #define DEFAULT_LOGFILE "sched_tc6.log" 75 #define BLOCK_SIZE 512 76 #define TIMES 10 77 #define MAX_TRIES 20 78 #define NAPTIME 1 79 #define REAL_TIME "1" 80 #define NO_FORK "0" 81 #define USAGE "Usage: %s [-l log] [-t type] [-p priority] [-f] [-v] [-d]\n" \ 82 " -l log log file \n" \ 83 " -t type priority type 'variable' or 'fixed' \n" \ 84 " -p priority priority value \n" \ 85 " -f fork child \n" \ 86 " -v verbose \n" \ 87 " -d enable debugging messages \n" 88 89 /* 90 * Function prototypes: 91 * 92 * process_file: reads data file 93 * 94 * parse_args: parse command line arguments 95 */ 96 void parse_args(int, char **); 97 int fork_realtime(char **); 98 int read_file(int, char *); 99 int lock_file(int, short, char *); 100 int unlock_file(int, char *); 101 int lock_error(int, char *); 102 103 /* 104 * Global variables: 105 * 106 * verbose: enable normal messages 107 * 108 * debug: enable debugging messages 109 * 110 * priority: process type (fixed priority, variable priority) 111 */ 112 int verbose = 0; 113 int debug = 0; 114 int fork_flag = 0; 115 int priority = DEFAULT_PRIORITY; 116 char *logfile = DEFAULT_LOGFILE; 117 char *priority_type = DEFAULT_PRIORITY_TYPE; 118 struct flock flock_struct; 119 struct flock *flock_ptr = &flock_struct; 120 121 int open_file(char *, int); 122 123 /*---------------------------------------------------------------------+ 124 | main | 125 | ==================================================================== | 126 | | 127 | Function: ... | 128 | | 129 +---------------------------------------------------------------------*/ 130 int main(int argc, char **argv) 131 { 132 char *filename = NULL; 133 FILE *statfile; 134 pid_t pid = 0; 135 int fd; 136 int rc; 137 clock_t start_time; /* start & stop times */ 138 clock_t stop_time; 139 float elapsed_time; 140 #ifdef __linux__ 141 time_t timer_info; 142 #else 143 struct tms timer_info; /* time accounting info */ 144 #endif 145 146 if ((filename = getenv("KERNEL")) == NULL) { 147 errno = ENODATA; 148 sys_error("environment variable KERNEL not set", __FILE__, 149 __LINE__); 150 } 151 152 /* Process command line arguments... */ 153 parse_args(argc, argv); 154 if (verbose) 155 printf("%s: Scheduler TestSuite program\n\n", *argv); 156 if (debug) { 157 printf("\tpriority type: %s\n", priority_type); 158 printf("\tpriority: %d\n", priority); 159 printf("\tlogfile: %s\n", logfile); 160 } 161 162 /* Adjust the priority of this process if the real time flag is set */ 163 if (!strcmp(priority_type, "fixed")) { 164 #ifndef __linux__ 165 if (setpri(0, DEFAULT_PRIORITY) < 0) 166 sys_error("setpri failed", __FILE__, __LINE__); 167 #else 168 if (setpriority(PRIO_PROCESS, 0, 0) < 0) 169 sys_error("setpri failed", __FILE__, __LINE__); 170 #endif 171 } else { 172 if (nice((priority - 50) - (nice(0) + 20)) < 0 && errno != 0) 173 sys_error("nice failed", __FILE__, __LINE__); 174 } 175 176 /* Read from raw I/O device and record elapsed time... */ 177 start_time = time(&timer_info); 178 179 /* Open and lock file file... */ 180 fd = open_file(filename, O_RDWR); 181 if (!lock_file(fd, F_WRLCK, filename)) /* set exclusive lock */ 182 error("lock_file failed", __FILE__, __LINE__); 183 184 /* If fork flag set, fork a real process */ 185 if (fork_flag) 186 pid = fork_realtime(argv); 187 188 /* Read file */ 189 if (debug) { 190 printf("\tprocess id %d successfully locked %s\n", 191 getpid(), filename); 192 printf("\tprocess id %d starting to read %s\n", 193 getpid(), filename); 194 } 195 196 if (!read_file(fd, filename)) 197 error("read_file failed", __FILE__, __LINE__); 198 199 /* Stop the timer and calculate the elapsed time */ 200 stop_time = time(&timer_info); 201 elapsed_time = (float)(stop_time - start_time) / 100.0; 202 203 /* Write the elapsed time to the temporary file... */ 204 if ((statfile = fopen(logfile, "w")) == NULL) 205 sys_error("fopen failed", __FILE__, __LINE__); 206 207 fprintf(statfile, "%f\n", elapsed_time); 208 if (debug) 209 printf("\n\telapsed time: %f\n", elapsed_time); 210 211 if (fclose(statfile) < 0) 212 sys_error("fclose failed", __FILE__, __LINE__); 213 214 /* Unlock file at latest possible time to prevent real time child from 215 * writing throughput results before user process parent */ 216 unlock_file(fd, filename); 217 close(fd); 218 219 if (debug) 220 printf("\tprocess id %d completed read and unlocked file\n", 221 getpid()); 222 223 /* The parent waits for child process to complete before exiting 224 * so the driver will not read the throughput results file before 225 * child writes to the file */ 226 if (pid != 0) { /* if parent process ... *//* wait for child process */ 227 if (debug) 228 printf 229 ("parent waiting on child process %d to complete\n", 230 pid); 231 232 while ((rc = wait(NULL)) != pid) 233 if (rc == -1) 234 sys_error("wait failed", __FILE__, __LINE__); 235 /* 236 DARA: which one to use 237 1st -- hangs 238 2nd -- ERROR message 239 240 while (wait((void *) 0) != pid) ; 241 while ((rc=wait ((void *) 0)) != pid) 242 if (rc == -1) 243 sys_error ("wait failed", __FILE__, __LINE__); 244 */ 245 } 246 247 /* Exit with success! */ 248 if (verbose) 249 printf("\nsuccessful!\n"); 250 return (0); 251 } 252 253 /*---------------------------------------------------------------------+ 254 | open_file () | 255 | ==================================================================== | 256 | | 257 | Function: ... | 258 | | 259 +---------------------------------------------------------------------*/ 260 int open_file(char *file, int open_mode) 261 { 262 int file_desc; 263 264 if ((file_desc = open(file, open_mode)) < 0) 265 sys_error("open failed", __FILE__, __LINE__); 266 return (file_desc); 267 } 268 269 /*---------------------------------------------------------------------+ 270 | fork_realtime () | 271 | ==================================================================== | 272 | | 273 | Function: ... | 274 | | 275 +---------------------------------------------------------------------*/ 276 int fork_realtime(char **args) 277 { 278 int pid; 279 char *results_file = args[2]; 280 char *priority = args[3]; 281 282 /* fork process then determine if process is parent or child */ 283 pid = fork(); 284 switch (pid) { 285 /* fork failed */ 286 case -1: 287 sys_error("fork failed", __FILE__, __LINE__); 288 289 /* child process */ 290 case 0: 291 if (execl(*args, *args, REAL_TIME, results_file, priority, 292 NO_FORK, NULL) < 0) 293 sys_error("execl failed", __FILE__, __LINE__); 294 295 /* parent process */ 296 default: 297 #ifdef DEBUG 298 printf("\tparent process id = %d\n", getpid()); 299 printf("\tchild process id = %d\n\n", pid); 300 #endif 301 302 break; 303 } 304 return (pid); 305 } 306 307 /*---------------------------------------------------------------------+ 308 | read_file () | 309 | ==================================================================== | 310 | | 311 | Function: ... | 312 | | 313 +---------------------------------------------------------------------*/ 314 int read_file(int fd, char *filename) 315 { 316 int bytes_read; 317 int loop_count; 318 long total_bytes; 319 off_t lseek(); 320 off_t file_offset = 0; 321 int whence = 0; 322 323 char buf[BLOCK_SIZE]; 324 325 /* read file for "TIMES" number of times */ 326 total_bytes = 0; 327 if (debug) 328 printf("\n"); 329 for (loop_count = 1; loop_count <= TIMES; loop_count++) { 330 while ((bytes_read = read(fd, buf, BLOCK_SIZE)) > 0) { 331 if (bytes_read == -1) { 332 sys_error("read failed", __FILE__, __LINE__); 333 } else 334 total_bytes = total_bytes + bytes_read; 335 } 336 if (lseek(fd, file_offset, whence) < 0) 337 sys_error("lseek failed", __FILE__, __LINE__); 338 339 if (debug) { 340 printf("\r\ttotal bytes read = %ld", total_bytes); 341 fflush(stdout); 342 } 343 total_bytes = 0; 344 } 345 if (debug) 346 printf("\n"); 347 return 1; 348 } 349 350 /*---------------------------------------------------------------------+ 351 | lock_file () | 352 | ==================================================================== | 353 | | 354 | Function: ... | 355 | | 356 +---------------------------------------------------------------------*/ 357 int lock_file(int fd, short lock_type, char *file) 358 { 359 int lock_attempt = 1; 360 int lock_mode; 361 362 #ifdef DEBUG 363 lock_mode = F_SETLK; /* return if lock fails */ 364 #else 365 lock_mode = F_SETLKW; /* set lock and use system wait */ 366 #endif 367 368 /* file segment locking set data type flock - information 369 * passed to system by user -- 370 * l_whence: starting point of relative offset of file 371 * l_start: defines relative offset in bytes from l_whence 372 * l_len: number of consecutive bytes to be locked 373 */ 374 flock_ptr->l_whence = 0; 375 flock_ptr->l_start = 0; 376 flock_ptr->l_len = 0; 377 flock_ptr->l_type = lock_type; 378 379 while (fcntl(fd, lock_mode, flock_ptr) == -1) { 380 if (lock_error(fd, file)) { 381 sleep(NAPTIME); 382 if (++lock_attempt > MAX_TRIES) { 383 printf 384 ("ERROR: max lock attempts of %d reached\n", 385 MAX_TRIES); 386 return (0); 387 } 388 } else 389 return (0); 390 } 391 return (1); 392 } 393 394 /*---------------------------------------------------------------------+ 395 | unlock_file () | 396 | ==================================================================== | 397 | | 398 | Function: ... | 399 | | 400 +---------------------------------------------------------------------*/ 401 int unlock_file(int fd, char *file) 402 { 403 flock_ptr->l_type = F_UNLCK; 404 405 if (fcntl(fd, F_SETLK, flock_ptr) < 0) 406 sys_error("fcntl failed", __FILE__, __LINE__); 407 408 return 1; 409 } 410 411 /*---------------------------------------------------------------------+ 412 | main | 413 | ==================================================================== | 414 | | 415 | Function: ... | 416 | | 417 +---------------------------------------------------------------------*/ 418 int lock_error(int fd, char *file) 419 { 420 int ret = 1; 421 422 printf("ERROR: lock failed: %s\n", file); 423 switch (errno) { 424 case EACCES: /* access not allowed */ 425 fcntl(fd, F_GETLK, flock_ptr); 426 #ifndef __linux__ 427 printf("ERROR: lock exists - nid: %lX pid: %ld\n", 428 flock_ptr->l_sysid, flock_ptr->l_pid); 429 #else 430 printf("ERROR: lock exists - nid:\n"); 431 #endif 432 break; 433 434 /* 435 * This was a DS error code, and DS does not exist V3.1 436 */ 437 #ifndef __linux__ 438 case EDIST: /* DS file server blocking requests */ 439 printf("ERROR: errno == EDIST\n"); 440 printf("The server has blocked new inbound requests\n"); 441 printf("or outbound requests are currently blocked.\n"); 442 break; 443 #endif 444 445 case EAGAIN: /* server too busy */ 446 printf("ERROR: Server too busy to accept the request\n"); 447 break; 448 449 case EDEADLK: /* only when F_SETLKW cmd is used */ 450 printf("ERROR: Putting the calling process to sleep\n"); 451 printf("would cause a dead lock\n"); 452 ret = 0; 453 break; 454 455 case ENOLCK: /* out of locks */ 456 printf("ERROR: No more file locks available\n"); 457 ret = 0; 458 break; 459 460 case ENOMEM: /* out of memory */ 461 printf("ERROR: The server or client does not have enough\n"); 462 printf("memory to service the request.\n"); 463 ret = 0; 464 break; 465 466 default: /* miscellaneous errors */ 467 printf("ERROR: Unknown lock error\n"); 468 perror("reason"); 469 ret = 0; 470 break; 471 } 472 473 printf("errno = %d\n", errno); /* log the errno value */ 474 sleep(10); 475 476 return (ret); 477 } 478 479 /*---------------------------------------------------------------------+ 480 | parse_args () | 481 | ==================================================================== | 482 | | 483 | Function: Parse the command line arguments & initialize global | 484 | variables. | 485 | | 486 | Updates: (command line options) | 487 | | 488 | [-t] type: priority type "fixed" or "variable" | 489 | [-p] priority: priority value | 490 | [-l] logfile: log file name | 491 | [-v] verbose | 492 | [-d] enable debugging messages | 493 | | 494 +---------------------------------------------------------------------*/ 495 void parse_args(int argc, char **argv) 496 { 497 int opt; 498 int lflg = 0, pflg = 0, tflg = 0; 499 int errflag = 0; 500 char *program_name = *argv; 501 extern char *optarg; /* Command line option */ 502 503 /* 504 * Parse command line options. 505 */ 506 while ((opt = getopt(argc, argv, "fl:t:p:vd")) != EOF) { 507 switch (opt) { 508 case 'f': /* fork flag */ 509 fork_flag++; 510 break; 511 case 'l': /* log file */ 512 lflg++; 513 logfile = optarg; 514 break; 515 case 't': /* process type */ 516 tflg++; 517 priority_type = optarg; 518 break; 519 case 'p': /* process priority */ 520 pflg++; 521 priority = atoi(optarg); 522 break; 523 case 'v': /* verbose */ 524 verbose++; 525 break; 526 case 'd': /* enable debugging messages */ 527 verbose++; 528 debug++; 529 break; 530 default: 531 errflag++; 532 break; 533 } 534 } 535 536 /* 537 * Check percentage and process slots... 538 */ 539 if (tflg) { 540 if (strcmp(priority_type, "fixed") && 541 strcmp(priority_type, "variable")) { 542 errflag++; 543 fprintf(stderr, "Error: priority type must be: " 544 "\'fixed\' or \'variable\'\n"); 545 } 546 } 547 if (pflg) { 548 if (priority < 50 || priority > 100) { 549 errflag++; 550 fprintf(stderr, "Error: priority range [50..100]\n"); 551 } 552 } 553 if (errflag) { 554 fprintf(stderr, USAGE, program_name); 555 exit(2); 556 } 557 } 558