| 1 | 
gregl | 
3.1 | 
#ifndef lint | 
| 2 | 
greg | 
3.39 | 
static const char       RCSid[] = "$Id: rholo4.c,v 3.38 2018/10/05 19:19:16 greg Exp $"; | 
| 3 | 
gregl | 
3.1 | 
#endif | 
| 4 | 
  | 
  | 
/* | 
| 5 | 
  | 
  | 
 * Holodeck display process communication | 
| 6 | 
  | 
  | 
 */ | 
| 7 | 
  | 
  | 
 | 
| 8 | 
  | 
  | 
#include "rholo.h" | 
| 9 | 
  | 
  | 
#include "rhdisp.h" | 
| 10 | 
schorsch | 
3.30 | 
#include "rtprocess.h" | 
| 11 | 
greg | 
3.33 | 
#include <sys/uio.h> | 
| 12 | 
  | 
  | 
#include <string.h> | 
| 13 | 
greg | 
3.31 | 
 | 
| 14 | 
gregl | 
3.2 | 
#ifndef HDSUF | 
| 15 | 
gwlarson | 
3.26 | 
#define HDSUF           ".hdi" | 
| 16 | 
gregl | 
3.2 | 
#endif | 
| 17 | 
gwlarson | 
3.26 | 
#ifndef SLAVENAME | 
| 18 | 
  | 
  | 
#define SLAVENAME       "slave" | 
| 19 | 
  | 
  | 
#endif | 
| 20 | 
gregl | 
3.1 | 
 | 
| 21 | 
gwlarson | 
3.21 | 
#ifndef FNONBLK | 
| 22 | 
  | 
  | 
#define FNONBLK         O_NONBLOCK | 
| 23 | 
  | 
  | 
#endif | 
| 24 | 
  | 
  | 
 | 
| 25 | 
gregl | 
3.2 | 
static int      inp_flags; | 
| 26 | 
greg | 
3.39 | 
static SUBPROC  dpd = SP_INACTIVE; | 
| 27 | 
gregl | 
3.5 | 
static FILE     *dpout; | 
| 28 | 
gregl | 
3.2 | 
 | 
| 29 | 
schorsch | 
3.36 | 
static void disp_flush(void); | 
| 30 | 
  | 
  | 
static void disp_result(int type, int nbytes, char *p); | 
| 31 | 
gregl | 
3.2 | 
 | 
| 32 | 
schorsch | 
3.36 | 
 | 
