| 1 | gwlarson | 3.19 | /* Copyright (c) 1998 Silicon Graphics, Inc. */ | 
| 2 | gregl | 3.1 |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ SGI"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 |  |  | * Holodeck display process communication | 
| 9 |  |  | */ | 
| 10 |  |  |  | 
| 11 |  |  | #include "rholo.h" | 
| 12 |  |  | #include "rhdisp.h" | 
| 13 | gregl | 3.2 | #include <sys/uio.h> | 
| 14 | gregl | 3.1 |  | 
| 15 | gregl | 3.2 | #ifndef HDSUF | 
| 16 | gregl | 3.16 | #define HDSUF   ".hdi" | 
| 17 | gregl | 3.2 | #endif | 
| 18 | gregl | 3.1 |  | 
| 19 | gregl | 3.2 | static int      inp_flags; | 
| 20 |  |  | static int      dpd[3]; | 
| 21 | gregl | 3.5 | static FILE     *dpout; | 
| 22 | gregl | 3.2 |  | 
| 23 |  |  |  | 
| 24 |  |  | disp_open(dname)                /* open the named display driver */ | 
| 25 | gregl | 3.1 | char    *dname; | 
| 26 |  |  | { | 
| 27 | gregl | 3.11 | char    dpath[128], fd0[8], fd1[8], *cmd[5]; | 
| 28 | gregl | 3.2 | int     i; | 
| 29 | gregl | 3.11 | /* get full display program name */ | 
| 30 | gregl | 3.2 | #ifdef DEVPATH | 
| 31 |  |  | sprintf(dpath, "%s/%s%s", DEVPATH, dname, HDSUF); | 
| 32 |  |  | #else | 
| 33 |  |  | sprintf(dpath, "dev/%s%s", dname, HDSUF); | 
| 34 |  |  | #endif | 
| 35 | gregl | 3.11 | /* dup stdin and stdout */ | 
| 36 |  |  | if (readinp) | 
| 37 |  |  | sprintf(fd0, "%d", dup(0)); | 
| 38 |  |  | else | 
| 39 |  |  | strcpy(fd0, "-1"); | 
| 40 |  |  | sprintf(fd1, "%d", dup(1)); | 
| 41 |  |  | /* start the display process */ | 
| 42 |  |  | cmd[0] = dpath; | 
| 43 |  |  | cmd[1] = froot; cmd[2] = fd1; cmd[3] = fd0; | 
| 44 |  |  | cmd[4] = NULL; | 
| 45 |  |  | i = open_process(dpd, cmd); | 
| 46 | gregl | 3.6 | if (i <= 0) | 
| 47 | gregl | 3.2 | error(USER, "cannot start display process"); | 
| 48 | gregl | 3.11 | if ((dpout = fdopen(dpd[1], "w")) == NULL) | 
| 49 | gregl | 3.5 | error(SYSTEM, "cannot associate FILE with display pipe"); | 
| 50 | gregl | 3.11 | dpd[1] = -1;            /* causes ignored error in close_process() */ | 
| 51 | gregl | 3.2 | inp_flags = 0; | 
| 52 | gregl | 3.11 | /* close dup'ed stdin and stdout */ | 
| 53 |  |  | if (readinp) | 
| 54 |  |  | close(atoi(fd0)); | 
| 55 |  |  | close(atoi(fd1)); | 
| 56 | gregl | 3.17 | /* check if outside */ | 
| 57 |  |  | if (vdef(OBSTRUCTIONS) && vbool(OBSTRUCTIONS)) | 
| 58 |  |  | disp_result(DS_OUTSECT, 0, NULL); | 
| 59 | gwlarson | 3.18 | /* send eye separation if specified */ | 
| 60 |  |  | if (vdef(EYESEP)) { | 
| 61 |  |  | char    fbuf[32]; | 
| 62 |  |  | sprintf(fbuf, "%.9e", vflt(EYESEP)); | 
| 63 |  |  | disp_result(DS_EYESEP, strlen(fbuf)+1, fbuf); | 
| 64 |  |  | } | 
| 65 | gregl | 3.2 | /* write out hologram grids */ | 
| 66 |  |  | for (i = 0; hdlist[i] != NULL; i++) | 
| 67 |  |  | disp_result(DS_ADDHOLO, sizeof(HDGRID), (char *)hdlist[i]); | 
| 68 | gregl | 3.5 | disp_flush(); | 
| 69 | gregl | 3.1 | } | 
| 70 |  |  |  | 
| 71 |  |  |  | 
| 72 | gregl | 3.2 | disp_packet(p)                  /* display a packet */ | 
| 73 | gregl | 3.4 | register PACKHEAD       *p; | 
| 74 | gregl | 3.2 | { | 
| 75 | gregl | 3.4 | disp_result(DS_BUNDLE, packsiz(p->nr), (char *)p); | 
| 76 | gregl | 3.2 | } | 
| 77 |  |  |  | 
| 78 |  |  |  | 
| 79 | gregl | 3.1 | disp_check(block)               /* check display process */ | 
| 80 |  |  | int     block; | 
| 81 |  |  | { | 
| 82 | gregl | 3.2 | MSGHEAD msg; | 
| 83 |  |  | int     n; | 
| 84 |  |  | char    *buf = NULL; | 
| 85 |  |  |  | 
| 86 | gregl | 3.6 | if (dpout == NULL) | 
| 87 | gregl | 3.2 | return(-1); | 
| 88 | gregl | 3.5 | /* flush display output */ | 
| 89 |  |  | disp_flush(); | 
| 90 | gregl | 3.3 | /* check read blocking */ | 
| 91 | gregl | 3.2 | if (block != (inp_flags == 0)) { | 
| 92 |  |  | inp_flags = block ? 0 : FNONBLK; | 
| 93 |  |  | if (fcntl(dpd[0], F_SETFL, inp_flags) < 0) | 
| 94 |  |  | goto fcntlerr; | 
| 95 |  |  | } | 
| 96 |  |  | /* read message header */ | 
| 97 |  |  | n = read(dpd[0], (char *)&msg, sizeof(MSGHEAD)); | 
| 98 |  |  | if (n != sizeof(MSGHEAD)) { | 
| 99 | gregl | 3.10 | if (n >= 0) { | 
| 100 |  |  | dpout = NULL; | 
| 101 | gregl | 3.2 | error(USER, "display process died"); | 
| 102 | gregl | 3.10 | } | 
| 103 | gregl | 3.2 | if (errno != EAGAIN & errno != EINTR) | 
| 104 |  |  | goto readerr; | 
| 105 | gregl | 3.3 | return(2);              /* acceptable failure */ | 
| 106 | gregl | 3.2 | } | 
| 107 |  |  | if (msg.nbytes) {               /* get the message body */ | 
| 108 |  |  | buf = (char *)malloc(msg.nbytes); | 
| 109 |  |  | if (buf == NULL) | 
| 110 |  |  | error(SYSTEM, "out of memory in disp_check"); | 
| 111 | gwlarson | 3.19 | if (inp_flags != 0 && fcntl(dpd[0], F_SETFL, inp_flags=0) < 0) | 
| 112 | gregl | 3.2 | goto fcntlerr; | 
| 113 |  |  | if (readbuf(dpd[0], buf, msg.nbytes) != msg.nbytes) | 
| 114 |  |  | goto readerr; | 
| 115 |  |  | } | 
| 116 |  |  | switch (msg.type) {             /* take appropriate action */ | 
| 117 | gregl | 3.12 | case DR_BUNDLE:         /* new bundle to calculate */ | 
| 118 | gregl | 3.2 | if (msg.nbytes != sizeof(PACKHEAD)) | 
| 119 |  |  | error(INTERNAL, "bad DR_BUNDLE from display process"); | 
| 120 |  |  | bundle_set(BS_ADD, (PACKHEAD *)buf, 1); | 
| 121 |  |  | break; | 
| 122 | gregl | 3.12 | case DR_NEWSET:         /* new calculation set */ | 
| 123 | gregl | 3.2 | if (msg.nbytes % sizeof(PACKHEAD)) | 
| 124 |  |  | error(INTERNAL, "bad DR_NEWSET from display process"); | 
| 125 | gwlarson | 3.19 | if (msg.nbytes) | 
| 126 |  |  | disp_result(DS_STARTIMM, 0, NULL); | 
| 127 | gregl | 3.2 | bundle_set(BS_NEW, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 128 | gwlarson | 3.19 | if (msg.nbytes) { | 
| 129 |  |  | disp_result(DS_ENDIMM, 0, NULL); | 
| 130 |  |  | disp_flush(); | 
| 131 |  |  | } | 
| 132 | gregl | 3.2 | break; | 
| 133 | gregl | 3.12 | case DR_ADDSET:         /* add to calculation set */ | 
| 134 | gwlarson | 3.19 | if (!msg.nbytes) | 
| 135 |  |  | break; | 
| 136 | gregl | 3.2 | if (msg.nbytes % sizeof(PACKHEAD)) | 
| 137 |  |  | error(INTERNAL, "bad DR_ADDSET from display process"); | 
| 138 |  |  | disp_result(DS_STARTIMM, 0, NULL); | 
| 139 |  |  | bundle_set(BS_ADD, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 140 |  |  | disp_result(DS_ENDIMM, 0, NULL); | 
| 141 | gregl | 3.15 | disp_flush(); | 
| 142 | gregl | 3.2 | break; | 
| 143 | gregl | 3.12 | case DR_ADJSET:         /* adjust calculation set members */ | 
| 144 | gwlarson | 3.19 | if (!msg.nbytes) | 
| 145 |  |  | break; | 
| 146 | gregl | 3.9 | if (msg.nbytes % sizeof(PACKHEAD)) | 
| 147 |  |  | error(INTERNAL, "bad DR_ADJSET from display process"); | 
| 148 |  |  | disp_result(DS_STARTIMM, 0, NULL); | 
| 149 |  |  | bundle_set(BS_ADJ, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 150 |  |  | disp_result(DS_ENDIMM, 0, NULL); | 
| 151 |  |  | disp_flush(); | 
| 152 |  |  | break; | 
| 153 | gregl | 3.12 | case DR_DELSET:         /* delete from calculation set */ | 
| 154 | gwlarson | 3.19 | if (!msg.nbytes) | 
| 155 |  |  | break; | 
| 156 | gregl | 3.2 | if (msg.nbytes % sizeof(PACKHEAD)) | 
| 157 |  |  | error(INTERNAL, "bad DR_DELSET from display process"); | 
| 158 |  |  | bundle_set(BS_DEL, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 159 |  |  | break; | 
| 160 | gregl | 3.12 | case DR_ATTEN:          /* block for priority request */ | 
| 161 | gregl | 3.2 | if (msg.nbytes) | 
| 162 |  |  | error(INTERNAL, "bad DR_ATTEN from display process"); | 
| 163 |  |  | /* send acknowledgement */ | 
| 164 |  |  | disp_result(DS_ACKNOW, 0, NULL); | 
| 165 | gregl | 3.3 | return(disp_check(1));  /* block on following request */ | 
| 166 | gregl | 3.13 | case DR_KILL:           /* kill computation process(es) */ | 
| 167 |  |  | if (msg.nbytes) | 
| 168 |  |  | error(INTERNAL, "bad DR_KILL from display process"); | 
| 169 | gregl | 3.14 | if (nprocs > 0) | 
| 170 |  |  | done_rtrace(); | 
| 171 |  |  | else | 
| 172 | gregl | 3.13 | error(WARNING, "no rtrace process to kill"); | 
| 173 |  |  | break; | 
| 174 |  |  | case DR_RESTART:        /* restart computation process(es) */ | 
| 175 |  |  | if (msg.nbytes) | 
| 176 |  |  | error(INTERNAL, "bad DR_RESTART from display process"); | 
| 177 | gregl | 3.14 | if (ncprocs > nprocs) | 
| 178 |  |  | new_rtrace(); | 
| 179 |  |  | else if (nprocs > 0) | 
| 180 | gregl | 3.13 | error(WARNING, "rtrace already runnning"); | 
| 181 |  |  | else | 
| 182 |  |  | error(WARNING, "holodeck not open for writing"); | 
| 183 |  |  | break; | 
| 184 |  |  | case DR_CLOBBER:        /* clobber holodeck */ | 
| 185 |  |  | if (msg.nbytes) | 
| 186 |  |  | error(INTERNAL, "bad DR_CLOBBER from display process"); | 
| 187 |  |  | if (!force || !ncprocs) | 
| 188 |  |  | error(WARNING, "request to clobber holodeck denied"); | 
| 189 |  |  | else { | 
| 190 |  |  | error(WARNING, "clobbering holodeck contents"); | 
| 191 |  |  | hdclobber(NULL); | 
| 192 |  |  | } | 
| 193 |  |  | break; | 
| 194 | gregl | 3.12 | case DR_SHUTDOWN:       /* shut down program */ | 
| 195 | gregl | 3.2 | if (msg.nbytes) | 
| 196 |  |  | error(INTERNAL, "bad DR_SHUTDOWN from display process"); | 
| 197 |  |  | return(0);              /* zero return signals shutdown */ | 
| 198 | gregl | 3.12 | case DR_NOOP:           /* do nothing */ | 
| 199 | gregl | 3.7 | break; | 
| 200 | gregl | 3.2 | default: | 
| 201 |  |  | error(INTERNAL, "unrecognized request from display process"); | 
| 202 |  |  | } | 
| 203 | gregl | 3.3 | if (msg.nbytes)                 /* clean up */ | 
| 204 | gregl | 3.2 | free(buf); | 
| 205 |  |  | return(1);                      /* normal return value */ | 
| 206 |  |  | fcntlerr: | 
| 207 |  |  | error(SYSTEM, "cannot change display blocking mode"); | 
| 208 |  |  | readerr: | 
| 209 |  |  | error(SYSTEM, "error reading from display process"); | 
| 210 | gregl | 3.1 | } | 
| 211 |  |  |  | 
| 212 |  |  |  | 
| 213 | gregl | 3.2 | int | 
| 214 |  |  | disp_close()                    /* close our display process */ | 
| 215 | gregl | 3.1 | { | 
| 216 | gregl | 3.2 | int     rval; | 
| 217 |  |  |  | 
| 218 | gregl | 3.6 | if (dpout == NULL) | 
| 219 | gregl | 3.2 | return(-1); | 
| 220 |  |  | disp_result(DS_SHUTDOWN, 0, NULL); | 
| 221 | gregl | 3.5 | fclose(dpout); | 
| 222 |  |  | dpout = NULL; | 
| 223 | gregl | 3.2 | return(close_process(dpd)); | 
| 224 |  |  | } | 
| 225 |  |  |  | 
| 226 |  |  |  | 
| 227 | gregl | 3.5 | disp_result(type, nbytes, p)    /* queue result message to display process */ | 
| 228 | gregl | 3.2 | int     type, nbytes; | 
| 229 |  |  | char    *p; | 
| 230 |  |  | { | 
| 231 |  |  | MSGHEAD msg; | 
| 232 |  |  |  | 
| 233 | gregl | 3.6 | if (dpout == NULL) | 
| 234 |  |  | return; | 
| 235 | gregl | 3.2 | msg.type = type; | 
| 236 |  |  | msg.nbytes = nbytes; | 
| 237 | gregl | 3.5 | fwrite((char *)&msg, sizeof(MSGHEAD), 1, dpout); | 
| 238 |  |  | if (nbytes > 0) | 
| 239 |  |  | fwrite(p, 1, nbytes, dpout); | 
| 240 |  |  | } | 
| 241 |  |  |  | 
| 242 |  |  |  | 
| 243 |  |  | disp_flush()                    /* flush output to display */ | 
| 244 |  |  | { | 
| 245 |  |  | if (fflush(dpout) < 0) | 
| 246 |  |  | error(SYSTEM, "error writing to the display process"); | 
| 247 | gregl | 3.1 | } |