home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2214 / prt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  10.2 KB  |  635 lines

  1. /*
  2.  * prt - Paralel Ray Tracer
  3.  *
  4.  * Copyright (C) 1990, Kory Hamzeh.
  5.  *
  6.  * This program acts as a front-end to 'rt'. It takes the user given list
  7.  * of hostnames, and using rsh, it spawns off copys of rt running on different
  8.  * machines. It will gather up the image fragments that each sub-process sends
  9.  * it, and builds one final image. The usage syntax is as follows:
  10.  *
  11.  *     prt input-file output-file host [host ... ]
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/fcntl.h>
  16. #include <sys/errno.h>
  17. #include <signal.h>
  18. #include <stdio.h>
  19.  
  20. #define MAX_HOSTS    64
  21.  
  22. typedef struct rt_info {
  23.     char    hostname[32];
  24.     int    pid;
  25.     int    cur_bytes;
  26.     int    tot_bytes;
  27.     int    offset;
  28.     int    bld_offset;
  29.     long    time_st;
  30.     long    time_en;
  31.     int    out_pipe[2];
  32.     int    err_pipe[2];
  33.     } RT_INFO;
  34.  
  35. RT_INFO rt_tab[MAX_HOSTS];
  36.  
  37. int num_hosts = 0;
  38. int tot_bytes = 0;
  39. int cur_bytes = 0;
  40. int percent_done = 0;
  41. int verbose = 0;
  42. int in_file[64];
  43. int out_file[64];
  44. FILE *in_fp;
  45. FILE *out_fp;
  46. int image_x;
  47. int image_y;
  48. char *image;
  49. char *my_name;
  50. fd_set work_fds;
  51. fd_set orig_fds;
  52. long time_st;
  53. long time_en;
  54. char *rt_args[32];
  55.  
  56. int Dead_baby();
  57.  
  58. /*
  59. ** Main startup code.
  60. */
  61.  
  62. main(argc, argv)
  63. int argc;
  64. char *argv[];
  65. {
  66.     int i, pix1, pix2;
  67.  
  68.     time(&time_st);
  69.  
  70.     my_name = argv[0];
  71.     ++argv;
  72.     --argc;
  73.  
  74.     if(argc < 3)
  75.         Usage();
  76.  
  77.     /*
  78.     ** Check for the verbose option.
  79.     */
  80.  
  81.     if(!strcmp(argv[0], "-v"))
  82.     {
  83.         verbose = 1;
  84.         ++argv;
  85.         --argc;
  86.     }
  87.  
  88.     if(argc < 2)
  89.         Usage();
  90.  
  91.     rt_args[0] = "rsh";
  92.     rt_args[2] = "rt";
  93.     rt_args[3] = "-z";
  94.     rt_args[4] = "-y";
  95.  
  96.     i = 7;
  97.     rt_args[i] = NULL;
  98.     while(argc > 2 && *argv[0] == '-')
  99.     {
  100.         rt_args[i] = *argv;
  101.         rt_args[i + 1] = NULL;
  102.         i++;
  103.         ++argv;
  104.         --argc;
  105.     }
  106.  
  107.     strcpy(in_file, argv[0]);
  108.     ++argv;
  109.     --argc;
  110.  
  111.     strcpy(out_file, argv[0]);
  112.     ++argv;
  113.     --argc;
  114.  
  115.     signal(SIGCLD, Dead_baby);
  116.  
  117.     /*
  118.     ** Get the list of hosts from the command line.
  119.     */
  120.  
  121.     while(argc > 0 && num_hosts < MAX_HOSTS)
  122.     {
  123.         strcpy(rt_tab[num_hosts].hostname, argv[0]);
  124.  
  125.         rt_tab[num_hosts].cur_bytes = 0;
  126.         rt_tab[num_hosts].tot_bytes = 0;
  127.  
  128.         ++argv;
  129.         --argc;
  130.         ++num_hosts;
  131.     }
  132.  
  133.     if(num_hosts == 0)
  134.     {
  135.         fprintf(stderr, "%s: no host were specified.\n", my_name);
  136.         exit(0);
  137.     }
  138.  
  139.     /*
  140.     ** Check to see if too many hosts were specified.
  141.     */
  142.  
  143.     if(num_hosts == MAX_HOSTS)
  144.     {
  145.         fprintf(stderr, "%s: Too many hosts. Max is %d.\n", 
  146.             my_name, MAX_HOSTS);
  147.         exit(1);
  148.     }
  149.  
  150.     /*
  151.     ** Check the image size.
  152.     */
  153.  
  154.     Get_image_size();
  155.  
  156.     if(verbose)
  157.     {
  158.         fprintf(stderr, "%s: image size is %d x %d\n", 
  159.             my_name, image_x, image_y);
  160.     }
  161.  
  162.     /*
  163.     ** Allocate an image buffer.
  164.     */
  165.  
  166.     if((image = (char *) malloc(image_x * image_y * 3)) == NULL)
  167.     {
  168.         fprintf(stderr, "%s: malloc of %d failed.\n", my_name,
  169.             image_x, image_y);
  170.         exit(1);
  171.     }
  172.  
  173.     /*
  174.     ** Open the output file.
  175.     */
  176.  
  177.     if((out_fp = fopen(out_file, "w")) == NULL)
  178.     {
  179.         fprintf(stderr, "%s: unable to create file '%s'.\n", my_name, out_file);
  180.         exit(1);
  181.     }
  182.  
  183.     /*
  184.     ** Calculate the total number of pixels that each sub-process
  185.     ** must render.
  186.     */
  187.  
  188.     pix1 = image_y / num_hosts;
  189.     pix2 = image_y % num_hosts;
  190.  
  191.     for(i = 0; i < num_hosts; i++)
  192.         rt_tab[i].tot_bytes = pix1 * (image_x * 3);
  193.  
  194.     for(i = 0; i < pix2; i++)
  195.         rt_tab[i].tot_bytes += image_x * 3;
  196.  
  197.     /*
  198.     ** Calculate the offset into the image buffer which each host
  199.     ** will use.
  200.     */
  201.  
  202.     for(i = 0, pix1 = 0; i < num_hosts; i++, pix1 += rt_tab[i].tot_bytes)
  203.         rt_tab[i].offset  = rt_tab[i].bld_offset = pix1;
  204.  
  205.     /*
  206.     ** Start the sub-processes.
  207.     */
  208.  
  209.     Start_tracers();
  210.  
  211.     /*
  212.     ** Gather bits of image and build one final big image.
  213.     */
  214.  
  215.     Gather_image();
  216.  
  217.     /*
  218.     ** Exit and go home.
  219.     */
  220.  
  221.     time(&time_en);
  222.  
  223.     if(verbose)
  224.         fprintf(stderr, "%s: Total execution time: %02d:%02d.\n",
  225.             my_name, (time_en - time_st) / 60, (time_en - time_st) % 60);
  226.  
  227.     fclose(out_fp);
  228.     exit(0);
  229. }
  230.  
  231.  
  232. /*
  233. ** Get_image_size()
  234. **
  235. ** Scan the object database looking for the resolution key word to figure
  236. ** out how big this image will be.
  237. */
  238.  
  239. Get_image_size()
  240. {
  241.     int found = 0;
  242.     int line = 1;
  243.     char buf[512];
  244.  
  245.     if((in_fp = fopen(in_file, "r")) == NULL)
  246.     {
  247.         fprintf(stderr, "%s: unable to open input file '%s'\n", 
  248.             my_name, in_file);
  249.         exit(1);
  250.     }
  251.  
  252.     /*
  253.     ** Scan the file looking for 'resolution xxx yyy'.
  254.     */
  255.  
  256.     while(fgets(buf, sizeof(buf), in_fp))
  257.     {
  258.         if(!strncmp(buf, "resolution", 10))
  259.         {
  260.             if(sscanf(buf + 10, "%d %d", &image_x, &image_y) != 2)
  261.             {
  262.                 fprintf(stderr, "%s: invalid resolution specified in input file on line %d.\n", my_name, line);
  263.                 fclose(in_fp);
  264.                 exit(1);
  265.             }
  266.  
  267.             found = 1;
  268.             break;
  269.         }
  270.  
  271.         ++line;
  272.     }
  273.  
  274.     fclose(in_fp);
  275.     if(!found)
  276.     {
  277.         fprintf(stderr, "%s: image resolution not found in file '%s'.\n",
  278.             my_name, in_file);
  279.         exit(1);
  280.     }
  281. }
  282.  
  283. /*
  284. ** Start_tracers()
  285. **
  286. ** This routine is a bit hairy. It creates the input, output, and error
  287. ** pipe, and then rsh's rt.
  288. */
  289.  
  290. Start_tracers()
  291. {
  292.     int rc, h, in_fd, i;
  293.     char starty[32], incy[32];
  294.  
  295.  
  296.     for(h = 0; h < num_hosts; h++)
  297.     {
  298.         /* First, create the pipe. */
  299.         rc = pipe(rt_tab[h].out_pipe);
  300.         rc += pipe(rt_tab[h].err_pipe);
  301.  
  302.         if(rc != 0)
  303.         {
  304.             fprintf(stderr, "%s: pipe() failed.\n", my_name);
  305.             Kill_tracers(h);
  306.         }
  307.  
  308.         if(verbose)
  309.             fprintf(stderr, "%s: starting rt on host %s.\n", my_name,
  310.                 rt_tab[h].hostname);
  311.         /* fork */
  312.         if((rt_tab[h].pid = fork()) < 0)
  313.         {
  314.             fprintf(stderr, "%s: fork() failed.\n", my_name);
  315.             Kill_tracers(h);
  316.         }
  317.  
  318.         if(rt_tab[h].pid > 0)        /* parent */
  319.         {
  320.             /* Close the write end of the pipes. */
  321.             close(rt_tab[h].out_pipe[1]);
  322.             close(rt_tab[h].err_pipe[1]);
  323.             /* Set for no delay on read */
  324.             fcntl(rt_tab[h].out_pipe[0], F_SETFL, O_NDELAY);
  325.             fcntl(rt_tab[h].err_pipe[0], F_SETFL, O_NDELAY);
  326.             /* set the start time */
  327.             time(&rt_tab[h].time_st);
  328.         }
  329.         else
  330.         {
  331.             sprintf(starty, "%d", h);
  332.             sprintf(incy, "%d", num_hosts);
  333.  
  334.             /* Close the read end of the pipe */
  335.             close(rt_tab[h].out_pipe[0]);
  336.             close(rt_tab[h].err_pipe[0]);
  337.  
  338.             in_fd = open(in_file, O_RDONLY);
  339.             close(0);        /* the data file */
  340.             dup(in_fd);
  341.             close(1);
  342.             dup(rt_tab[h].out_pipe[1]);
  343.  
  344.             close(2);
  345.             dup(rt_tab[h].err_pipe[1]);
  346.  
  347.             for(i = 3; i < 100; i++)
  348.                 close(i);
  349.  
  350.             rt_args[1] = rt_tab[h].hostname;
  351.             rt_args[5] = starty;
  352.             rt_args[6] = incy;
  353.  
  354.             /* exec the sucker */
  355.             execvp("rsh", rt_args);
  356.  
  357.             fprintf(stderr, "%s: rsh on host %s failed.\n", my_name,
  358.                 rt_tab[h].hostname); 
  359.             exit(1);
  360.         }
  361.     }
  362. }
  363.  
  364. /*
  365. ** Gather_image()
  366. **
  367. ** This routine gathers the bits of images flying back from the various 
  368. ** sub-processes, and build one big final image.
  369. */
  370.  
  371. Gather_image()
  372. {
  373.     int h, width, rc;
  374.     extern int errno;
  375.  
  376.     /*
  377.     ** Build fd list for select.
  378.     */
  379.  
  380.     Build_fd_set();
  381.  
  382.     /*
  383.     ** Write the image header.
  384.     */
  385.  
  386.     fprintf(out_fp, "%d %d\n", image_x, image_y);
  387.     tot_bytes = image_x * image_y * 3;
  388.     cur_bytes = 0;
  389.     percent_done = 0;
  390.     width = MAX_HOSTS * 2;
  391.  
  392.     /*
  393.     ** Main loop.
  394.     */
  395.  
  396.     if(verbose)
  397.         fprintf(stderr, "%s: %d%% done         ", my_name, percent_done);
  398.  
  399.     while(cur_bytes < tot_bytes)
  400.     {
  401.         Build_fd_set();
  402.         work_fds = orig_fds;
  403.         rc = select(width, &work_fds, NULL, NULL, NULL);
  404.         if(rc < 0)
  405.             continue;
  406.  
  407.         for(h = 0; h < num_hosts; h++)
  408.         {
  409.             if(rt_tab[h].pid == 0)
  410.                 continue;
  411.  
  412.             if(FD_ISSET(rt_tab[h].out_pipe[0], &work_fds))
  413.             {
  414.                 Get_image_frag(h);
  415.                 FD_CLR(rt_tab[h].out_pipe[0], &work_fds);
  416.             }
  417.  
  418.             if(FD_ISSET(rt_tab[h].err_pipe[0], &work_fds))
  419.             {
  420.                 Tracer_error_report(h);
  421.                 FD_CLR(rt_tab[h].err_pipe[0], &work_fds);
  422.             }
  423.  
  424.         }
  425.  
  426.         if(verbose)
  427.         {
  428.             if(((cur_bytes * 100) / tot_bytes) != percent_done)
  429.             {
  430.                 percent_done = (cur_bytes * 100) / tot_bytes;
  431.                 fprintf(stderr, "\r%s: %d%% done        ", my_name, 
  432.                     percent_done);
  433.             }
  434.         }
  435.     }
  436.  
  437.     /* Write out the image */
  438.     Write_image();
  439.  
  440. }
  441.  
  442. /*
  443. ** Get_image_frag(host)
  444. **
  445. ** Get the image fragment which just came form one of the tracers. Just store
  446. ** it in the buffer for now, and we'll sort it out later.
  447. */
  448.  
  449. Get_image_frag(h)
  450. int h;
  451. {
  452.     int fd, count;
  453.     char *p;
  454.     extern int errno;
  455.  
  456.     if(rt_tab[h].pid == 0)
  457.         return;
  458.  
  459.     fd = rt_tab[h].out_pipe[0];
  460.     p = image + rt_tab[h].offset + rt_tab[h].cur_bytes;
  461.  
  462.     while((count = read(fd, p, image_x * 3)) > 0)
  463.     {
  464.         p += count;
  465.         rt_tab[h].cur_bytes += count;
  466.         cur_bytes += count;
  467.         if(rt_tab[h].cur_bytes == rt_tab[h].tot_bytes)
  468.         {
  469.             if(verbose)
  470.                 Rt_done(h);
  471.             rt_tab[h].pid = 0;
  472.             return ;
  473.         }
  474.     }
  475.  
  476.     if(count == 0 && errno != EWOULDBLOCK && errno != EINTR)
  477.     {
  478.         rt_tab[h].pid = 0;    /* this guy is done */
  479.         if(verbose)
  480.             fprintf(stderr, "\n%s: rt on host %s is done.\n", my_name,
  481.                 rt_tab[h].hostname);
  482.     }
  483.  
  484. }
  485.  
  486.  
  487. /*
  488. ** Tracer_error_report()
  489. **
  490. ** A rt sub-process sent us a message through its stderr pipe. Display the
  491. ** message and kill them all.
  492. */
  493.  
  494. Tracer_error_report(h)
  495. int h;
  496. {
  497.     char ebuf[512];
  498.     int count;
  499.  
  500.     if(rt_tab[h].pid == 0)
  501.         return ;
  502.  
  503.     count = read(rt_tab[h].err_pipe[0], ebuf, sizeof(ebuf));
  504.     if(count > 0)
  505.     {
  506.         fprintf(stderr, "\n%s: Error from rt on host %s\007\n", my_name,
  507.             rt_tab[h].hostname);
  508.         ebuf[count] = 0;
  509.         fprintf(stderr, "%s", ebuf);
  510.         Kill_tracers(num_hosts);
  511.         exit(0);
  512.     }
  513. }
  514.  
  515.  
  516. /*
  517. ** Write_image()
  518. **
  519. ** Take the image fragments that came back from all of the tracers and
  520. ** write one big image.
  521. */
  522.  
  523. Write_image()
  524. {
  525.     int h, rs;
  526.     char *p;
  527.  
  528.     if(verbose)
  529.         fprintf(stderr, "\n%s: writing image ... ", my_name);
  530.  
  531.     cur_bytes = 0;
  532.     rs = image_x * 3;
  533.     h = 0;
  534.  
  535.     while(cur_bytes < tot_bytes)
  536.     {
  537.         p = image + rt_tab[h].bld_offset;
  538.         fwrite(p, rs, 1, out_fp);
  539.         rt_tab[h].bld_offset += rs;
  540.         cur_bytes += rs;
  541.  
  542.         h++;
  543.         if(h == num_hosts)
  544.             h = 0;
  545.     }
  546.  
  547.     if(verbose)
  548.         fprintf(stderr, "\n");
  549. }
  550.  
  551.  
  552. /*
  553. ** Usage()
  554. **
  555. ** Print usage message.
  556. */
  557.  
  558.  
  559. Usage()
  560. {
  561.     fprintf(stderr, "Usage: %s [-v] input-file output-file host [host ..]\n",
  562.         my_name);
  563.     exit(1);
  564. }
  565.  
  566.  
  567. /*
  568. ** Kill_tracers()
  569. **
  570. */
  571.  
  572. Kill_tracers(count)
  573. int count;
  574. {
  575.     int h;
  576.  
  577.     for(h = 0; h < count; h++)
  578.         kill(rt_tab[h].pid, 9);     /* a sure kill */
  579. }
  580.  
  581. /*
  582. ** Dead_baby()
  583. **
  584. ** Death of a child signal is vectored here.
  585. */
  586.  
  587. Dead_baby()
  588. {
  589.     int status;
  590.  
  591.     wait(&status);
  592.     signal(SIGCLD, Dead_baby);
  593. }
  594.  
  595. /*
  596. ** Build_fd_set() - Build an fd_set for select()
  597. */
  598.  
  599. Build_fd_set()
  600. {
  601.     int h;
  602.  
  603.     FD_ZERO(&orig_fds);
  604.  
  605.     for(h = 0; h < num_hosts; h++)
  606.     {
  607.         if(rt_tab[h].pid == 0)
  608.             continue;
  609.  
  610.         FD_SET(rt_tab[h].out_pipe[0], &orig_fds);
  611.         FD_SET(rt_tab[h].err_pipe[0], &orig_fds); 
  612.     }
  613. }
  614.  
  615.  
  616. /*
  617. ** Rt_done()
  618. **
  619. ** A rt sub-process fisnished, let the user know.
  620. */
  621.  
  622. Rt_done(h)
  623. int h;
  624. {
  625.     int min, sec;
  626.  
  627.     time(&rt_tab[h].time_en);
  628.     min = (rt_tab[h].time_en - rt_tab[h].time_st) / 60;
  629.     sec = (rt_tab[h].time_en - rt_tab[h].time_st) % 60;
  630.  
  631.     fprintf(stderr, "\n%s: rt on host %s is done. Execution time: %02d:%02d.\n", 
  632.             my_name, rt_tab[h].hostname, min, sec);
  633. }
  634.  
  635.