| 33 | 
greg | 
3.38 | 
void | 
| 34 | 
schorsch | 
3.36 | 
disp_open(              /* open the named display driver */ | 
| 35 | 
  | 
  | 
        char    *dname | 
| 36 | 
  | 
  | 
) | 
| 37 | 
gregl | 
3.1 | 
{ | 
| 38 | 
gwlarson | 
3.25 | 
        char    buf[sizeof(HDGRID)+512], fd0[8], fd1[8], *cmd[5], *sfn; | 
| 39 | 
gwlarson | 
3.24 | 
        int     i, n, len; | 
| 40 | 
gwlarson | 
3.26 | 
 | 
| 41 | 
  | 
  | 
        if (!strcmp(dname, SLAVENAME)) { | 
| 42 | 
schorsch | 
3.30 | 
                dpd.r = 0;              /* read from stdin */ | 
| 43 | 
gwlarson | 
3.26 | 
                dpout = stdout;         /* write to stdout */ | 
| 44 | 
greg | 
3.39 | 
                dpd.flags = 0;          /* we're the slave procees */ | 
| 45 | 
gwlarson | 
3.26 | 
        } else { | 
| 46 | 
  | 
  | 
                                        /* get full display program name */ | 
| 47 | 
gregl | 
3.2 | 
#ifdef DEVPATH | 
| 48 | 
gwlarson | 
3.26 | 
                sprintf(buf, "%s/%s%s", DEVPATH, dname, HDSUF); | 
| 49 | 
gregl | 
3.2 | 
#else | 
| 50 | 
gwlarson | 
3.26 | 
                sprintf(buf, "dev/%s%s", dname, HDSUF); | 
| 51 | 
gregl | 
3.2 | 
#endif | 
| 52 | 
gwlarson | 
3.26 | 
                                        /* dup stdin and stdout */ | 
| 53 | 
  | 
  | 
                if (readinp) | 
| 54 | 
  | 
  | 
                        sprintf(fd0, "%d", dup(0)); | 
| 55 | 
  | 
  | 
                else | 
| 56 | 
  | 
  | 
                        strcpy(fd0, "-1"); | 
| 57 | 
  | 
  | 
                sprintf(fd1, "%d", dup(1)); | 
| 58 | 
  | 
  | 
                                        /* start the display process */ | 
| 59 | 
  | 
  | 
                cmd[0] = buf; | 
| 60 | 
  | 
  | 
                cmd[1] = froot; cmd[2] = fd1; cmd[3] = fd0; | 
| 61 | 
  | 
  | 
                cmd[4] = NULL; | 
| 62 | 
schorsch | 
3.30 | 
                i = open_process(&dpd, cmd); | 
| 63 | 
gwlarson | 
3.26 | 
                if (i <= 0) | 
| 64 | 
  | 
  | 
                        error(USER, "cannot start display process"); | 
| 65 | 
schorsch | 
3.30 | 
                if ((dpout = fdopen(dpd.w, "w")) == NULL) | 
| 66 | 
gwlarson | 
3.26 | 
                        error(SYSTEM, "problem opening display pipe"); | 
| 67 | 
  | 
  | 
                                        /* close dup'ed stdin and stdout */ | 
| 68 | 
  | 
  | 
                if (readinp) | 
| 69 | 
  | 
  | 
                        close(atoi(fd0)); | 
| 70 | 
  | 
  | 
                close(atoi(fd1)); | 
| 71 | 
  | 
  | 
        } | 
| 72 | 
schorsch | 
3.30 | 
        dpd.w = -1;             /* causes ignored error in close_process() */ | 
| 73 | 
gregl | 
3.2 | 
        inp_flags = 0; | 
| 74 | 
gregl | 
3.17 | 
                                /* check if outside */ | 
| 75 | 
  | 
  | 
        if (vdef(OBSTRUCTIONS) && vbool(OBSTRUCTIONS)) | 
| 76 | 
  | 
  | 
                disp_result(DS_OUTSECT, 0, NULL); | 
| 77 | 
gwlarson | 
3.18 | 
                                /* send eye separation if specified */ | 
| 78 | 
  | 
  | 
        if (vdef(EYESEP)) { | 
| 79 | 
gwlarson | 
3.23 | 
                sprintf(buf, "%.9e", vflt(EYESEP)); | 
| 80 | 
  | 
  | 
                disp_result(DS_EYESEP, strlen(buf)+1, buf); | 
| 81 | 
gwlarson | 
3.18 | 
        } | 
| 82 | 
gwlarson | 
3.23 | 
                                /* write out hologram grids & octrees */ | 
| 83 | 
  | 
  | 
        for (i = 0; hdlist[i] != NULL; i++) { | 
| 84 | 
schorsch | 
3.32 | 
                memcpy(buf, (void *)hdlist[i], sizeof(HDGRID)); | 
| 85 | 
gwlarson | 
3.24 | 
                len = sizeof(HDGRID); | 
| 86 | 
  | 
  | 
                n = vdef(GEOMETRY); | 
| 87 | 
  | 
  | 
                sfn = i<n ? nvalue(GEOMETRY,i) : | 
| 88 | 
  | 
  | 
                                n ? nvalue(GEOMETRY,n-1) : vval(OCTREE); | 
| 89 | 
  | 
  | 
                strcpy(buf+len, sfn); | 
| 90 | 
  | 
  | 
                len += strlen(sfn) + 1; | 
| 91 | 
  | 
  | 
                n = vdef(PORTS); | 
| 92 | 
  | 
  | 
                sfn = i<n ? nvalue(PORTS,i) : n ? nvalue(PORTS,n-1) : ""; | 
| 93 | 
  | 
  | 
                strcpy(buf+len, sfn); | 
| 94 | 
  | 
  | 
                len += strlen(sfn) + 1; | 
| 95 | 
  | 
  | 
                disp_result(DS_ADDHOLO, len, buf); | 
| 96 | 
gwlarson | 
3.23 | 
        } | 
| 97 | 
gregl | 
3.5 | 
        disp_flush(); | 
| 98 | 
gregl | 
3.1 | 
} | 
| 99 | 
  | 
  | 
 | 
