00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023
00024 #include <errno.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <signal.h>
00029 #include <unistd.h>
00030 #include <fcntl.h>
00031
00032 #include <sys/time.h>
00033 #include <sys/types.h>
00034 #include <sys/times.h>
00035 #include <sys/wait.h>
00036 #include <sys/socket.h>
00037 #include <sys/resource.h>
00038
00039 #include <netinet/in.h>
00040
00041 #include <assert_pp.h>
00042 #include <time_util.h>
00043
00044 #include "gkemu.h"
00045 #include "childProcess.h"
00046
00047 #include <rk/rk.h>
00048 #include <rk/rk_error.h>
00049
00050 #include "rk_util.h"
00051
00052
00053
00054
00055 #define SAMPLES_PER_SECOND 1
00056
00057
00058
00059
00060 #define MAX_CLIENTS 8
00061
00062
00063
00064
00065 #define CLIENT_BUFFER_MAX 4096
00066
00067 #if !defined(__XSTRING)
00068
00069
00070
00071
00072
00073 #define __XSTRING(x) __STRING(x)
00074 #endif
00075
00076
00077
00078
00079
00080
00081 #define my_perror(x) perror(x ", file " __FILE__ ", line " __XSTRING(__LINE__))
00082
00083 enum {
00084 RKTB_DONE,
00085 RKTB_CREATED_RESOURCE_SET,
00086 };
00087
00088
00089
00090
00091
00092
00093
00094 enum {
00095 RKTF_DONE = (1L << RKTB_DONE),
00096 RKTF_CREATED_RESOURCE_SET = (1L << RKTB_CREATED_RESOURCE_SET),
00097 };
00098
00099 enum {
00100 RKTB_CLIENT_INITIALIZED,
00101 };
00102
00103
00104
00105
00106
00107
00108
00109 enum {
00110 RKTF_CLIENT_INITIALIZED = (1L << RKTB_CLIENT_INITIALIZED),
00111 };
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 static struct {
00133 unsigned long rkt_Flags;
00134 const char *rkt_UtilityName;
00135 struct timeval rkt_StartTime;
00136 const char *rkt_OutputBase;
00137 const char *rkt_Name;
00138 unsigned int rkt_ChildPeriod;
00139 unsigned int rkt_ChildCompute;
00140 rk_resource_set_t rkt_ResourceSet;
00141 pid_t rkt_ChildPID;
00142
00143 int rkt_ServerSocket;
00144 char rkt_ClientBuffer[CLIENT_BUFFER_MAX];
00145 int rkt_ClientSockets[MAX_CLIENTS];
00146 unsigned long rkt_ClientFlags[MAX_CLIENTS];
00147 } rktimes_data;
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 static void rktClientWrite(unsigned int index, const char *buffer, size_t len)
00159 {
00160 int fd;
00161
00162 require(rktimes_data.rkt_ServerSocket != -1);
00163 require(index < MAX_CLIENTS);
00164 require(buffer != NULL);
00165
00166 if( (fd = rktimes_data.rkt_ClientSockets[index]) >= 0 )
00167 {
00168 int rc;
00169
00170 rc = write(fd, buffer, len);
00171 if( rc != len )
00172 {
00173 require((rc != -1) || (errno == EPIPE) || (errno == EWOULDBLOCK));
00174
00175
00176 close(fd);
00177 rktimes_data.rkt_ClientSockets[index] = -1;
00178 rktimes_data.rkt_ClientFlags[index] = 0;
00179 }
00180 }
00181 }
00182
00183
00184
00185
00186
00187
00188 static void sigpass(int sig)
00189 {
00190 require((sig == SIGINT) || (sig == SIGTERM));
00191 require(rktimes_data.rkt_ChildPID != 0);
00192
00193 if( kill(rktimes_data.rkt_ChildPID, sig) == -1 )
00194 {
00195 my_perror("kill");
00196 }
00197 }
00198
00199
00200 #define MAX_PROC_LIST 128
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 static void sigalrm(int sig)
00213 {
00214 static unsigned long long total_compute, total_nice, total_deadline;
00215 static unsigned long long total_usage;
00216 static pid_t procs[MAX_PROC_LIST];
00217
00218 unsigned long long inc_usage = 0, total_run, total_idle;
00219 struct cpu_reserve_attr cra;
00220 struct timeval curr, run;
00221 int lpc, len, count;
00222 rk_reserve_t cr;
00223
00224 require(sig == SIGALRM);
00225
00226
00227 gettimeofday(&curr, NULL);
00228 timersub(&curr, &rktimes_data.rkt_StartTime, &run);
00229 total_run = (run.tv_sec * 1000000) + run.tv_usec;
00230
00231
00232 if( (count = rk_resource_set_get_proclist(rktimes_data.rkt_ResourceSet,
00233 procs,
00234 MAX_PROC_LIST)) == -1 )
00235 {
00236 my_perror("rk_resource_set_get_proclist");
00237
00238 rktimes_data.rkt_Flags |= RKTF_DONE;
00239 }
00240
00241
00242 for( lpc = 0; lpc < count; lpc++ )
00243 {
00244 struct cpChildProcess *cp;
00245
00246 if( (cp = cpFindChildProcess(procs[lpc])) == NULL )
00247 {
00248
00249 if( (cp = cpCreateChildProcess(procs[lpc])) != NULL )
00250 {
00251 cpOpenOutput(cp,
00252 rktimes_data.rkt_OutputBase,
00253 &rktimes_data.rkt_StartTime);
00254 }
00255 }
00256 if( cp != NULL )
00257 {
00258 inc_usage += cpSampleUsage(cp, &run);
00259 }
00260 }
00261
00262
00263 total_usage += inc_usage;
00264
00265
00266 if( (cr = rk_resource_set_get_cpu_rsv(rktimes_data.rkt_ResourceSet)) !=
00267 NULL_RESERVE)
00268 {
00269 if( rk_cpu_reserve_get_attr(cr, &cra) != RK_ERROR )
00270 {
00271 unsigned long long rsv_period, rsv_compute, rsv_nice, rsv_deadline;
00272 double multiplier;
00273
00274
00275 rsv_period = (cra.period.tv_sec * 1000000) +
00276 (cra.period.tv_nsec / 1000);
00277 multiplier = (1000000.0 / rsv_period) /
00278 (double)SAMPLES_PER_SECOND;
00279 rsv_compute = ((cra.compute_time.tv_sec * 1000000) +
00280 (cra.compute_time.tv_nsec / 1000)) * multiplier;
00281 if( inc_usage > rsv_compute )
00282 {
00283 rsv_nice = 0;
00284 }
00285 else
00286 {
00287 rsv_nice = rsv_compute - inc_usage;
00288 rsv_compute = inc_usage;
00289 }
00290 rsv_deadline = ((cra.deadline.tv_sec * 1000000) +
00291 (cra.deadline.tv_nsec / 1000)) * multiplier;
00292
00293 total_deadline += rsv_deadline - (rsv_compute + rsv_nice);
00294 total_compute += rsv_compute;
00295 total_nice += rsv_nice;
00296 }
00297 else
00298 {
00299 my_perror("rk_cpu_reserve_get_attr");
00300 }
00301 }
00302
00303 total_idle = total_run - total_usage;
00304
00305
00306 len = gkFormatUpdate(rktimes_data.rkt_ClientBuffer, CLIENT_BUFFER_MAX,
00307 GKA_CPUUser, total_usage,
00308 GKA_CPUIdle, total_idle,
00309 GKA_CPUReserveUser, total_compute,
00310 GKA_CPUReserveNice, total_nice,
00311 GKA_CPUReserveIdle, total_deadline,
00312 GKA_Processes, count,
00313 GKA_ProcessesRunning, 0,
00314 GKA_UpTime, &run,
00315 GKA_TAG_DONE);
00316
00317
00318 for( lpc = 0; lpc < MAX_CLIENTS; lpc++ )
00319 {
00320 if( rktimes_data.rkt_ClientSockets[lpc] != -1 )
00321 {
00322 if( !(rktimes_data.rkt_ClientFlags[lpc] &
00323 RKTF_CLIENT_INITIALIZED) )
00324 {
00325 rktClientWrite(lpc,
00326 gkInitialUpdateOpen,
00327 strlen(gkInitialUpdateOpen));
00328 }
00329 rktClientWrite(lpc, rktimes_data.rkt_ClientBuffer, len);
00330 if( !(rktimes_data.rkt_ClientFlags[lpc] &
00331 RKTF_CLIENT_INITIALIZED) )
00332 {
00333 rktClientWrite(lpc,
00334 gkInitialUpdateClose,
00335 strlen(gkInitialUpdateClose));
00336 rktimes_data.rkt_ClientFlags[lpc] |= RKTF_CLIENT_INITIALIZED;
00337 }
00338 }
00339 }
00340 }
00341
00342
00343
00344
00345
00346
00347 static void sigchld(int sig)
00348 {
00349 require(sig == SIGCHLD);
00350 require(rktimes_data.rkt_ChildPID != 0);
00351
00352 rktimes_data.rkt_Flags |= RKTF_DONE;
00353 }
00354
00355
00356
00357
00358
00359
00360 static void sigexit(int sig)
00361 {
00362 require((sig == SIGINT) || (sig == SIGTERM));
00363
00364 rktimes_data.rkt_Flags |= RKTF_DONE;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 static void sigio(int sig)
00374 {
00375 struct sockaddr saddr;
00376 socklen_t saddrlen;
00377 int fd;
00378
00379 require(sig == SIGIO);
00380 require(rktimes_data.rkt_ServerSocket != -1);
00381
00382 saddrlen = sizeof(saddr);
00383
00384 while( (fd = accept(rktimes_data.rkt_ServerSocket,
00385 &saddr,
00386 &saddrlen)) >= 0 )
00387 {
00388 int fl, lpc;
00389
00390
00391
00392
00393
00394 fl = fcntl(fd, F_GETFL, 0);
00395 fcntl(fd, F_SETFL, fl | O_NONBLOCK);
00396
00397 for( lpc = 0;
00398 (lpc < MAX_CLIENTS) &&
00399 (rktimes_data.rkt_ClientSockets[lpc] != -1);
00400 lpc++ );
00401 if( lpc < MAX_CLIENTS )
00402 {
00403 int len;
00404
00405 rktimes_data.rkt_ClientSockets[lpc] = fd;
00406
00407
00408 len = gkFormatPreamble(
00409 rktimes_data.rkt_ClientBuffer,
00410 CLIENT_BUFFER_MAX,
00411 GKA_HostName, rktimes_data.rkt_Name,
00412 GKA_SystemName, rktimes_data.rkt_UtilityName,
00413 GKA_TAG_DONE);
00414 rktClientWrite(lpc, rktimes_data.rkt_ClientBuffer, len);
00415 }
00416 else
00417 {
00418
00419 close(fd);
00420 }
00421 }
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431 static rk_resource_set_t rktCreateSelfResourceSet(char *name)
00432 {
00433 rk_resource_set_t rs, retval = NULL_RESOURCE_SET;
00434
00435 require(name != NULL);
00436 require(strlen(name) > 0);
00437 require(strlen(name) < RK_NAME_LEN);
00438
00439 if( (rs = rk_resource_set_create(name)) != NULL_RESOURCE_SET )
00440 {
00441 struct cpu_reserve_attr cra;
00442 rk_reserve_t cr;
00443
00444 memset(&cra, 0, sizeof(cra));
00445
00446 cra.compute_time.tv_sec = 0;
00447 cra.compute_time.tv_nsec = 5000000;
00448 cra.period.tv_sec = 0;
00449 cra.period.tv_nsec = 1000000000;
00450 cra.deadline = cra.period;
00451 cra.blocking_time = cra.start_time = (struct timespec){ 0, 0 };
00452 cra.reserve_type.sch_mode = RSV_SOFT;
00453 cra.reserve_type.enf_mode = RSV_SOFT;
00454 cra.reserve_type.rep_mode = RSV_SOFT;
00455 cra.processor = RK_ANY_CPU;
00456 if( rk_cpu_reserve_create(rs, &cr, &cra) != RK_ERROR )
00457 {
00458
00459
00460
00461
00462 retval = rs;
00463 }
00464 else
00465 {
00466 my_perror("rk_cpu_reserve_create");
00467 rk_resource_set_destroy(rs);
00468 }
00469 }
00470 else
00471 {
00472 my_perror("rk_resource_set_create");
00473 }
00474 return( retval );
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 static rk_resource_set_t rktGetChildResourceSet(rk_resource_set_t rs,
00495 const char *requested_name,
00496 const char *default_name,
00497 unsigned int child_period,
00498 unsigned int child_compute)
00499 {
00500 rk_resource_set_t retval = rs;
00501
00502 require((requested_name == NULL) ||
00503 ((strlen(requested_name) > 0) &&
00504 (strlen(requested_name) <= RK_NAME_LEN)));
00505 require(default_name != NULL);
00506 require(strlen(default_name) > 0);
00507 require(strlen(default_name) <= RK_NAME_LEN);
00508 require(((child_period == 0) && (child_compute == 0)) ||
00509 (child_compute < child_period));
00510
00511
00512 if( retval == NULL_RESOURCE_SET )
00513 {
00514 const char *actual_name;
00515
00516 if( requested_name != NULL )
00517 {
00518 actual_name = requested_name;
00519 }
00520 else
00521 {
00522 actual_name = default_name;
00523 }
00524 if( (retval = rk_resource_set_create((char *)actual_name)) !=
00525 NULL_RESOURCE_SET )
00526 {
00527 rktimes_data.rkt_Flags |= RKTF_CREATED_RESOURCE_SET;
00528 }
00529 else
00530 {
00531 my_perror("rk_resource_set_create");
00532 }
00533 }
00534
00535 if( retval != NULL_RESOURCE_SET )
00536 {
00537 rk_reserve_t cr = NULL_RESERVE;
00538
00539 if( (cr = rk_resource_set_get_cpu_rsv(retval)) != NULL_RESERVE )
00540 {
00541
00542
00543
00544
00545 if( rk_resource_set_get_num_procs(retval) > 0 )
00546 {
00547
00548 }
00549 else
00550 {
00551
00552 if( rk_cpu_reserve_delete(retval) == 0 )
00553 {
00554 cr = NULL_RESERVE;
00555
00556 rktimes_data.rkt_Flags |= RKTF_CREATED_RESOURCE_SET;
00557 }
00558 else
00559 {
00560 my_perror("rk_cpu_reserve_delete");
00561 }
00562 }
00563 }
00564
00565 if( (cr == NULL_RESERVE) && (child_period > 0) )
00566 {
00567 struct cpu_reserve_attr cra;
00568
00569 cra.compute_time.tv_sec = 0;
00570 cra.compute_time.tv_nsec = child_compute * 1000;
00571 cra.period.tv_sec = 0;
00572 cra.period.tv_nsec = child_period * 1000;
00573 cra.deadline = cra.period;
00574 cra.blocking_time = cra.start_time = (struct timespec){ 0, 0 };
00575 cra.reserve_type.sch_mode = RSV_SOFT;
00576 cra.reserve_type.enf_mode = RSV_SOFT;
00577 cra.reserve_type.rep_mode = RSV_SOFT;
00578 cra.processor = RK_ANY_CPU;
00579 if( rk_cpu_reserve_create(retval, &cr, &cra) < 0 )
00580 {
00581 my_perror("rk_cpu_reserve_create");
00582 }
00583 }
00584 }
00585 return( retval );
00586 }
00587
00588
00589
00590
00591
00592
00593
00594 static void rktUsage(FILE *file, char *prog_name)
00595 {
00596 require(file != NULL);
00597 require(prog_name != NULL);
00598 require(strlen(prog_name) > 0);
00599
00600 fprintf(file,
00601 "Usage: %s [options] -- <command> [argument ...]\n",
00602 prog_name);
00603 fprintf(file,
00604 "\n"
00605 "Create a resource set and periodically record the CPU\n"
00606 "usage of the attached process and its children.\n"
00607 "\n"
00608 "Options:\n"
00609 "\t-h\t\tThis help message.\n"
00610 "\t-V\t\tShow the version number.\n"
00611
00612 "\t-o <file>\tBase name for the output files. (Default: rktimes)\n"
00613
00614 "\t-n <name>\tName of the RK resource set. If a resource set\n"
00615 "\t\t\twith that name already exists, that will be used.\n"
00616 "\t\t\tOtherwise, a new one with that name will be created.\n"
00617 "\t\t\t(Default: rktimes)\n"
00618
00619 "\t-p <port>\tServer port for GKrellmd emulation.\n"
00620
00621 "\t-P <time>\tThe period for the CPU reservation.\n"
00622 "\t\t\tThe -C option must also be given.\n"
00623
00624 "\t-C <time>\tThe compute time for the CPU reservation.\n"
00625 "\t\t\tThe -P option must also be given.\n"
00626
00627 "\n"
00628
00629 "Package: " PACKAGE_STRING "\n"
00630 "Contact: " PACKAGE_BUGREPORT "\n");
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 static int rktProcessOptions(int *argc_inout, char **argv_inout[])
00645 {
00646 unsigned long long us_time;
00647 int ch, retval = 0;
00648 char *prog_name;
00649 char **argv;
00650 int argc;
00651
00652 require(argc_inout != NULL);
00653 require(argv_inout != NULL);
00654
00655 argc = *argc_inout;
00656 argv = *argv_inout;
00657 prog_name = argv[0];
00658 while( ((ch = getopt(argc, argv, "hVo:n:p:P:C:")) != -1) && (retval == 0) )
00659 {
00660 switch( ch )
00661 {
00662 case 'o':
00663
00664 if( strlen(optarg) == 0 )
00665 {
00666 fprintf(stderr,
00667 "%s: -o value is empty\n",
00668 prog_name);
00669 retval = 1;
00670 }
00671 else
00672 {
00673 rktimes_data.rkt_OutputBase = optarg;
00674 }
00675 break;
00676 case 'n':
00677
00678 if( strlen(optarg) == 0 )
00679 {
00680 fprintf(stderr,
00681 "%s: -n value is empty\n",
00682 prog_name);
00683 retval = 1;
00684 }
00685 else if( strlen(optarg) > RK_NAME_LEN )
00686 {
00687 fprintf(stderr,
00688 "%s: -n value too long (only %d characters allowed)\n",
00689 prog_name,
00690 RK_NAME_LEN);
00691 retval = 1;
00692 }
00693 else
00694 {
00695 rktimes_data.rkt_Name = optarg;
00696 }
00697 break;
00698 case 'P':
00699
00700 if( string_to_microsec(&us_time, optarg) )
00701 {
00702 rktimes_data.rkt_ChildPeriod = us_time;
00703 }
00704 else
00705 {
00706 fprintf(stderr,
00707 "%s: -P option requires a time value\n",
00708 prog_name);
00709 retval = 1;
00710 }
00711 break;
00712 case 'C':
00713
00714 if( string_to_microsec(&us_time, optarg) )
00715 {
00716 rktimes_data.rkt_ChildCompute = us_time;
00717 }
00718 else
00719 {
00720 fprintf(stderr,
00721 "%s: -C option requires a time value\n",
00722 prog_name);
00723 retval = 1;
00724 }
00725 break;
00726 case 'p':
00727
00728 {
00729 int port;
00730
00731 if( (sscanf(optarg, "%d", &port) == 1) &&
00732 (port > 0) && (port < 65536) )
00733 {
00734 int fd;
00735
00736 if( (fd = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
00737 {
00738 my_perror("socket");
00739 retval = -1;
00740 }
00741 else
00742 {
00743 struct sockaddr_in sin;
00744 int on = 1;
00745
00746 (void)setsockopt(fd,
00747 SOL_SOCKET,
00748 SO_REUSEADDR,
00749 (char *)&on,
00750 sizeof(on));
00751 #if defined(BSD44)
00752 sin.sin_len = sizeof(sin);
00753 #endif
00754 sin.sin_family = AF_INET;
00755 sin.sin_port = htons(port);
00756 sin.sin_addr.s_addr = INADDR_ANY;
00757 if( bind(fd,
00758 (struct sockaddr *)&sin,
00759 sizeof(sin)) == -1 )
00760 {
00761 my_perror("bind");
00762 retval = -1;
00763 }
00764 else if( listen(fd, 5) == -1 )
00765 {
00766 my_perror("listen");
00767 retval = -1;
00768 }
00769 else
00770 {
00771 int fl;
00772
00773 fl = fcntl(fd, F_GETFL, 0);
00774 fl |= O_NONBLOCK |
00775 #if defined(O_ASYNC)
00776 O_ASYNC
00777 #elif defined(FASYNC)
00778 FASYNC
00779 #endif
00780 ;
00781 fcntl(fd, F_SETFL, fl);
00782 fcntl(fd, F_SETOWN, getpid());
00783
00784
00785
00786
00787 }
00788 }
00789 if( retval == 0 )
00790 {
00791 rktimes_data.rkt_ServerSocket = fd;
00792 }
00793 else
00794 {
00795 close(fd);
00796 }
00797 }
00798 else
00799 {
00800 fprintf(stderr,
00801 "%s: Invalid -p value: %s\n",
00802 prog_name,
00803 optarg);
00804 retval = 1;
00805 }
00806 }
00807 break;
00808 case 'V':
00809 fprintf(stderr, "%s\n", PACKAGE_VERSION);
00810 retval = -1;
00811 break;
00812 case 'h':
00813 case '?':
00814 default:
00815 retval = 1;
00816 break;
00817 }
00818 }
00819
00820 if( (rktimes_data.rkt_ChildCompute == 0) &&
00821 (rktimes_data.rkt_ChildPeriod == 0) )
00822 {
00823 }
00824 else if( rktimes_data.rkt_ChildCompute == 0 )
00825 {
00826 fprintf(stderr,
00827 "%s: Compute time _must_ be specified with period\n",
00828 prog_name);
00829 retval = 1;
00830 }
00831 else if( rktimes_data.rkt_ChildPeriod == 0 )
00832 {
00833 fprintf(stderr,
00834 "%s: Period time _must_ be specified with compute time\n",
00835 prog_name);
00836 retval = 1;
00837 }
00838 else if( rktimes_data.rkt_ChildCompute >= rktimes_data.rkt_ChildPeriod )
00839 {
00840 fprintf(stderr,
00841 "%s: Compute time _must_ be less than the period\n",
00842 prog_name);
00843 retval = 1;
00844 }
00845 *argc_inout -= optind;
00846 *argv_inout += optind;
00847
00848 if( (*argc_inout > 0) && (strcmp(*argv_inout[0], "--") == 0) )
00849 {
00850 *argc_inout -= 1;
00851 *argv_inout += 1;
00852 }
00853 if( (retval == 0) && (*argc_inout == 0) )
00854 {
00855
00856 if( rktimes_data.rkt_Name == NULL )
00857 {
00858 fprintf(stderr, "%s: Missing utility to monitor\n", prog_name);
00859 retval = 1;
00860 }
00861
00862 else if( (rktimes_data.rkt_ResourceSet =
00863 rk_resource_set_get_by_name(rktimes_data.rkt_Name)) ==
00864 NULL_RESOURCE_SET )
00865 {
00866 fprintf(stderr,
00867 "%s: No such resource set: %s\n",
00868 prog_name,
00869 rktimes_data.rkt_Name);
00870 retval = 1;
00871 }
00872 }
00873 return( retval );
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887 static int rktParentPart(rk_resource_set_t rs)
00888 {
00889 int retval = EXIT_FAILURE;
00890 struct itimerval itv;
00891 struct sigaction sa;
00892 sigset_t sigmask;
00893
00894 require(rs != NULL_RESOURCE_SET);
00895
00896 if( rktimes_data.rkt_ChildPID != 0 )
00897 {
00898 char scratch[PATH_MAX];
00899 FILE *pid_file;
00900
00901 snprintf(scratch,
00902 sizeof(scratch),
00903 "%s-child.pid",
00904 rktimes_data.rkt_OutputBase);
00905 if( (pid_file = fopen(scratch, "w")) != NULL )
00906 {
00907 fprintf(pid_file, "%d", rktimes_data.rkt_ChildPID);
00908 fclose(pid_file);
00909 pid_file = NULL;
00910 }
00911 }
00912
00913
00914 if( rk_resource_set_attach_process(rs, getpid()) < 0 )
00915 {
00916 my_perror("rk_resource_set_attach_process");
00917 }
00918
00919
00920
00921
00922
00923
00924
00925 sigemptyset(&sigmask);
00926 sigaddset(&sigmask, SIGALRM);
00927 sigaddset(&sigmask, SIGCHLD);
00928 sigaddset(&sigmask, SIGIO);
00929 sigaddset(&sigmask, SIGINT);
00930 sigaddset(&sigmask, SIGTERM);
00931 if( sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0 )
00932 {
00933 my_perror("sigprocmask");
00934
00935 ensure(0);
00936 }
00937
00938
00939 sa.sa_mask = sigmask;
00940 sa.sa_flags = 0;
00941 #if defined(SA_RESTART)
00942 sa.sa_flags |= SA_RESTART;
00943 #endif
00944
00945 signal(SIGPIPE, SIG_IGN);
00946
00947 sa.sa_handler = sigalrm;
00948 sigaction(SIGALRM, &sa, NULL);
00949
00950 if( rktimes_data.rkt_ServerSocket != -1 )
00951 {
00952 sa.sa_handler = sigio;
00953 sigaction(SIGIO, &sa, NULL);
00954 }
00955
00956 if( rktimes_data.rkt_ChildPID == 0 )
00957 {
00958
00959
00960
00961
00962
00963 sa.sa_handler = sigexit;
00964 sigaction(SIGINT, &sa, NULL);
00965 sigaction(SIGTERM, &sa, NULL);
00966 }
00967 else
00968 {
00969
00970 sa.sa_handler = sigchld;
00971 sigaction(SIGCHLD, &sa, NULL);
00972
00973
00974
00975
00976
00977
00978 sa.sa_handler = sigpass;
00979 sigaction(SIGINT, &sa, NULL);
00980 sigaction(SIGTERM, &sa, NULL);
00981 }
00982
00983 itv.it_interval.tv_sec = 0;
00984 itv.it_interval.tv_usec = 1000000 / SAMPLES_PER_SECOND;
00985 itv.it_value.tv_sec = 0;
00986 itv.it_value.tv_usec = 1000000 / SAMPLES_PER_SECOND;
00987
00988 if( setitimer(ITIMER_REAL, &itv, NULL) == 0 )
00989 {
00990 sigset_t empty_sigmask;
00991 int status;
00992
00993 sigemptyset(&empty_sigmask);
00994
00995
00996 while( !(rktimes_data.rkt_Flags & RKTF_DONE) )
00997 {
00998 sigsuspend(&empty_sigmask);
00999 }
01000
01001
01002 if( rktimes_data.rkt_ChildPID == 0 )
01003 {
01004
01005
01006
01007 }
01008 else if( wait(&status) >= 0 )
01009 {
01010 if( WIFEXITED(status) )
01011 {
01012 retval = WEXITSTATUS(status);
01013 }
01014 else if( WIFSIGNALED(status) )
01015 {
01016 retval = EXIT_SUCCESS;
01017 }
01018 else
01019 {
01020 retval = EXIT_FAILURE;
01021 }
01022 }
01023 else
01024 {
01025 my_perror("wait");
01026 retval = EXIT_FAILURE;
01027 }
01028
01029
01030 memset(&itv, 0, sizeof(itv));
01031 if( setitimer(ITIMER_REAL, &itv, NULL) < 0 )
01032 {
01033 my_perror("setitimer");
01034
01035 ensure(0);
01036 }
01037 }
01038 else
01039 {
01040 my_perror("setitimer");
01041 retval = EXIT_FAILURE;
01042 }
01043
01044
01045 signal(SIGALRM, SIG_IGN);
01046 signal(SIGCHLD, SIG_IGN);
01047 signal(SIGINT, SIG_IGN);
01048 signal(SIGTERM, SIG_IGN);
01049 signal(SIGIO, SIG_IGN);
01050
01051
01052 if( sigprocmask(SIG_UNBLOCK, &sigmask, NULL) < 0 )
01053 {
01054 my_perror("sigprocmask");
01055
01056 ensure(0);
01057 }
01058
01059 return( retval );
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 static int rktChildPart(rk_resource_set_t rs, char *argv[])
01075 {
01076 int rc, retval = EXIT_SUCCESS;
01077 sigset_t sigmask;
01078 int lpc;
01079
01080 require(rs != NULL_RESOURCE_SET);
01081 require(argv != NULL);
01082
01083
01084
01085
01086
01087 rk_inherit_mode(1);
01088 if( rk_resource_set_attach_process(rs, getpid()) == 0 )
01089 {
01090 }
01091 else
01092 {
01093 my_perror("rk_resource_set_attach_process");
01094 retval = EXIT_FAILURE;
01095 }
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105 if( rktimes_data.rkt_ServerSocket != -1 )
01106 {
01107 close(rktimes_data.rkt_ServerSocket);
01108 rktimes_data.rkt_ServerSocket = -1;
01109 }
01110
01111
01112 do {
01113 if( (rc = open("/dev/null", O_RDWR)) == -1 )
01114 {
01115 fprintf(stderr, "Error: Cannot open '/dev/null'?");
01116 retval = EXIT_FAILURE;
01117 }
01118 else if( rc > 2 )
01119 {
01120 close(rc);
01121 }
01122 else
01123 {
01124
01125 }
01126 } while( (rc >= 0) && (rc <= 2) );
01127
01128
01129 for( lpc = 3; lpc < FD_SETSIZE; lpc++ )
01130 {
01131 if( close(lpc) != -1 )
01132 {
01133 fprintf(stderr,
01134 "Warning: Descriptor %d was leaked from rktimes.\n",
01135 lpc);
01136 }
01137 }
01138
01139
01140 sigfillset(&sigmask);
01141 if( sigprocmask(SIG_UNBLOCK, &sigmask, NULL) < 0 )
01142 {
01143 my_perror("sigprocmask");
01144
01145 ensure(0);
01146 }
01147
01148 if( retval == EXIT_SUCCESS )
01149 {
01150 execvp(argv[0], argv);
01151
01152
01153 perror(argv[0]);
01154 switch( errno )
01155 {
01156 case ENOENT:
01157 case EPERM:
01158 retval = 127;
01159 break;
01160 default:
01161 retval = EXIT_FAILURE;
01162 break;
01163 }
01164 }
01165 return( retval );
01166 }
01167
01168 int main(int argc, char *argv[])
01169 {
01170 int lpc, retval = EXIT_FAILURE;
01171
01172
01173 rktimes_data.rkt_OutputBase = "rktimes";
01174 rktimes_data.rkt_ServerSocket = -1;
01175 for( lpc = 0; lpc < MAX_CLIENTS; lpc++ )
01176 {
01177 rktimes_data.rkt_ClientSockets[lpc] = -1;
01178 }
01179
01180
01181 if( cpInitChildProcessData() )
01182 {
01183 char *prog_name = argv[0];
01184 int rc;
01185
01186 rc = rktProcessOptions(&argc, &argv);
01187 if( (rc == 0) && ((argc > 0) || (rktimes_data.rkt_Name != NULL)) )
01188 {
01189 char self_rs_name[RK_NAME_LEN + 1];
01190 rk_resource_set_t rs;
01191
01192 if( argc > 0 )
01193 {
01194 rktimes_data.rkt_UtilityName = argv[0];
01195 }
01196 else
01197 {
01198 rktimes_data.rkt_UtilityName = "(none)";
01199 }
01200 snprintf(self_rs_name, RK_NAME_LEN + 1, "rktimes.%d", getpid());
01201
01202
01203
01204
01205
01206 {
01207 sigset_t sigmask;
01208
01209 sigaddset(&sigmask, SIGINT);
01210 sigaddset(&sigmask, SIGTERM);
01211 if( sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0 )
01212 {
01213 my_perror("sigprocmask");
01214
01215 ensure(0);
01216 }
01217 }
01218
01219 rs = rktCreateSelfResourceSet(self_rs_name);
01220 rktimes_data.rkt_ResourceSet =
01221 rktGetChildResourceSet(rktimes_data.rkt_ResourceSet,
01222 rktimes_data.rkt_Name,
01223 "rktimes",
01224 rktimes_data.rkt_ChildPeriod,
01225 rktimes_data.rkt_ChildCompute);
01226 if( (rs != NULL_RESOURCE_SET) &&
01227 (rktimes_data.rkt_ResourceSet != NULL_RESOURCE_SET) )
01228 {
01229 gettimeofday(&rktimes_data.rkt_StartTime, NULL);
01230 if( argc == 0 )
01231 {
01232 retval = rktParentPart(rs);
01233 }
01234 else if( (rktimes_data.rkt_ChildPID = fork()) > 0 )
01235 {
01236 retval = rktParentPart(rs);
01237 }
01238 else if( rktimes_data.rkt_ChildPID == 0 )
01239 {
01240 return( rktChildPart(rktimes_data.rkt_ResourceSet, argv) );
01241 }
01242 else
01243 {
01244 my_perror("fork");
01245 retval = EXIT_FAILURE;
01246 }
01247 }
01248 if( rktimes_data.rkt_Flags & RKTF_CREATED_RESOURCE_SET )
01249 {
01250 rk_resource_set_destroy(rktimes_data.rkt_ResourceSet);
01251 rktimes_data.rkt_ResourceSet = NULL_RESOURCE_SET;
01252 }
01253 rk_resource_set_destroy(rs);
01254 }
01255 else if( rc >= 0 )
01256 {
01257 rktUsage(stderr, prog_name);
01258 }
01259 if( rktimes_data.rkt_ServerSocket != -1 )
01260 {
01261 close(rktimes_data.rkt_ServerSocket);
01262 rktimes_data.rkt_ServerSocket = -1;
01263 }
01264 cpKillChildProcessData();
01265 }
01266
01267 return( retval );
01268 }