1 /* -*-C-*- 2 ***************************************************************************** 3 * 4 * File: $RCSFile: process_table.c$ 5 * Version: $Id: process_table.c,v 1.32 2004/01/16 06:49:16 jnoll Exp $ ($Name: $) 6 * Description: process table manipulation and i/o. 7 * Author: John Noll, Santa Clara University 8 * Created: Sun Jun 29 13:41:31 2003 9 * Modified: Thu Dec 4 11:48:43 2003 (John Noll, SCU) jnoll@carbon.cudenver.edu 10 * Language: C 11 * Package: N/A 12 * Status: $State: Exp $ 13 * 14 * (c) Copyright 2003, Santa Clara University, all rights reserved. 15 * 16 ***************************************************************************** 17 */ 18 #include 19 #include 20 #include 21 #include 22 #include 23 #include 24 #include 25 #include 26 #include 27 #include 28 #include "graph.h" 29 #include "process_table.h" 30 #include "graph_engine.h" 31 32 33 /* Globals. */ 34 peos_context_t process_table[PEOS_MAX_PID+1]; 35 int cur_pid = -1; /* Initially, start below proc table. */ 36 37 38 /* 39 * These functions allow manipulation of processes without access to 40 * process table. 41 */ 42 43 44 /* This function tries to get a lock for the file descriptor */ 45 46 int get_lock(int fd) 47 { 48 49 struct flock lck; 50 int num_attempts = 0; 51 52 /* initialize the lock struct for a write lock */ 53 lck.l_type = F_WRLCK; /* get a write exclusive lock */ 54 lck.l_whence = 0; 55 lck.l_start = 0; 56 lck.l_len = 0; /* lock the whole file address space */ 57 58 while (fcntl(fd, F_SETLK, &lck) < 0) { 59 if ((errno == EAGAIN) || (errno == EACCES)) { 60 if(++num_attempts <= MAX_LOCK_ATTEMPTS) { 61 fprintf(stderr, "Attempting Process File Lock ...\n"); 62 sleep(2); 63 continue; 64 } 65 66 fprintf(stderr, "File Lock Error: File Busy \n Error Msg : %s\n", strerror(errno)); 67 return -1; 68 } 69 fprintf(stderr, "File Lock Error: Unknown Error\n"); 70 fprintf(stderr, "System Error Message: %s\n", strerror(errno)); 71 return -1; 72 } 73 74 return 1; 75 } 76 77 78 int release_lock(int fd) 79 { 80 81 struct flock lck; 82 83 /* initialize the lock struct for a write lock */ 84 lck.l_type = F_UNLCK; /* get a write exclusive lock */ 85 lck.l_whence = 0; 86 lck.l_start = 0L; 87 lck.l_len = 0L; /* lock the whole file address space */ 88 89 if(fcntl(fd, F_SETLK, &lck) < 0) 90 return -1; 91 else 92 return 1; 93 } 94 95 96 97 int peos_get_pid(peos_context_t *context) 98 { 99 int pid = context- process_table; 100 return pid >=0 && pid <= PEOS_MAX_PID ? pid : -1; 101 } 102 103 peos_context_t *peos_get_context(int pid) 104 { 105 if (pid < 0 || pid > PEOS_MAX_PID) { 106 return NULL; 107 } 108 109 return &(process_table[pid]); 110 } 111 112 char *get_script(int pid, char *act_name) 113 { 114 peos_context_t *context = peos_get_context(pid); 115 116 if (context != NULL) { 117 return get_script_graph(context -> process_graph, act_name); 118 } 119 else { 120 fprintf(stderr,"\n get_script error : context not found\n"); 121 return NULL; 122 } 123 } 124 125 126 int peos_set_resource_value(int pid, char *resource_name, char *resource_value) 127 { 128 int i; 129 peos_context_t *context = peos_get_context(pid); 130 peos_resource_t *resources = context -> resources; 131 int num_resources = context -> num_resources; 132 133 for(i = 0; i < num_resources; i++) { 134 if(strcmp(resources[i].name,resource_name) == 0) { 135 strcpy(resources[i].value,resource_value); 136 return 1; 137 } 138 } 139 140 return -1; 141 } 142 143 144 145 /* XXX remove this - it's just as easy to use the graph directly. */ 146 int make_node_lists(Graph g, peos_action_t **actions, int *num_actions, peos_other_node_t **other_nodes, int *num_other_nodes) 147 { 148 Node n; 149 int num_act = 0; 150 int num_nodes = 0; 151 int asize = INST_ARRAY_INCR; 152 int osize = INST_ARRAY_INCR; 153 peos_action_t *act_array = (peos_action_t *) calloc(asize, sizeof(peos_action_t)); 154 155 peos_other_node_t *node_array = (peos_other_node_t *) calloc(osize, sizeof(peos_other_node_t)); 156 157 if (g != NULL) { 158 for(n = g -> source;n != NULL; n = n -> next) { 159 if (n -> type == ACTION) { 160 if(num_act >= asize) { 161 asize = asize + INST_ARRAY_INCR; 162 if ((act_array = realloc(act_array,asize*sizeof(peos_action_t))) == NULL) { 163 fprintf(stderr, "Too Many Actions\n"); 164 free(act_array); 165 return -1; 166 } 167 } 168 strcpy(act_array[num_act].name, n -> name); 169 act_array[num_act].state = STATE(n); 170 act_array[num_act].requires_state = REQUIRES_STATE(n); 171 act_array[num_act].provides_state = PROVIDES_STATE(n); 172 act_array[num_act].script = n -> script; 173 num_act ++; 174 } 175 else { 176 if((n->type == SELECTION) || (n->type == BRANCH)) { 177 if(num_nodes >= osize) { 178 osize = osize + INST_ARRAY_INCR; 179 if((node_array = realloc(node_array,osize*sizeof(peos_other_node_t))) == NULL) { 180 fprintf(stderr,"Too many nodes\n"); 181 free(node_array); 182 return -1; 183 } 184 } 185 strcpy(node_array[num_nodes].name, n -> name); 186 node_array[num_nodes].state = STATE(n); 187 num_nodes ++; 188 } 189 } 190 } 191 *actions = act_array; 192 *num_actions = num_act; 193 *other_nodes = node_array; 194 *num_other_nodes = num_nodes; 195 return 1; 196 } 197 else { 198 free(act_array); 199 free(node_array); 200 return -1; 201 } 202 } 203 204 205 /* 206 * Set state of nodes in g from state info in actions and other nodes. 207 * XXX collapse these two lists into one; there's no need to distinguish. 208 */ 209 int annotate_graph(Graph g, peos_action_t *actions, int num_actions, peos_other_node_t *other_nodes, int num_other_nodes) 210 { 211 int i; 212 Node node; 213 214 for(node = g -> source; node != NULL; node = node -> next) { 215 if (node -> type == ACTION) { 216 STATE(node) = get_act_state(node -> name,actions,num_actions); 217 REQUIRES_STATE(node) = get_act_requires_state(node -> name, actions, num_actions); 218 PROVIDES_STATE(node) = get_act_provides_state(node -> name, actions, num_actions); 219 } 220 else { 221 if((node->type == SELECTION) || (node->type == BRANCH)) { 222 for(i=0;i < num_other_nodes; i++) { 223 if (strcmp(node->name,other_nodes[i].name)==0) { 224 STATE(node) = other_nodes[i].state; 225 STATE(node->matching) = other_nodes[i].state; 226 } 227 } 228 } 229 } 230 } 231 232 return 1; 233 } 234 235 int 236 load_context(FILE *in, peos_context_t *context) 237 { 238 int i; 239 int num_actions, num_other_nodes; 240 241 peos_action_t *actions; 242 243 peos_other_node_t *other_nodes; 244 245 if (fscanf(in, "pid: %d\n", &context->pid) != 1) { 246 return 0; 247 } 248 if (fscanf(in, "model: %s\n", context->model) != 1) { 249 return 0; 250 } 251 if (strcmp(context->model, "none") == 0) { 252 context->model[0] = '\0'; 253 context->process_graph = NULL; 254 } 255 256 if (fscanf(in, "status: %d\n", (int *)&context->status) != 1) return 0; 257 258 if (context->status != PEOS_NONE && context->model[0]) { 259 if ((context->process_graph = makegraph(context->model)) == NULL) { 260 return 0; 261 } else { 262 initialize_graph(context->process_graph); 263 } 264 } 265 266 if (fscanf(in, "actions: ") < 0) return 0; 267 268 if (fscanf(in, "%d ", &num_actions) != 1) return 0; 269 actions = (peos_action_t *) calloc(num_actions, sizeof(peos_action_t)); 270 271 for (i = 0; i < num_actions; i++) { 272 if (fscanf(in, "%s %d %d %d", actions[i].name,(int *)&actions[i].state, (int *)&actions[i].requires_state, (int *)&actions[i].provides_state) != 4) { 273 free(actions); 274 return 0; 275 } 276 actions[i].pid = context->pid; 277 } 278 279 fscanf(in, "\n"); 280 281 if (fscanf(in, "other_nodes: ") < 0) return 0; 282 283 if (fscanf(in, "%d ", &num_other_nodes) != 1) return 0; 284 other_nodes = (peos_other_node_t *) 285 calloc(num_other_nodes, sizeof(peos_other_node_t)); 286 287 for (i = 0; i < num_other_nodes; i++) { 288 if (fscanf(in, "%s %d", other_nodes[i].name,(int *)&other_nodes[i].state) != 2) { 289 free(other_nodes); 290 return 0; 291 } 292 other_nodes[i].pid = context->pid; 293 } 294 295 296 fscanf(in, "\n"); 297 298 if (fscanf(in, "resources: ") < 0) return 0; 299 300 if (fscanf(in, "%d ", &context->num_resources) != 1) return 0; 301 302 303 context->resources = (peos_resource_t *) calloc(context->num_resources,sizeof(peos_resource_t)); 304 305 for (i = 0; i < context->num_resources; i++) { 306 if (fscanf(in, "%s %s", context->resources[i].name,context->resources[i].value) != 2) { 307 free(context->resources); 308 return 0; 309 } 310 context->resources[i].pid = context->pid; 311 } 312 313 314 if (fscanf(in, "\n \n") < 0) return 0; 315 316 if (context->process_graph) { 317 if (annotate_graph(context->process_graph, actions, num_actions, 318 other_nodes, num_other_nodes) < 0) { 319 return 0; 320 } 321 } 322 323 if (num_actions) free(actions); 324 if (num_other_nodes) free(other_nodes); 325 return 1; 326 } 327 328 int load_process_table() 329 { 330 return load_proc_table("proc_table.dat"); 331 } 332 333 int save_process_table() 334 { 335 return save_proc_table("proc_table.dat"); 336 } 337 338 int load_proc_table(char *file) 339 { 340 int i, status = -1; 341 FILE *in; 342 343 int num_proc = 0; 344 345 int fd; 346 347 fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 348 if (fd < 0) { 349 fprintf(stderr, "Cannot Get Process Table File Descriptor\n"); 350 exit(EXIT_FAILURE); 351 } 352 353 if(get_lock(fd) < 0) { 354 fprintf(stderr, "Cannot Obtain Process Table File Lock\n"); 355 exit(EXIT_FAILURE); 356 } 357 358 in = fdopen(fd, "r+"); 359 360 for (i = 0; i <= PEOS_MAX_PID; i++) { 361 process_table[i].status = PEOS_NONE; 362 } 363 if (in) { 364 status = 0; 365 while (load_context(in, &process_table[num_proc])) 366 num_proc++; 367 /* fclose(in); */ 368 /* XXX This is an issue here. If I close the file stream or the file descriptor, I loose the lock on the file. So right now this will result in some open descriptors. Potential solution is to use a global descriptor, which can be closed from save_proc_table */ 369 } 370 else { 371 fprintf(stderr, "Error in getting file pointer for load process table"); 372 release_lock(fd); 373 close(fd); 374 } 375 return status; 376 } 377 378 379 int save_context(int pid, peos_context_t *context, FILE *out) 380 { 381 int i; 382 int num_actions = 0; 383 int num_other_nodes = 0; 384 385 peos_action_t *actions; 386 peos_other_node_t *other_nodes; 387 388 make_node_lists(context->process_graph,&actions,&num_actions,&other_nodes,&num_other_nodes); 389 390 391 fprintf(out, "pid: %d\n", pid); 392 fprintf(out, "model: %s\n", context->model[0] ? context->model : "none"); 393 fprintf(out, "status: %d\n", context->status); 394 fprintf(out, "actions: "); 395 fprintf(out, "%d ", num_actions); 396 for (i = 0; i < num_actions; i++) { 397 fprintf(out, " %s %d %d %d", actions[i].name, actions[i].state, actions[i].requires_state, actions[i].provides_state); 398 } 399 400 fprintf(out, "\nother_nodes: "); 401 fprintf(out, "%d ", num_other_nodes); 402 for (i = 0; i < num_other_nodes; i++) { 403 fprintf(out, " %s %d", other_nodes[i].name, other_nodes[i].state); 404 } 405 406 fprintf(out, "\nresources: "); 407 fprintf(out, "%d ", context->num_resources); 408 for (i = 0; i < context->num_resources; i++) { 409 fprintf(out, " %s %s", context->resources[i].name, context->resources[i].value); 410 } 411 412 fprintf(out, "\n \n"); 413 return 1; 414 } 415 416 int 417 save_proc_table(char *file) 418 { 419 int i; 420 FILE *out; 421 422 int fd; 423 424 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 425 426 if (fd < 0) { 427 fprintf(stderr, "Cannot Get File Descriptor\n"); 428 exit(EXIT_FAILURE); 429 } 430 431 /* setting the lock again will replace the old lock we have */ 432 if(get_lock(fd) < 0) { 433 fprintf(stderr, "Cannot Obtain Process Table File Lock\n"); 434 exit(EXIT_FAILURE); 435 } 436 437 /* out = fdopen(fd, "w"); XXX Why doesn't this work ? XXX */ 438 out = fopen(file, "w"); 439 440 if (out) { 441 for (i = 0; i <= PEOS_MAX_PID; i++) { 442 save_context(i, &(process_table[i]), out); 443 } 444 release_lock(fd); 445 close(fd); 446 fclose(out); 447 } 448 else { 449 fprintf(stderr, "File Pointer Error: %s \n", strerror(errno)); 450 return -1; 451 } 452 return 0; 453 } 454 455 456 char **peos_list_instances() 457 { 458 static char *result[PEOS_MAX_PID+1]; 459 int i; 460 461 if(load_process_table() < 0) { 462 fprintf(stderr, "System Error: Cannot Load Process Table\n"); 463 exit(EXIT_FAILURE); 464 } 465 466 for (i = 0; i <= PEOS_MAX_PID; i++) { 467 result[i] = process_table[i].model; 468 } 469 result[i] = NULL; 470 471 if(save_process_table() < 0) { 472 fprintf(stderr, "System Error: Cannot Save Process Table\n"); 473 exit(EXIT_FAILURE); 474 } 475 476 return result; 477 } 478 479 int delete_entry(int pid) 480 { 481 peos_context_t *context; 482 483 if (pid >= 0 && pid <= PEOS_MAX_PID) { 484 context = &(process_table[pid]); 485 context->model[0] = '\0'; 486 context->status = PEOS_NONE; 487 GraphDestroy(context->process_graph); 488 context->process_graph = NULL; 489 context->num_resources = 0; 490 free(context->resources); 491 return 1; 492 } 493 else { 494 return 0; 495 } 496 } 497 498 peos_context_t *find_free_entry() 499 { 500 int i; 501 for (i = 0; i < PEOS_MAX_PID + 1; i++) { 502 process_status_t status = process_table[i].status; 503 if (status & (PEOS_NONE|PEOS_DONE|PEOS_ERROR)) { 504 return &(process_table[i]); 505 } 506 } 507 return NULL; 508 } 509 510 peos_action_t *peos_list_actions(int pid, int *num_actions) 511 { 512 513 int num_act, num_other_nodes, i; 514 peos_action_t *actions; 515 peos_other_node_t *other_nodes; 516 517 if(load_process_table() < 0) { 518 fprintf(stderr, "System Error: Cannot Load Process Table\n"); 519 exit(EXIT_FAILURE); 520 } 521 522 *num_actions = 0; 523 if (process_table[pid].status & (PEOS_DONE | PEOS_NONE | PEOS_ERROR)) { 524 if(save_process_table() < 0) { 525 fprintf(stderr, "System Error: Cannot Save Process Table\n"); 526 exit(EXIT_FAILURE); 527 } 528 return NULL; 529 } 530 531 if(make_node_lists(process_table[pid].process_graph,&actions,&num_act,&other_nodes,&num_other_nodes) == -1) { 532 if(save_process_table() < 0) { 533 fprintf(stderr, "System Error: Cannot Save Process Table\n"); 534 exit(EXIT_FAILURE); 535 } 536 return NULL; 537 } 538 539 for (i = 0; i < num_act; i++) { 540 actions[i].pid = pid; 541 } 542 for (i = 0; i < num_other_nodes; i++) { 543 other_nodes[i].pid = pid; 544 } 545 *num_actions = num_act; 546 547 if(save_process_table() < 0) { 548 fprintf(stderr, "System Error: Cannot Save Process Table\n"); 549 exit(EXIT_FAILURE); 550 } 551 552 return actions; 553 } 554 555 556 #ifdef UNIT_TEST 557 #include "test_process_table.c" 558 #endif