| 100 | 
  | 
  | 
 | 
| 101 | 
greg | 
3.38 | 
void | 
| 102 | 
schorsch | 
3.36 | 
disp_packet(                    /* display a packet */ | 
| 103 | 
greg | 
3.38 | 
        PACKHEAD        *p | 
| 104 | 
schorsch | 
3.36 | 
) | 
| 105 | 
gregl | 
3.2 | 
{ | 
| 106 | 
gregl | 
3.4 | 
        disp_result(DS_BUNDLE, packsiz(p->nr), (char *)p); | 
| 107 | 
gregl | 
3.2 | 
} | 
| 108 | 
  | 
  | 
 | 
| 109 | 
  | 
  | 
 | 
| 110 | 
greg | 
3.38 | 
int | 
| 111 | 
schorsch | 
3.36 | 
disp_check(             /* check display process */ | 
| 112 | 
  | 
  | 
        int     block | 
| 113 | 
  | 
  | 
) | 
| 114 | 
gregl | 
3.1 | 
{ | 
| 115 | 
gregl | 
3.2 | 
        MSGHEAD msg; | 
| 116 | 
  | 
  | 
        int     n; | 
| 117 | 
  | 
  | 
        char    *buf = NULL; | 
| 118 | 
  | 
  | 
 | 
| 119 | 
gregl | 
3.6 | 
        if (dpout == NULL) | 
| 120 | 
gregl | 
3.2 | 
                return(-1); | 
| 121 | 
gregl | 
3.5 | 
                                        /* flush display output */ | 
| 122 | 
  | 
  | 
        disp_flush(); | 
| 123 | 
gregl | 
3.3 | 
                                        /* check read blocking */ | 
| 124 | 
gregl | 
3.2 | 
        if (block != (inp_flags == 0)) { | 
| 125 | 
  | 
  | 
                inp_flags = block ? 0 : FNONBLK; | 
| 126 | 
schorsch | 
3.30 | 
                if (fcntl(dpd.r, F_SETFL, inp_flags) < 0) | 
| 127 | 
gregl | 
3.2 | 
                        goto fcntlerr; | 
| 128 | 
  | 
  | 
        } | 
| 129 | 
  | 
  | 
                                        /* read message header */ | 
| 130 | 
schorsch | 
3.30 | 
        n = read(dpd.r, (char *)&msg, sizeof(MSGHEAD)); | 
| 131 | 
gregl | 
3.2 | 
        if (n != sizeof(MSGHEAD)) { | 
| 132 | 
gregl | 
3.10 | 
                if (n >= 0) { | 
| 133 | 
  | 
  | 
                        dpout = NULL; | 
| 134 | 
gregl | 
3.2 | 
                        error(USER, "display process died"); | 
| 135 | 
gregl | 
3.10 | 
                } | 
| 136 | 
schorsch | 
3.35 | 
                if ((errno != EAGAIN) & (errno != EINTR)) | 
| 137 | 
gregl | 
3.2 | 
                        goto readerr; | 
| 138 | 
gregl | 
3.3 | 
                return(2);              /* acceptable failure */ | 
| 139 | 
gregl | 
3.2 | 
        } | 
| 140 | 
  | 
  | 
        if (msg.nbytes) {               /* get the message body */ | 
| 141 | 
gwlarson | 
3.20 | 
                if (msg.nbytes < 0) | 
| 142 | 
  | 
  | 
                        error(INTERNAL, "anti-message from display process"); | 
| 143 | 
gregl | 
3.2 | 
                buf = (char *)malloc(msg.nbytes); | 
| 144 | 
  | 
  | 
                if (buf == NULL) | 
| 145 | 
  | 
  | 
                        error(SYSTEM, "out of memory in disp_check"); | 
| 146 | 
schorsch | 
3.30 | 
                if (inp_flags != 0 && fcntl(dpd.r, F_SETFL, inp_flags=0) < 0) | 
| 147 | 
gregl | 
3.2 | 
                        goto fcntlerr; | 
| 148 | 
schorsch | 
3.30 | 
                if (readbuf(dpd.r, buf, msg.nbytes) != msg.nbytes) | 
| 149 | 
gregl | 
3.2 | 
                        goto readerr; | 
| 150 | 
  | 
  | 
        } | 
| 151 | 
  | 
  | 
        switch (msg.type) {             /* take appropriate action */ | 
| 152 | 
gregl | 
3.12 | 
        case DR_BUNDLE:         /* new bundle to calculate */ | 
| 153 | 
gregl | 
3.2 | 
                if (msg.nbytes != sizeof(PACKHEAD)) | 
| 154 | 
  | 
  | 
                        error(INTERNAL, "bad DR_BUNDLE from display process"); | 
| 155 | 
  | 
  | 
                bundle_set(BS_ADD, (PACKHEAD *)buf, 1); | 
| 156 | 
  | 
  | 
                break; | 
| 157 | 
gregl | 
3.12 | 
        case DR_NEWSET:         /* new calculation set */ | 
| 158 | 
gregl | 
3.2 | 
                if (msg.nbytes % sizeof(PACKHEAD)) | 
| 159 | 
  | 
  | 
                        error(INTERNAL, "bad DR_NEWSET from display process"); | 
| 160 | 
gwlarson | 
3.19 | 
                if (msg.nbytes) | 
| 161 | 
  | 
  | 
                        disp_result(DS_STARTIMM, 0, NULL); | 
| 162 | 
gregl | 
3.2 | 
                bundle_set(BS_NEW, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 163 | 
gwlarson | 
3.19 | 
                if (msg.nbytes) { | 
| 164 | 
  | 
  | 
                        disp_result(DS_ENDIMM, 0, NULL); | 
| 165 | 
  | 
  | 
                        disp_flush(); | 
| 166 | 
  | 
  | 
                } | 
| 167 | 
gregl | 
3.2 | 
                break; | 
| 168 | 
gregl | 
3.12 | 
        case DR_ADDSET:         /* add to calculation set */ | 
| 169 | 
gwlarson | 
3.19 | 
                if (!msg.nbytes) | 
| 170 | 
  | 
  | 
                        break; | 
| 171 | 
gregl | 
3.2 | 
                if (msg.nbytes % sizeof(PACKHEAD)) | 
| 172 | 
  | 
  | 
                        error(INTERNAL, "bad DR_ADDSET from display process"); | 
| 173 | 
  | 
  | 
                disp_result(DS_STARTIMM, 0, NULL); | 
| 174 | 
  | 
  | 
                bundle_set(BS_ADD, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 175 | 
  | 
  | 
                disp_result(DS_ENDIMM, 0, NULL); | 
| 176 | 
gregl | 
3.15 | 
                disp_flush(); | 
| 177 | 
gregl | 
3.2 | 
                break; | 
| 178 | 
gregl | 
3.12 | 
        case DR_ADJSET:         /* adjust calculation set members */ | 
| 179 | 
gwlarson | 
3.19 | 
                if (!msg.nbytes) | 
| 180 | 
  | 
  | 
                        break; | 
| 181 | 
gregl | 
3.9 | 
                if (msg.nbytes % sizeof(PACKHEAD)) | 
| 182 | 
  | 
  | 
                        error(INTERNAL, "bad DR_ADJSET from display process"); | 
| 183 | 
  | 
  | 
                disp_result(DS_STARTIMM, 0, NULL); | 
| 184 | 
  | 
  | 
                bundle_set(BS_ADJ, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 185 | 
  | 
  | 
                disp_result(DS_ENDIMM, 0, NULL); | 
| 186 | 
  | 
  | 
                disp_flush(); | 
| 187 | 
  | 
  | 
                break; | 
| 188 | 
gregl | 
3.12 | 
        case DR_DELSET:         /* delete from calculation set */ | 
| 189 | 
gwlarson | 
3.19 | 
                if (!msg.nbytes) | 
| 190 | 
  | 
  | 
                        break; | 
| 191 | 
gregl | 
3.2 | 
                if (msg.nbytes % sizeof(PACKHEAD)) | 
| 192 | 
  | 
  | 
                        error(INTERNAL, "bad DR_DELSET from display process"); | 
| 193 | 
  | 
  | 
                bundle_set(BS_DEL, (PACKHEAD *)buf, msg.nbytes/sizeof(PACKHEAD)); | 
| 194 | 
  | 
  | 
                break; | 
| 195 | 
gwlarson | 
3.22 | 
        case DR_VIEWPOINT:      /* set target eye position */ | 
| 196 | 
  | 
  | 
                if (msg.nbytes != sizeof(VIEWPOINT)) | 
| 197 | 
  | 
  | 
                        error(INTERNAL, "bad DR_VIEWPOINT from display process"); | 
| 198 | 
schorsch | 
3.34 | 
                myeye = *((VIEWPOINT *)buf); | 
| 199 | 
gwlarson | 
3.22 | 
                break; | 
| 200 | 
gregl | 
3.12 | 
        case DR_ATTEN:          /* block for priority request */ | 
| 201 | 
gregl | 
3.2 | 
                if (msg.nbytes) | 
| 202 | 
  | 
  | 
                        error(INTERNAL, "bad DR_ATTEN from display process"); | 
| 203 | 
  | 
  | 
                                        /* send acknowledgement */ | 
| 204 | 
  | 
  | 
                disp_result(DS_ACKNOW, 0, NULL); | 
| 205 | 
gregl | 
3.3 | 
                return(disp_check(1));  /* block on following request */ | 
| 206 | 
gregl | 
3.13 | 
        case DR_KILL:           /* kill computation process(es) */ | 
| 207 | 
  | 
  | 
                if (msg.nbytes) | 
| 208 | 
  | 
  | 
                        error(INTERNAL, "bad DR_KILL from display process"); | 
| 209 | 
gregl | 
3.14 | 
                if (nprocs > 0) | 
| 210 | 
  | 
  | 
                        done_rtrace(); | 
| 211 | 
  | 
  | 
                else | 
| 212 | 
gregl | 
3.13 | 
                        error(WARNING, "no rtrace process to kill"); | 
| 213 | 
  | 
  | 
                break; | 
| 214 | 
  | 
  | 
        case DR_RESTART:        /* restart computation process(es) */ | 
| 215 | 
  | 
  | 
                if (msg.nbytes) | 
| 216 | 
  | 
  | 
                        error(INTERNAL, "bad DR_RESTART from display process"); | 
| 217 | 
gregl | 
3.14 | 
                if (ncprocs > nprocs) | 
| 218 | 
  | 
  | 
                        new_rtrace(); | 
| 219 | 
  | 
  | 
                else if (nprocs > 0) | 
| 220 | 
gregl | 
3.13 | 
                        error(WARNING, "rtrace already runnning"); | 
| 221 | 
  | 
  | 
                else | 
| 222 | 
  | 
  | 
                        error(WARNING, "holodeck not open for writing"); | 
| 223 | 
  | 
  | 
                break; | 
| 224 | 
  | 
  | 
        case DR_CLOBBER:        /* clobber holodeck */ | 
| 225 | 
  | 
  | 
                if (msg.nbytes) | 
| 226 | 
  | 
  | 
                        error(INTERNAL, "bad DR_CLOBBER from display process"); | 
| 227 | 
schorsch | 
3.35 | 
                if ((force <= 0) | (ncprocs <= 0)) | 
| 228 | 
gregl | 
3.13 | 
                        error(WARNING, "request to clobber holodeck denied"); | 
| 229 | 
  | 
  | 
                else { | 
| 230 | 
  | 
  | 
                        error(WARNING, "clobbering holodeck contents"); | 
| 231 | 
  | 
  | 
                        hdclobber(NULL); | 
| 232 | 
  | 
  | 
                } | 
| 233 | 
  | 
  | 
                break; | 
| 234 | 
gregl | 
3.12 | 
        case DR_SHUTDOWN:       /* shut down program */ | 
| 235 | 
gregl | 
3.2 | 
                if (msg.nbytes) | 
| 236 | 
  | 
  | 
                        error(INTERNAL, "bad DR_SHUTDOWN from display process"); | 
| 237 | 
  | 
  | 
                return(0);              /* zero return signals shutdown */ | 
| 238 | 
gregl | 
3.12 | 
        case DR_NOOP:           /* do nothing */ | 
| 239 | 
gregl | 
3.7 | 
                break; | 
| 240 | 
gregl | 
3.2 | 
        default: | 
| 241 | 
  | 
  | 
                error(INTERNAL, "unrecognized request from display process"); | 
| 242 | 
  | 
  | 
        } | 
| 243 | 
gregl | 
3.3 | 
        if (msg.nbytes)                 /* clean up */ | 
| 244 | 
gregl | 
3.2 | 
                free(buf); | 
| 245 | 
  | 
  | 
        return(1);                      /* normal return value */ | 
| 246 | 
  | 
  | 
fcntlerr: | 
| 247 | 
  | 
  | 
        error(SYSTEM, "cannot change display blocking mode"); | 
| 248 | 
  | 
  | 
readerr: | 
| 249 | 
  | 
  | 
        error(SYSTEM, "error reading from display process"); | 
| 250 | 
schorsch | 
3.36 | 
        return -1; /* pro forma return */ | 
| 251 | 
gregl | 
3.1 | 
} | 
| 252 | 
  | 
  | 
 | 
| 253 | 
  | 
  | 
 | 
| 254 | 
greg | 
3.38 | 
int | 
| 255 | 
schorsch | 
3.36 | 
disp_close(void)                        /* close our display process */ | 
| 256 | 
gregl | 
3.1 | 
{ | 
| 257 | 
gregl | 
3.6 | 
        if (dpout == NULL) | 
| 258 | 
gregl | 
3.2 | 
                return(-1); | 
| 259 | 
gwlarson | 
3.23 | 
        myeye.rng = 0; | 
| 260 | 
gregl | 
3.2 | 
        disp_result(DS_SHUTDOWN, 0, NULL); | 
| 261 | 
gregl | 
3.5 | 
        fclose(dpout); | 
| 262 | 
  | 
  | 
        dpout = NULL; | 
| 263 | 
greg | 
3.39 | 
        return(dpd.flags&PF_RUNNING ? close_process(&dpd) : 0); | 
| 264 | 
schorsch | 
3.30 | 
 | 
| 265 | 
gregl | 
3.2 | 
} | 
| 266 | 
  | 
  | 
 | 
| 267 | 
  | 
  | 
 | 
| 268 | 
schorsch | 
3.36 | 
static void | 
| 269 | 
  | 
  | 
disp_result(    /* queue result message to display process */ | 
| 270 | 
  | 
  | 
        int     type, | 
| 271 | 
  | 
  | 
        int     nbytes, | 
| 272 | 
  | 
  | 
        char    *p | 
| 273 | 
  | 
  | 
) | 
| 274 | 
gregl | 
3.2 | 
{ | 
| 275 | 
  | 
  | 
        MSGHEAD msg; | 
| 276 | 
gwlarson | 
3.20 | 
                                        /* consistency checks */ | 
| 277 | 
  | 
  | 
#ifdef DEBUG | 
| 278 | 
  | 
  | 
        if (nbytes < 0 || nbytes > 0 & p == NULL) | 
| 279 | 
  | 
  | 
                error(CONSISTENCY, "bad buffer handed to disp_result"); | 
| 280 | 
  | 
  | 
#endif | 
| 281 | 
gregl | 
3.6 | 
        if (dpout == NULL) | 
| 282 | 
  | 
  | 
                return; | 
| 283 | 
gregl | 
3.2 | 
        msg.type = type; | 
| 284 | 
  | 
  | 
        msg.nbytes = nbytes; | 
| 285 | 
greg | 
3.37 | 
        putbinary(&msg, sizeof(MSGHEAD), 1, dpout); | 
| 286 | 
gregl | 
3.5 | 
        if (nbytes > 0) | 
| 287 | 
greg | 
3.37 | 
                putbinary(p, 1, nbytes, dpout); | 
| 288 | 
gregl | 
3.5 | 
} | 
| 289 | 
  | 
  | 
 | 
| 290 | 
  | 
  | 
 | 
| 291 | 
schorsch | 
3.36 | 
static void | 
| 292 | 
  | 
  | 
disp_flush(void)                        /* flush output to display */ | 
| 293 | 
gregl | 
3.5 | 
{ | 
| 294 | 
  | 
  | 
        if (fflush(dpout) < 0) | 
| 295 | 
  | 
  | 
                error(SYSTEM, "error writing to the display process"); | 
| 296 | 
gregl | 
3.1 | 
} |