1 /* DYNGUI.C     (c) Copyright "Fish" (David B. Trout), 2003-2014     */
2 /*              Hercules External GUI Interface DLL                  */
3 
4 #include "hstdinc.h"
5 #include "hercules.h"       // (#includes "config." w/#define for VERSION)
6 
7 #ifdef EXTERNALGUI
8 
9 #if defined(OPTION_DYNAMIC_LOAD)
10 
11 #include "devtype.h"
12 #include "opcode.h"
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 // Some handy macros...       (feel free to add these to hercules.h)
16 
17 #ifndef BOOL
18 #define BOOL  BYTE
19 #endif
20 #ifndef FALSE
21 #define FALSE   0
22 #endif
23 #ifndef TRUE
24 #define TRUE    1
25 #endif
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 // Our global variables...    (initialized by our "Initialize" function)
29 
30 #define  INPUT_STREAM_FILE_PTR    ( stdin  )
31 #define  OUTPUT_STREAM_FILE_PTR   ( stdout )
32 #define  STATUS_STREAM_FILE_PTR   ( stderr )
33 #define  MAX_COMMAND_LEN          (  1024  )
34 #define  DEF_MAXRATES_RPT_INTVL   (  1440  )
35 
36 #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL )
37 #if !defined( _MSVC_ )
38   SYSBLK            *psysblk;                  // (ptr to Herc's SYSBLK structure)
39   #define  sysblk  (*psysblk)
40 #endif
41 #endif
42 
43 static FILE*    fOutputStream        = NULL;   // (stdout stream)
44 static FILE*    fStatusStream        = NULL;   // (stderr stream)
45 static int      nInputStreamFileNum  =  -1;    // (file descriptor for stdin stream)
46 static int      gui_nounload         =   1;    // (nounload indicator)
47 
48 // The device query buffer SHOULD be the maximum device filename length
49 // plus the maximum descriptive length of any/all options for the device,
50 // but there is no #define for either so we have no choice but to impose
51 // our own maximum.
52 
53 #define  MAX_DEVICEQUERY_LEN      ( 1024 + 256 )
54 
55 ///////////////////////////////////////////////////////////////////////////////
56 // Some forward references...   (our own functions that we call)
57 
58 void  Initialize         ();
59 void  ProcessingLoop     ();
60 void  Cleanup            ();
61 void  UpdateTargetCPU    ();
62 void  ReadInputData      (int nTimeoutMillsecs);
63 void  ProcessInputData   ();
64 void* gui_panel_command  (char* pszCommand);
65 void  UpdateStatus       ();
66 void  HandleForcedRefresh();
67 void  UpdateCPUStatus    ();
68 void  UpdateRegisters    ();
69 void  UpdateDeviceStatus ();
70 void  NewUpdateDevStats  ();
71 
72 void  gui_fprintf( FILE* stream, const char* pszFormat, ... );
73 
74 ///////////////////////////////////////////////////////////////////////////////
75 // Our main processing loop...
76 
77 BOOL bDoneProcessing = FALSE;       // (set to TRUE to exit)
78 
ProcessingLoop()79 void ProcessingLoop()
80 {
81     // Notify logger_thread we're in control
82 
83     sysblk.panel_init = 1;
84 
85     // Our main purpose in life: read input stream and process
86     // any commands that may be entered, and send periodic status
87     // information back to the external gui via its status stream.
88 
89     // Note we only exit whenever our bDoneProcessing flag is set
90     // which is normally not done until just before Herc unloads
91     // us which is normally not done until immediately before it
92     // terminates.
93 
94     // Also note we re-retrieve sysblk.panrate each iteration
95     // since it could change from one iteration to the next as a result
96     // of the Hercules "panrate" command being entered and processed.
97 
98     while (!bDoneProcessing)
99     {
100         UpdateTargetCPU();      // ("cpu" command could have changed it)
101         UpdateStatus();         // (keep sending status back to gui...)
102 
103         ReadInputData( sysblk.panrate );
104 
105         ProcessInputData();     // (if there even is any of course...)
106     }
107 }
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 
111 int     pcpu                = INT_MAX;  // target cpu# for commands and displays
112 REGS*   pTargetCPU_REGS     = NULL;     // pointer to target cpu REGS
113 
114 int     prev_pcpu           = INT_MAX;  // (previous value)
115 REGS*   pPrevTargetCPU_REGS = NULL;     // (previous value)
116 
117 REGS    copyregs;                       // (copy of active cpu's REGS)
118 REGS    copysieregs;                    // (same but when in SIE mode)
119 REGS*   CopyREGS( int cpu );            // (fwd ref)
120 
121 ///////////////////////////////////////////////////////////////////////////////
122 
UpdateTargetCPU()123 void  UpdateTargetCPU ()
124 {
125     if (!sysblk.shutdown)
126         pTargetCPU_REGS = CopyREGS( pcpu = sysblk.pcpu );
127 }
128 
129 ///////////////////////////////////////////////////////////////////////////////
130 // (get non-moving/non-dynamic working copy of active cpu's register context)
131 
CopyREGS(int cpu)132 REGS* CopyREGS( int cpu )               // (same logic as in panel.c)
133 {
134     REGS* regs;
135 
136     if (cpu < 0 || cpu >= sysblk.maxcpu)
137         cpu = 0;
138 
139     obtain_lock( &sysblk.cpulock[cpu] );
140 
141     if (!(regs = sysblk.regs[cpu]))
142     {
143         release_lock( &sysblk.cpulock[cpu] );
144         return &sysblk.dummyregs;
145     }
146 
147     memcpy( &copyregs, regs, sysblk.regs_copy_len );
148 
149     if (!copyregs.hostregs)
150     {
151         release_lock(&sysblk.cpulock[cpu]);
152         return &sysblk.dummyregs;
153     }
154 
155 #if defined(_FEATURE_SIE)
156     if (regs->sie_active)
157     {
158         memcpy( &copysieregs, regs->guestregs, sysblk.regs_copy_len );
159         copyregs.guestregs = &copysieregs;
160         copysieregs.hostregs = &copyregs;
161         regs = &copysieregs;
162     }
163     else
164 #endif
165         regs = &copyregs;
166 
167     SET_PSW_IA( regs );
168 
169     release_lock( &sysblk.cpulock[cpu] );
170     return regs;
171 }
172 
173 ///////////////////////////////////////////////////////////////////////////////
174 
175 char*  pszInputBuff    = NULL;                  // ptr to buffer
176 int    nInputBuffSize  = (MAX_COMMAND_LEN+1);   // how big the buffer is
177 int    nInputLen       = 0;                     // amount of data it's holding
178 
179 ///////////////////////////////////////////////////////////////////////////////
180 
ReadInputData(int nTimeoutMillsecs)181 void ReadInputData ( int nTimeoutMillsecs )
182 {
183     size_t  nMaxBytesToRead;
184     int     nBytesRead;
185     char*   pReadBuffer;
186 
187     // Wait for keyboard input data to arrive...
188 
189 #if !defined( _MSVC_ )
190 
191     fd_set          input_fd_set;
192     struct timeval  wait_interval_timeval;
193     int             rc;
194 
195     FD_ZERO ( &input_fd_set );
196     FD_SET  ( nInputStreamFileNum, &input_fd_set );
197 
198     wait_interval_timeval.tv_sec  =  nTimeoutMillsecs / 1000;
199     wait_interval_timeval.tv_usec = (nTimeoutMillsecs % 1000) * 1000;
200 
201     if ((rc = select( nInputStreamFileNum+1, &input_fd_set, NULL, NULL, &wait_interval_timeval )) < 0)
202     {
203         if (HSO_EINTR == HSO_errno)
204             return;             // (we were interrupted by a signal)
205 
206         // A bona fide error occurred; abort...
207 
208         logmsg
209         (
210             _("HHCDG003S select failed on input stream: %s\n")
211 
212             ,strerror(HSO_errno)
213         );
214 
215         bDoneProcessing = TRUE;     // (force main loop to exit)
216         return;
217     }
218 
219     // Has keyboard input data indeed arrived yet?
220 
221     if (!FD_ISSET( nInputStreamFileNum, &input_fd_set ))
222         return;     // (nothing for us to do...)
223 
224 #endif // !defined( _MSVC_ )
225 
226     // Ensure our buffer never overflows... (-2 because
227     // we need room for at least 1 byte + NULL terminator)
228 
229     MINMAX(nInputLen,0,(nInputBuffSize-2));
230 
231     // Read input data into next available buffer location...
232     // (nMaxBytesToRead-1 == room for NULL terminator)
233 
234     pReadBuffer     = (pszInputBuff   + nInputLen);
235     nMaxBytesToRead = (nInputBuffSize - nInputLen) - 1;
236 
237 #if !defined( _MSVC_ )
238 
239     if ((nBytesRead = read( nInputStreamFileNum, pReadBuffer, nMaxBytesToRead )) < 0)
240     {
241         if (EINTR == errno)
242             return;             // (we were interrupted by a signal)
243 
244         // A bona fide error occurred; abort...
245 
246         logmsg
247         (
248             _("HHCDG004S read failed on input stream: %s\n")
249 
250             ,strerror(errno)
251         );
252 
253         bDoneProcessing = TRUE;     // (force main loop to exit)
254         return;
255     }
256 
257 #else // defined( _MSVC_ )
258 
259     if ( ( nBytesRead = w32_get_stdin_char( pReadBuffer, nTimeoutMillsecs ) ) <= 0 )
260         return;
261 
262 #endif // !defined( _MSVC_ )
263 
264     // Update amount of input data we have and
265     // ensure that it's always NULL terminated...
266 
267     MINMAX(nBytesRead,0,nInputBuffSize);
268     nInputLen += nBytesRead;
269     MINMAX(nInputLen,0,(nInputBuffSize-1));
270     *(pszInputBuff + nInputLen) = 0;
271 }
272 
273 ///////////////////////////////////////////////////////////////////////////////
274 
275 char*  pszCommandBuff    = NULL;                // ptr to buffer
276 int    nCommandBuffSize  = (MAX_COMMAND_LEN+1); // how big the buffer is
277 int    nCommandLen       = 0;                   // amount of data it's holding
278 
279 ///////////////////////////////////////////////////////////////////////////////
280 // Process the data we just read from the input stream...
281 
ProcessInputData()282 void  ProcessInputData ()
283 {
284     char*  pNewLineChar;
285 
286     // Ensure our buffer is NULL terminated...
287 
288     MINMAX(nInputLen,0,(nInputBuffSize-1));
289     *(pszInputBuff + nInputLen) = 0;
290 
291     // Input commands are delimited by newline characters...
292 
293     while (nInputLen && (pNewLineChar = strchr(pszInputBuff,'\n')) != NULL)
294     {
295         // Extract command from input buffer
296         // into our command processing buffer...
297 
298         nCommandLen = (pNewLineChar - pszInputBuff);
299         MINMAX(nCommandLen,0,(nCommandBuffSize-1));
300         memcpy(pszCommandBuff, pszInputBuff, nCommandLen);
301         *(pszCommandBuff + nCommandLen) = 0;
302 
303         // Process the extracted command...
304 
305         // Note that we always call the registered "panel_command" function
306         // rather than call our "gui_panel_command" function directly. This
307         // is in case some other DLL has overridden OUR command handler...
308 
309         panel_command ( pszCommandBuff );   // (call registered handler)
310 
311         // Shift remaining data back to beginning of input buffer...
312 
313         nInputLen = ((pszInputBuff + nInputLen) - (pNewLineChar+1));
314         MINMAX(nInputLen,0,(nInputBuffSize-1));
315         memmove(pszInputBuff,pNewLineChar+1,nInputLen);
316         *(pszInputBuff + nInputLen) = 0;
317     }
318 }
319 
320 ///////////////////////////////////////////////////////////////////////////////
321 // (These are actually boolean flags..)
322 
323 double gui_version           = 0.0;     // (version of HercGUI we're talking to)
324 
325 BYTE   gui_forced_refresh    = 1;       // (force initial update refresh)
326 
327 BYTE   gui_wants_gregs       = 0;
328 BYTE   gui_wants_gregs64     = 0;
329 BYTE   gui_wants_cregs       = 0;
330 BYTE   gui_wants_cregs64     = 0;
331 BYTE   gui_wants_aregs       = 0;
332 BYTE   gui_wants_fregs       = 0;
333 BYTE   gui_wants_fregs64     = 0;
334 BYTE   gui_wants_devlist     = 0;
335 BYTE   gui_wants_new_devlist = 1;       // (should always be initially on)
336 #if defined(OPTION_MIPS_COUNTING)
337 BYTE   gui_wants_aggregates  = 1;
338 BYTE   gui_wants_cpupct      = 0;
339 BYTE   gui_wants_cpupct_all  = 0;
340 int    prev_cpupct    [ MAX_CPU_ENGINES ];
341 U32    prev_mips_rate  = 0;
342 U32    prev_sios_rate  = 0;
343 #endif // defined(OPTION_MIPS_COUNTING)
344 
345 ///////////////////////////////////////////////////////////////////////////////
346 // Our Hercules "panel_command" override...
347 
gui_panel_command(char * pszCommand)348 void*  gui_panel_command (char* pszCommand)
349 {
350     void* (*next_panel_command_handler)(char* pszCommand);
351 
352     // Special GUI commands start with ']'. At the moment, all these special
353     // gui commands tell us is what status information it's interested in...
354 
355     if ( ']' != *pszCommand )
356         goto NotSpecialGUICommand;
357 
358     gui_forced_refresh = 1;                         // (forced update refresh)
359 
360     pszCommand++;                                   // (bump past ']')
361 
362     if (strncasecmp(pszCommand,"VERS=",5) == 0)
363     {
364         gui_version = atof(pszCommand+5);
365         return NULL;
366     }
367 
368     if (strncasecmp(pszCommand,"SCD=",4) == 0)
369     {
370         // (set current directory)
371         if (chdir(pszCommand+4) != 0)
372         {
373             // (inform gui of error)
374             char *cwd = getcwd( NULL, 0 );
375             if (cwd)
376             {
377                 debug_cd_cmd( cwd );
378                 free( cwd );
379             }
380         }
381         return NULL;
382     }
383 
384     if (strncasecmp(pszCommand,"GREGS=",6) == 0)
385     {
386         gui_wants_gregs = atoi(pszCommand+6);
387         return NULL;
388     }
389 
390     if (strncasecmp(pszCommand,"GREGS64=",8) == 0)
391     {
392         gui_wants_gregs64 = atoi(pszCommand+8);
393         return NULL;
394     }
395 
396     if (strncasecmp(pszCommand,"CREGS=",6) == 0)
397     {
398         gui_wants_cregs = atoi(pszCommand+6);
399         return NULL;
400     }
401 
402     if (strncasecmp(pszCommand,"CREGS64=",8) == 0)
403     {
404         gui_wants_cregs64 = atoi(pszCommand+8);
405         return NULL;
406     }
407 
408     if (strncasecmp(pszCommand,"AREGS=",6) == 0)
409     {
410         gui_wants_aregs = atoi(pszCommand+6);
411         return NULL;
412     }
413 
414     if (strncasecmp(pszCommand,"FREGS=",6) == 0)
415     {
416         gui_wants_fregs = atoi(pszCommand+6);
417         return NULL;
418     }
419 
420     if (strncasecmp(pszCommand,"FREGS64=",8) == 0)
421     {
422         gui_wants_fregs64 = atoi(pszCommand+8);
423         return NULL;
424     }
425 
426     if (strncasecmp(pszCommand,"DEVLIST=",8) == 0)
427     {
428         gui_wants_devlist = atoi(pszCommand+8);
429         if ( gui_wants_devlist )
430             gui_wants_new_devlist = 0;
431         return NULL;
432     }
433 
434     if (strncasecmp(pszCommand,"NEWDEVLIST=",11) == 0)
435     {
436         gui_wants_new_devlist = atoi(pszCommand+11);
437         if ( gui_wants_new_devlist )
438             gui_wants_devlist = 0;
439         return NULL;
440     }
441 
442     if (strncasecmp(pszCommand,"MAINSTOR=",9) == 0)
443     {
444         gui_fprintf(fStatusStream,"MAINSTOR=%"UINT_PTR_FMT"d\n",(uintptr_t)pTargetCPU_REGS->mainstor);
445 
446         // Here's a trick! Hercules reports its version number to the GUI
447         // by means of the MAINSIZE value! Later releases of HercGUI know
448         // to interpret mainsizes less than 1000 as Hercule's version number.
449         // Earlier versions of HercGUI will simply try to interpret it as
450         // the actual mainsize, but no real harm is done since we immediately
451         // send it the CORRECT mainsize immediately afterwards. This allows
452         // future versions of HercGUI to know whether the version of Hercules
453         // that it's talking to supports a given feature or not. Slick, eh? :)
454         gui_fprintf(fStatusStream,"MAINSIZE=%s\n",VERSION);
455 
456         if (gui_version < 1.12)
457             gui_fprintf(fStatusStream,"MAINSIZE=%d\n",(U32)sysblk.mainsize);
458         else
459             gui_fprintf(fStatusStream,"MAINSIZE=%"UINT_PTR_FMT"d\n",(uintptr_t)sysblk.mainsize);
460         return NULL;
461     }
462 
463 #if defined(OPTION_MIPS_COUNTING)
464     if (strncasecmp(pszCommand,"CPUPCT=",7) == 0)
465     {
466         gui_wants_cpupct = atoi(pszCommand+7);
467         return NULL;
468     }
469     if (strncasecmp(pszCommand,"CPUPCTALL=",10) == 0)
470     {
471         if (!(gui_wants_cpupct_all = atoi(pszCommand+10)))
472             memset( &prev_cpupct[0], 0xFF, sizeof(prev_cpupct) );
473         return NULL;
474     }
475     if (strncasecmp(pszCommand,"AGGREGATE=",10) == 0)
476     {
477         gui_wants_aggregates = atoi(pszCommand+10);
478         gui_forced_refresh = 1;
479         return NULL;
480     }
481 #endif
482 
483     // Silently ignore any unrecognized special GUI commands...
484 
485     return NULL;        // (silently ignore it)
486 
487 NotSpecialGUICommand:
488 
489     // Ignore "commands" that are actually just comments (start with '*' or '#')
490 
491     if ('*' == pszCommand[0] || '#' == pszCommand[0])
492     {
493         if ('*' == pszCommand[0])       // (LOUD comment?)
494             logmsg("%s\n",pszCommand);  // (then log to console)
495         return NULL;                    // (and otherwise ignore it)
496     }
497 
498     // Otherwise it's not a command that we handle. Call the next higher
499     // level command handler which, under normal circumstances SHOULD be
500     // Hercules's "panel_command" function, but which MAY have been over-
501     // ridden by yet some OTHER dynamically loaded command handler...
502 
503     next_panel_command_handler = HDL_FINDNXT( gui_panel_command );
504 
505     if (!next_panel_command_handler)    // (extremely unlikely!)
506         return (char *)-1;              // (extremely unlikely!)
507 
508     return  next_panel_command_handler( pszCommand );
509 }
510 
511 ///////////////////////////////////////////////////////////////////////////////
512 // Status updating control fields...
513 
514 QWORD  psw, prev_psw;
515 BYTE   wait_bit;
516 BYTE   prev_cpustate   = 0xFF;
517 U64    prev_instcount  = 0;
518 
519 U32    prev_gr   [16];
520 U64    prev_gr64 [16];
521 
522 U32    prev_cr   [16];
523 U64    prev_cr64 [16];
524 
525 U32    prev_ar   [16];
526 
527 U32    prev_fpr  [8*2];
528 U32    prev_fpr64[16*2];
529 
530 ///////////////////////////////////////////////////////////////////////////////
531 // Send status information messages back to the gui...
532 
UpdateStatus()533 void  UpdateStatus ()
534 {
535     BOOL  bStatusChanged = FALSE;   // (whether or not anything has changed)
536 
537     if (sysblk.shutdown) return;
538 
539     copy_psw(pTargetCPU_REGS, psw);
540     wait_bit = (psw[1] & 0x02);
541 
542     // The SYS light and %CPU-Utilization
543     // information we send *ALL* the time...
544 
545     if (!(0
546         || CPUSTATE_STOPPING == pTargetCPU_REGS->cpustate
547         || CPUSTATE_STOPPED  == pTargetCPU_REGS->cpustate
548     ))
549     {
550         gui_fprintf(fStatusStream,
551 
552             "SYS=%c\n"
553 
554             ,wait_bit ? '0' : '1'
555         );
556     }
557 
558 #if defined(OPTION_MIPS_COUNTING)
559     if (gui_wants_cpupct)
560     {
561         if (gui_wants_aggregates)
562         {
563             int cpu, cpupct = 0, started = 0;
564             for (cpupct=0, cpu=0; cpu < sysblk.maxcpu; cpu++)
565             {
566                 if (1
567                     && IS_CPU_ONLINE( cpu )
568                     && CPUSTATE_STARTED == sysblk.regs[ cpu ]->cpustate
569                 )
570                 {
571                     started++;
572                     cpupct += sysblk.regs[ cpu ]->cpupct;
573                 }
574             }
575             gui_fprintf(fStatusStream,
576 
577                 "CPUPCT=%d\n"
578 
579                 ,started ? (cpupct / started) : 0
580             );
581         }
582         else
583         {
584             gui_fprintf(fStatusStream,
585 
586                 "CPUPCT=%d\n"
587 
588                 ,pTargetCPU_REGS->cpupct
589             );
590         }
591     }
592     if (gui_wants_cpupct_all)
593     {
594         int  i, cpupct;
595 
596         for (i = 0; i < sysblk.hicpu; i++)
597         {
598             if (0
599                 || !IS_CPU_ONLINE(i)
600                 || CPUSTATE_STARTED != sysblk.regs[i]->cpustate
601             )
602                 cpupct = 0;
603             else
604                 cpupct = sysblk.regs[i]->cpupct;
605 
606             if (cpupct != prev_cpupct[i])
607             {
608                 prev_cpupct[i] = cpupct;
609                 gui_fprintf( fStatusStream, "CPUPCT%02d=%d\n", i, cpupct );
610             }
611         }
612     }
613 #endif
614 
615     // Determine if we need to inform the GUI of anything...
616 
617     bStatusChanged = FALSE;     // (whether or not anything has changed)
618 
619     if (0
620         || gui_forced_refresh
621         || pTargetCPU_REGS != pPrevTargetCPU_REGS
622         || pcpu != prev_pcpu
623         || memcmp(prev_psw, psw, sizeof(prev_psw)) != 0
624         || prev_cpustate   != pTargetCPU_REGS->cpustate
625         || prev_instcount != INSTCOUNT(pTargetCPU_REGS)
626     )
627     {
628         bStatusChanged = TRUE;          // (something has indeed changed...)
629 
630         if (gui_forced_refresh)         // (forced refresh?)
631             HandleForcedRefresh();      // (reset all prev values)
632 
633         // Save new values for next time...
634 
635         pPrevTargetCPU_REGS = pTargetCPU_REGS;
636         prev_pcpu = pcpu;
637         memcpy(prev_psw, psw, sizeof(prev_psw));
638         prev_cpustate = pTargetCPU_REGS->cpustate;
639         prev_instcount = INSTCOUNT(pTargetCPU_REGS);
640     }
641 
642     // If anything has changed, inform the GUI...
643 
644     if (bStatusChanged)
645     {
646         UpdateCPUStatus();      // (update the status line info...)
647         UpdateRegisters();      // (update the registers display...)
648     }
649 
650     // PROGRAMMING NOTE: my original [rather poorly designed I admit] logic
651     // sent device status messages to the GUI *continuously* (i.e. all the
652     // time), even when both Herc and the channel subsystem was idle. This
653     // proved to be terribly inefficient, causing the GUI to consume *FAR*
654     // too much valuable CPU cycles parsing all of those messages.
655 
656     // Thus, starting with this version of dyngui, we now only send device
657     // status messages to the GUI only whenever the device's status actually
658     // changes, but only if it (the GUI) specifically requests such notifi-
659     // cations of course (via the new "]NEWDEVLIST=" special message).
660 
661     // The new(er) version of HercGUI understands (and thus requests) these
662     // newer format device status messages, but older versions of HercGUI
663     // of course do not. Thus in order to remain compatible with the current
664     // (older) version of the GUI, we still need to support the inefficient
665     // technique of constantly sending a constant stream of device status
666     // messages.
667 
668     // Eventually at some point this existing original inefficient technique
669     // logic will be removed (once everyone has had time to upgrade to the
670     // newer version of HercGUI), but for now, at least for the next couple
671     // of HercGUI release cycles, we need to keep it.
672 
673     if (gui_wants_devlist)      // (if the device list is visible)
674         UpdateDeviceStatus();   // (update the list of devices...)
675 
676     else // (the two options are mutually exclusive from one another)
677 
678     if (gui_wants_new_devlist)  // (if the device list is visible)
679         NewUpdateDevStats();    // (update the list of devices...)
680 
681     gui_forced_refresh  = 0;    // (reset switch; must follow devlist update)
682 }
683 
684 ///////////////////////////////////////////////////////////////////////////////
685 // Forced GUI Refresh: reset all "previous" values to force update...
686 
HandleForcedRefresh()687 void HandleForcedRefresh()
688 {
689 #ifdef OPTION_MIPS_COUNTING
690     prev_mips_rate          = INT_MAX;
691     prev_sios_rate          = INT_MAX;
692 #endif
693     prev_instcount          = ULLONG_MAX;
694     prev_pcpu               = INT_MAX;
695     pPrevTargetCPU_REGS     = NULL;
696     prev_cpustate           = 0xFF;
697     memset( prev_psw,         0xFF,  sizeof(prev_psw) );
698 
699     memset(   &prev_gr   [0], 0xFF,
700         sizeof(prev_gr) );
701 
702     memset(   &prev_cr   [0], 0xFF,
703         sizeof(prev_cr) );
704 
705     memset(   &prev_ar   [0], 0xFF,
706         sizeof(prev_ar) );
707 
708     memset(   &prev_fpr  [0], 0xFF,
709         sizeof(prev_fpr) );
710 
711     memset(   &prev_gr64 [0], 0xFF,
712         sizeof(prev_gr64) );
713 
714     memset(   &prev_cr64 [0], 0xFF,
715         sizeof(prev_cr64) );
716 
717     memset(   &prev_fpr64[0], 0xFF,
718         sizeof(prev_fpr64) );
719 
720 #if defined(OPTION_MIPS_COUNTING)
721     memset(   &prev_cpupct   [0], 0xFF,
722         sizeof(prev_cpupct   ) );
723 #endif
724 }
725 
726 ///////////////////////////////////////////////////////////////////////////////
727 // Send status information messages back to the gui...
728 
UpdateCPUStatus()729 void  UpdateCPUStatus ()
730 {
731     if (sysblk.shutdown) return;
732 
733     if (pTargetCPU_REGS == &sysblk.dummyregs)
734     {
735         // pTargetCPU_REGS == &sysblk.dummyregs; cpu is offline
736 
737         gui_fprintf(fStatusStream, "STATUS="
738 
739             "%s%02X (((((((((((((((((((((((( OFFLINE ))))))))))))))))))))))))\n",
740 
741             PTYPSTR(pcpu) ,pcpu);
742     }
743     else // pTargetCPU_REGS != &sysblk.dummyregs; cpu is online
744     {
745         // CPU status line...  (PSW, status indicators, and instruction count)
746 
747         gui_fprintf(fStatusStream, "STATUS="
748 
749             "%s%02X "
750 
751             "PSW=%2.2X%2.2X%2.2X%2.2X "
752                 "%2.2X%2.2X%2.2X%2.2X "
753                 "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X "
754 
755             "%c%c%c%c%c%c%c%c "
756 
757             "instcount=%" I64_FMT "u\n"
758 
759             ,PTYPSTR(pTargetCPU_REGS->cpuad), pTargetCPU_REGS->cpuad
760 
761             ,psw[0], psw[1], psw[2],  psw[3]
762             ,psw[4], psw[5], psw[6],  psw[7]
763             ,psw[8], psw[9], psw[10], psw[11], psw[12], psw[13], psw[14], psw[15]
764 
765             ,CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate ? 'M' : '.'
766             ,sysblk.inststep                               ? 'T' : '.'
767             ,wait_bit                                      ? 'W' : '.'
768             ,pTargetCPU_REGS->loadstate                    ? 'L' : '.'
769             ,pTargetCPU_REGS->checkstop                    ? 'C' : '.'
770             ,PROBSTATE(&pTargetCPU_REGS->psw)              ? 'P' : '.'
771             ,
772 #if        defined(_FEATURE_SIE)
773             SIE_MODE(pTargetCPU_REGS)                      ? 'S' : '.'
774 #else  // !defined(_FEATURE_SIE)
775                                                                    '.'
776 #endif //  defined(_FEATURE_SIE)
777             ,
778 #if        defined(_900)
779             ARCH_900 == pTargetCPU_REGS->arch_mode         ? 'Z' : '.'
780 #else  // !defined(_900)
781                                                                    '.'
782 #endif //  defined(_900)
783             ,(U64)INSTCOUNT(pTargetCPU_REGS)
784         );
785 
786     } // endif cpu is online/offline
787 
788 #if defined(OPTION_MIPS_COUNTING)
789 
790     // MIPS rate and SIOS rate...
791     {
792         U32* mipsrate;
793         U32* siosrate;
794 
795         if (gui_wants_aggregates)
796         {
797             mipsrate = &sysblk.mipsrate;
798             siosrate = &sysblk.siosrate;
799         }
800         else
801         {
802             mipsrate = &pTargetCPU_REGS->mipsrate;
803             siosrate = &pTargetCPU_REGS->siosrate;
804         }
805 
806         if (*mipsrate != prev_mips_rate)
807         {
808             gui_fprintf( fStatusStream,
809 
810                 "MIPS=%4d.%2.2d\n"
811 
812                 , *mipsrate / 1000000
813                 ,(*mipsrate % 1000000) / 10000
814             );
815 
816             prev_mips_rate = *mipsrate;
817         }
818 
819         if (*siosrate != prev_sios_rate)
820         {
821             gui_fprintf( fStatusStream,
822 
823                 "SIOS=%4d\n"
824 
825                 ,*siosrate
826             );
827 
828             prev_sios_rate = *siosrate;
829         }
830     }
831 
832     update_maxrates_hwm(); // (update high-water-mark values)
833 
834 #endif // defined(OPTION_MIPS_COUNTING)
835 }
836 
837 ///////////////////////////////////////////////////////////////////////////////
838 // Send status information messages back to the gui...
839 
840 #define REG32FMT  "%8.8"I32_FMT"X"
841 #define REG64FMT  "%16.16"I64_FMT"X"
842 
UpdateRegisters()843 void  UpdateRegisters ()
844 {
845     if (sysblk.shutdown) return;
846 
847     if (gui_wants_gregs)
848     {
849         if (0
850             || prev_gr[0] != pTargetCPU_REGS->GR_L(0)
851             || prev_gr[1] != pTargetCPU_REGS->GR_L(1)
852             || prev_gr[2] != pTargetCPU_REGS->GR_L(2)
853             || prev_gr[3] != pTargetCPU_REGS->GR_L(3)
854         )
855         {
856             prev_gr[0] = pTargetCPU_REGS->GR_L(0);
857             prev_gr[1] = pTargetCPU_REGS->GR_L(1);
858             prev_gr[2] = pTargetCPU_REGS->GR_L(2);
859             prev_gr[3] = pTargetCPU_REGS->GR_L(3);
860 
861             gui_fprintf(fStatusStream,
862 
863                 "GR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
864 
865                 ,pTargetCPU_REGS->GR_L(0)
866                 ,pTargetCPU_REGS->GR_L(1)
867                 ,pTargetCPU_REGS->GR_L(2)
868                 ,pTargetCPU_REGS->GR_L(3)
869             );
870         }
871 
872         if (0
873             || prev_gr[4] != pTargetCPU_REGS->GR_L(4)
874             || prev_gr[5] != pTargetCPU_REGS->GR_L(5)
875             || prev_gr[6] != pTargetCPU_REGS->GR_L(6)
876             || prev_gr[7] != pTargetCPU_REGS->GR_L(7)
877         )
878         {
879             prev_gr[4] = pTargetCPU_REGS->GR_L(4);
880             prev_gr[5] = pTargetCPU_REGS->GR_L(5);
881             prev_gr[6] = pTargetCPU_REGS->GR_L(6);
882             prev_gr[7] = pTargetCPU_REGS->GR_L(7);
883 
884             gui_fprintf(fStatusStream,
885 
886                 "GR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
887 
888                 ,pTargetCPU_REGS->GR_L(4)
889                 ,pTargetCPU_REGS->GR_L(5)
890                 ,pTargetCPU_REGS->GR_L(6)
891                 ,pTargetCPU_REGS->GR_L(7)
892             );
893         }
894 
895         if (0
896             || prev_gr[8]  != pTargetCPU_REGS->GR_L(8)
897             || prev_gr[9]  != pTargetCPU_REGS->GR_L(9)
898             || prev_gr[10] != pTargetCPU_REGS->GR_L(10)
899             || prev_gr[11] != pTargetCPU_REGS->GR_L(11)
900         )
901         {
902             prev_gr[8]  = pTargetCPU_REGS->GR_L(8);
903             prev_gr[9]  = pTargetCPU_REGS->GR_L(9);
904             prev_gr[10] = pTargetCPU_REGS->GR_L(10);
905             prev_gr[11] = pTargetCPU_REGS->GR_L(11);
906 
907             gui_fprintf(fStatusStream,
908 
909                 "GR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
910 
911                 ,pTargetCPU_REGS->GR_L(8)
912                 ,pTargetCPU_REGS->GR_L(9)
913                 ,pTargetCPU_REGS->GR_L(10)
914                 ,pTargetCPU_REGS->GR_L(11)
915             );
916         }
917 
918         if (0
919             || prev_gr[12] != pTargetCPU_REGS->GR_L(12)
920             || prev_gr[13] != pTargetCPU_REGS->GR_L(13)
921             || prev_gr[14] != pTargetCPU_REGS->GR_L(14)
922             || prev_gr[15] != pTargetCPU_REGS->GR_L(15)
923         )
924         {
925             prev_gr[12] = pTargetCPU_REGS->GR_L(12);
926             prev_gr[13] = pTargetCPU_REGS->GR_L(13);
927             prev_gr[14] = pTargetCPU_REGS->GR_L(14);
928             prev_gr[15] = pTargetCPU_REGS->GR_L(15);
929 
930             gui_fprintf(fStatusStream,
931 
932                 "GRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
933 
934                 ,pTargetCPU_REGS->GR_L(12)
935                 ,pTargetCPU_REGS->GR_L(13)
936                 ,pTargetCPU_REGS->GR_L(14)
937                 ,pTargetCPU_REGS->GR_L(15)
938             );
939         }
940     }
941 
942     if (gui_wants_gregs64)
943     {
944         if (0
945             || prev_gr64[0] != pTargetCPU_REGS->GR_G(0)
946             || prev_gr64[1] != pTargetCPU_REGS->GR_G(1)
947         )
948         {
949             prev_gr64[0] = pTargetCPU_REGS->GR_G(0);
950             prev_gr64[1] = pTargetCPU_REGS->GR_G(1);
951 
952             gui_fprintf(fStatusStream,
953 
954                 "64_GR0-1="REG64FMT" "REG64FMT"\n"
955 
956                 ,pTargetCPU_REGS->GR_G(0)
957                 ,pTargetCPU_REGS->GR_G(1)
958             );
959         }
960 
961         if (0
962             || prev_gr64[2] != pTargetCPU_REGS->GR_G(2)
963             || prev_gr64[3] != pTargetCPU_REGS->GR_G(3)
964         )
965         {
966             prev_gr64[2] = pTargetCPU_REGS->GR_G(2);
967             prev_gr64[3] = pTargetCPU_REGS->GR_G(3);
968 
969             gui_fprintf(fStatusStream,
970 
971                 "64_GR2-3="REG64FMT" "REG64FMT"\n"
972 
973                 ,pTargetCPU_REGS->GR_G(2)
974                 ,pTargetCPU_REGS->GR_G(3)
975             );
976         }
977 
978         if (0
979             || prev_gr64[4] != pTargetCPU_REGS->GR_G(4)
980             || prev_gr64[5] != pTargetCPU_REGS->GR_G(5)
981         )
982         {
983             prev_gr64[4] = pTargetCPU_REGS->GR_G(4);
984             prev_gr64[5] = pTargetCPU_REGS->GR_G(5);
985 
986             gui_fprintf(fStatusStream,
987 
988                 "64_GR4-5="REG64FMT" "REG64FMT"\n"
989 
990                 ,pTargetCPU_REGS->GR_G(4)
991                 ,pTargetCPU_REGS->GR_G(5)
992             );
993         }
994 
995         if (0
996             || prev_gr64[6] != pTargetCPU_REGS->GR_G(6)
997             || prev_gr64[7] != pTargetCPU_REGS->GR_G(7)
998         )
999         {
1000             prev_gr64[6] = pTargetCPU_REGS->GR_G(6);
1001             prev_gr64[7] = pTargetCPU_REGS->GR_G(7);
1002 
1003             gui_fprintf(fStatusStream,
1004 
1005                 "64_GR6-7="REG64FMT" "REG64FMT"\n"
1006 
1007                 ,pTargetCPU_REGS->GR_G(6)
1008                 ,pTargetCPU_REGS->GR_G(7)
1009             );
1010         }
1011 
1012         if (0
1013             || prev_gr64[8]  != pTargetCPU_REGS->GR_G(8)
1014             || prev_gr64[9]  != pTargetCPU_REGS->GR_G(9)
1015         )
1016         {
1017             prev_gr64[8] = pTargetCPU_REGS->GR_G(8);
1018             prev_gr64[9] = pTargetCPU_REGS->GR_G(9);
1019 
1020             gui_fprintf(fStatusStream,
1021 
1022                 "64_GR8-9="REG64FMT" "REG64FMT"\n"
1023 
1024                 ,pTargetCPU_REGS->GR_G(8)
1025                 ,pTargetCPU_REGS->GR_G(9)
1026             );
1027         }
1028 
1029         if (0
1030             || prev_gr64[10] != pTargetCPU_REGS->GR_G(10)
1031             || prev_gr64[11] != pTargetCPU_REGS->GR_G(11)
1032         )
1033         {
1034             prev_gr64[10] = pTargetCPU_REGS->GR_G(10);
1035             prev_gr64[11] = pTargetCPU_REGS->GR_G(11);
1036 
1037             gui_fprintf(fStatusStream,
1038 
1039                 "64_GRA-B="REG64FMT" "REG64FMT"\n"
1040 
1041                 ,pTargetCPU_REGS->GR_G(10)
1042                 ,pTargetCPU_REGS->GR_G(11)
1043             );
1044         }
1045 
1046         if (0
1047             || prev_gr64[12] != pTargetCPU_REGS->GR_G(12)
1048             || prev_gr64[13] != pTargetCPU_REGS->GR_G(13)
1049         )
1050         {
1051             prev_gr64[12] = pTargetCPU_REGS->GR_G(12);
1052             prev_gr64[13] = pTargetCPU_REGS->GR_G(13);
1053 
1054             gui_fprintf(fStatusStream,
1055 
1056                 "64_GRC-D="REG64FMT" "REG64FMT"\n"
1057 
1058                 ,pTargetCPU_REGS->GR_G(12)
1059                 ,pTargetCPU_REGS->GR_G(13)
1060             );
1061         }
1062 
1063         if (0
1064             || prev_gr64[14] != pTargetCPU_REGS->GR_G(14)
1065             || prev_gr64[15] != pTargetCPU_REGS->GR_G(15)
1066         )
1067         {
1068             prev_gr64[14] = pTargetCPU_REGS->GR_G(14);
1069             prev_gr64[15] = pTargetCPU_REGS->GR_G(15);
1070 
1071             gui_fprintf(fStatusStream,
1072 
1073                 "64_GRE-F="REG64FMT" "REG64FMT"\n"
1074 
1075                 ,pTargetCPU_REGS->GR_G(14)
1076                 ,pTargetCPU_REGS->GR_G(15)
1077             );
1078         }
1079     }
1080 
1081     if (gui_wants_cregs)
1082     {
1083         if (0
1084             || prev_cr[0] != pTargetCPU_REGS->CR_L(0)
1085             || prev_cr[1] != pTargetCPU_REGS->CR_L(1)
1086             || prev_cr[2] != pTargetCPU_REGS->CR_L(2)
1087             || prev_cr[3] != pTargetCPU_REGS->CR_L(3)
1088         )
1089         {
1090             prev_cr[0] = pTargetCPU_REGS->CR_L(0);
1091             prev_cr[1] = pTargetCPU_REGS->CR_L(1);
1092             prev_cr[2] = pTargetCPU_REGS->CR_L(2);
1093             prev_cr[3] = pTargetCPU_REGS->CR_L(3);
1094 
1095             gui_fprintf(fStatusStream,
1096 
1097                 "CR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1098 
1099                 ,pTargetCPU_REGS->CR_L(0)
1100                 ,pTargetCPU_REGS->CR_L(1)
1101                 ,pTargetCPU_REGS->CR_L(2)
1102                 ,pTargetCPU_REGS->CR_L(3)
1103             );
1104         }
1105 
1106         if (0
1107             || prev_cr[4] != pTargetCPU_REGS->CR_L(4)
1108             || prev_cr[5] != pTargetCPU_REGS->CR_L(5)
1109             || prev_cr[6] != pTargetCPU_REGS->CR_L(6)
1110             || prev_cr[7] != pTargetCPU_REGS->CR_L(7)
1111         )
1112         {
1113             prev_cr[4] = pTargetCPU_REGS->CR_L(4);
1114             prev_cr[5] = pTargetCPU_REGS->CR_L(5);
1115             prev_cr[6] = pTargetCPU_REGS->CR_L(6);
1116             prev_cr[7] = pTargetCPU_REGS->CR_L(7);
1117 
1118             gui_fprintf(fStatusStream,
1119 
1120                 "CR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1121 
1122                 ,pTargetCPU_REGS->CR_L(4)
1123                 ,pTargetCPU_REGS->CR_L(5)
1124                 ,pTargetCPU_REGS->CR_L(6)
1125                 ,pTargetCPU_REGS->CR_L(7)
1126             );
1127         }
1128 
1129         if (0
1130             || prev_cr[8]  != pTargetCPU_REGS->CR_L(8)
1131             || prev_cr[9]  != pTargetCPU_REGS->CR_L(9)
1132             || prev_cr[10] != pTargetCPU_REGS->CR_L(10)
1133             || prev_cr[11] != pTargetCPU_REGS->CR_L(11)
1134         )
1135         {
1136             prev_cr[8]  = pTargetCPU_REGS->CR_L(8);
1137             prev_cr[9]  = pTargetCPU_REGS->CR_L(9);
1138             prev_cr[10] = pTargetCPU_REGS->CR_L(10);
1139             prev_cr[10] = pTargetCPU_REGS->CR_L(10);
1140 
1141             gui_fprintf(fStatusStream,
1142 
1143                 "CR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1144 
1145                 ,pTargetCPU_REGS->CR_L(8)
1146                 ,pTargetCPU_REGS->CR_L(9)
1147                 ,pTargetCPU_REGS->CR_L(10)
1148                 ,pTargetCPU_REGS->CR_L(11)
1149             );
1150         }
1151 
1152         if (0
1153             || prev_cr[12] != pTargetCPU_REGS->CR_L(12)
1154             || prev_cr[13] != pTargetCPU_REGS->CR_L(13)
1155             || prev_cr[14] != pTargetCPU_REGS->CR_L(14)
1156             || prev_cr[15] != pTargetCPU_REGS->CR_L(15)
1157         )
1158         {
1159             prev_cr[12] = pTargetCPU_REGS->CR_L(12);
1160             prev_cr[13] = pTargetCPU_REGS->CR_L(13);
1161             prev_cr[14] = pTargetCPU_REGS->CR_L(14);
1162             prev_cr[15] = pTargetCPU_REGS->CR_L(15);
1163 
1164             gui_fprintf(fStatusStream,
1165 
1166                 "CRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1167 
1168                 ,pTargetCPU_REGS->CR_L(12)
1169                 ,pTargetCPU_REGS->CR_L(13)
1170                 ,pTargetCPU_REGS->CR_L(14)
1171                 ,pTargetCPU_REGS->CR_L(15)
1172             );
1173         }
1174     }
1175 
1176     if (gui_wants_cregs64)
1177     {
1178         if (0
1179             || prev_cr64[0] != pTargetCPU_REGS->CR_G(0)
1180             || prev_cr64[1] != pTargetCPU_REGS->CR_G(1)
1181         )
1182         {
1183             prev_cr64[0] = pTargetCPU_REGS->CR_G(0);
1184             prev_cr64[1] = pTargetCPU_REGS->CR_G(1);
1185 
1186             gui_fprintf(fStatusStream,
1187 
1188                 "64_CR0-1="REG64FMT" "REG64FMT"\n"
1189 
1190                 ,pTargetCPU_REGS->CR_G(0)
1191                 ,pTargetCPU_REGS->CR_G(1)
1192             );
1193         }
1194 
1195         if (0
1196             || prev_cr64[2] != pTargetCPU_REGS->CR_G(2)
1197             || prev_cr64[3] != pTargetCPU_REGS->CR_G(3)
1198         )
1199         {
1200             prev_cr64[2] = pTargetCPU_REGS->CR_G(2);
1201             prev_cr64[3] = pTargetCPU_REGS->CR_G(3);
1202 
1203             gui_fprintf(fStatusStream,
1204 
1205                 "64_CR2-3="REG64FMT" "REG64FMT"\n"
1206 
1207                 ,pTargetCPU_REGS->CR_G(2)
1208                 ,pTargetCPU_REGS->CR_G(3)
1209             );
1210         }
1211 
1212         if (0
1213             || prev_cr64[4] != pTargetCPU_REGS->CR_G(4)
1214             || prev_cr64[5] != pTargetCPU_REGS->CR_G(5)
1215         )
1216         {
1217             prev_cr64[4] = pTargetCPU_REGS->CR_G(4);
1218             prev_cr64[5] = pTargetCPU_REGS->CR_G(5);
1219 
1220             gui_fprintf(fStatusStream,
1221 
1222                 "64_CR4-5="REG64FMT" "REG64FMT"\n"
1223 
1224                 ,pTargetCPU_REGS->CR_G(4)
1225                 ,pTargetCPU_REGS->CR_G(5)
1226             );
1227         }
1228 
1229         if (0
1230             || prev_cr64[6] != pTargetCPU_REGS->CR_G(6)
1231             || prev_cr64[7] != pTargetCPU_REGS->CR_G(7)
1232         )
1233         {
1234             prev_cr64[6] = pTargetCPU_REGS->CR_G(6);
1235             prev_cr64[7] = pTargetCPU_REGS->CR_G(7);
1236 
1237             gui_fprintf(fStatusStream,
1238 
1239                 "64_CR6-7="REG64FMT" "REG64FMT"\n"
1240 
1241                 ,pTargetCPU_REGS->CR_G(6)
1242                 ,pTargetCPU_REGS->CR_G(7)
1243             );
1244         }
1245 
1246         if (0
1247             || prev_cr64[8]  != pTargetCPU_REGS->CR_G(8)
1248             || prev_cr64[9]  != pTargetCPU_REGS->CR_G(9)
1249         )
1250         {
1251             prev_cr64[8] = pTargetCPU_REGS->CR_G(8);
1252             prev_cr64[9] = pTargetCPU_REGS->CR_G(9);
1253 
1254             gui_fprintf(fStatusStream,
1255 
1256                 "64_CR8-9="REG64FMT" "REG64FMT"\n"
1257 
1258                 ,pTargetCPU_REGS->CR_G(8)
1259                 ,pTargetCPU_REGS->CR_G(9)
1260             );
1261         }
1262 
1263         if (0
1264             || prev_cr64[10] != pTargetCPU_REGS->CR_G(10)
1265             || prev_cr64[11] != pTargetCPU_REGS->CR_G(11)
1266         )
1267         {
1268             prev_cr64[10] = pTargetCPU_REGS->CR_G(10);
1269             prev_cr64[11] = pTargetCPU_REGS->CR_G(11);
1270 
1271             gui_fprintf(fStatusStream,
1272 
1273                 "64_CRA-B="REG64FMT" "REG64FMT"\n"
1274 
1275                 ,pTargetCPU_REGS->CR_G(10)
1276                 ,pTargetCPU_REGS->CR_G(11)
1277             );
1278         }
1279 
1280         if (0
1281             || prev_cr64[12] != pTargetCPU_REGS->CR_G(12)
1282             || prev_cr64[13] != pTargetCPU_REGS->CR_G(13)
1283         )
1284         {
1285             prev_cr64[12] = pTargetCPU_REGS->CR_G(12);
1286             prev_cr64[13] = pTargetCPU_REGS->CR_G(13);
1287 
1288             gui_fprintf(fStatusStream,
1289 
1290                 "64_CRC-D="REG64FMT" "REG64FMT"\n"
1291 
1292                 ,pTargetCPU_REGS->CR_G(12)
1293                 ,pTargetCPU_REGS->CR_G(13)
1294             );
1295         }
1296 
1297         if (0
1298             || prev_cr64[14] != pTargetCPU_REGS->CR_G(14)
1299             || prev_cr64[15] != pTargetCPU_REGS->CR_G(15)
1300         )
1301         {
1302             prev_cr64[14] = pTargetCPU_REGS->CR_G(14);
1303             prev_cr64[15] = pTargetCPU_REGS->CR_G(15);
1304 
1305             gui_fprintf(fStatusStream,
1306 
1307                 "64_CRE-F="REG64FMT" "REG64FMT"\n"
1308 
1309                 ,pTargetCPU_REGS->CR_G(14)
1310                 ,pTargetCPU_REGS->CR_G(15)
1311             );
1312         }
1313     }
1314 
1315     if (gui_wants_aregs)
1316     {
1317         if (0
1318             || prev_ar[0] != pTargetCPU_REGS->AR(0)
1319             || prev_ar[1] != pTargetCPU_REGS->AR(1)
1320             || prev_ar[2] != pTargetCPU_REGS->AR(2)
1321             || prev_ar[3] != pTargetCPU_REGS->AR(3)
1322         )
1323         {
1324             prev_ar[0] = pTargetCPU_REGS->AR(0);
1325             prev_ar[1] = pTargetCPU_REGS->AR(1);
1326             prev_ar[2] = pTargetCPU_REGS->AR(2);
1327             prev_ar[3] = pTargetCPU_REGS->AR(3);
1328 
1329             gui_fprintf(fStatusStream,
1330 
1331                 "AR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1332 
1333                 ,pTargetCPU_REGS->AR(0)
1334                 ,pTargetCPU_REGS->AR(1)
1335                 ,pTargetCPU_REGS->AR(2)
1336                 ,pTargetCPU_REGS->AR(3)
1337             );
1338         }
1339 
1340         if (0
1341             || prev_ar[4] != pTargetCPU_REGS->AR(4)
1342             || prev_ar[5] != pTargetCPU_REGS->AR(5)
1343             || prev_ar[6] != pTargetCPU_REGS->AR(6)
1344             || prev_ar[7] != pTargetCPU_REGS->AR(7)
1345         )
1346         {
1347             prev_ar[4] = pTargetCPU_REGS->AR(4);
1348             prev_ar[5] = pTargetCPU_REGS->AR(5);
1349             prev_ar[6] = pTargetCPU_REGS->AR(6);
1350             prev_ar[7] = pTargetCPU_REGS->AR(7);
1351 
1352             gui_fprintf(fStatusStream,
1353 
1354                 "AR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1355 
1356                 ,pTargetCPU_REGS->AR(4)
1357                 ,pTargetCPU_REGS->AR(5)
1358                 ,pTargetCPU_REGS->AR(6)
1359                 ,pTargetCPU_REGS->AR(7)
1360             );
1361         }
1362 
1363         if (0
1364             || prev_ar[8]  != pTargetCPU_REGS->AR(8)
1365             || prev_ar[9]  != pTargetCPU_REGS->AR(9)
1366             || prev_ar[10] != pTargetCPU_REGS->AR(10)
1367             || prev_ar[11] != pTargetCPU_REGS->AR(11)
1368         )
1369         {
1370             prev_ar[8]  = pTargetCPU_REGS->AR(8);
1371             prev_ar[9]  = pTargetCPU_REGS->AR(9);
1372             prev_ar[10] = pTargetCPU_REGS->AR(10);
1373             prev_ar[11] = pTargetCPU_REGS->AR(11);
1374 
1375             gui_fprintf(fStatusStream,
1376 
1377                 "AR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1378 
1379                 ,pTargetCPU_REGS->AR(8)
1380                 ,pTargetCPU_REGS->AR(9)
1381                 ,pTargetCPU_REGS->AR(10)
1382                 ,pTargetCPU_REGS->AR(11)
1383             );
1384         }
1385 
1386         if (0
1387             || prev_ar[12] != pTargetCPU_REGS->AR(12)
1388             || prev_ar[13] != pTargetCPU_REGS->AR(13)
1389             || prev_ar[14] != pTargetCPU_REGS->AR(14)
1390             || prev_ar[15] != pTargetCPU_REGS->AR(15)
1391         )
1392         {
1393             prev_ar[12] = pTargetCPU_REGS->AR(12);
1394             prev_ar[13] = pTargetCPU_REGS->AR(13);
1395             prev_ar[14] = pTargetCPU_REGS->AR(14);
1396             prev_ar[15] = pTargetCPU_REGS->AR(15);
1397 
1398             gui_fprintf(fStatusStream,
1399 
1400                 "ARC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1401 
1402                 ,pTargetCPU_REGS->AR(12)
1403                 ,pTargetCPU_REGS->AR(13)
1404                 ,pTargetCPU_REGS->AR(14)
1405                 ,pTargetCPU_REGS->AR(15)
1406             );
1407         }
1408     }
1409 
1410     if (gui_wants_fregs)
1411     {
1412         if (0
1413             || prev_fpr[0] != pTargetCPU_REGS->fpr[0]
1414             || prev_fpr[1] != pTargetCPU_REGS->fpr[1]
1415             || prev_fpr[2] != pTargetCPU_REGS->fpr[2]
1416             || prev_fpr[3] != pTargetCPU_REGS->fpr[3]
1417         )
1418         {
1419             prev_fpr[0] = pTargetCPU_REGS->fpr[0];
1420             prev_fpr[1] = pTargetCPU_REGS->fpr[1];
1421             prev_fpr[2] = pTargetCPU_REGS->fpr[2];
1422             prev_fpr[3] = pTargetCPU_REGS->fpr[3];
1423 
1424             gui_fprintf(fStatusStream,
1425 
1426                 "FR0-2="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1427 
1428                 ,pTargetCPU_REGS->fpr[0]
1429                 ,pTargetCPU_REGS->fpr[1]
1430                 ,pTargetCPU_REGS->fpr[2]
1431                 ,pTargetCPU_REGS->fpr[3]
1432             );
1433         }
1434 
1435         if (0
1436             || prev_fpr[4] != pTargetCPU_REGS->fpr[4]
1437             || prev_fpr[5] != pTargetCPU_REGS->fpr[5]
1438             || prev_fpr[6] != pTargetCPU_REGS->fpr[6]
1439             || prev_fpr[7] != pTargetCPU_REGS->fpr[7]
1440         )
1441         {
1442             prev_fpr[4] = pTargetCPU_REGS->fpr[4];
1443             prev_fpr[5] = pTargetCPU_REGS->fpr[5];
1444             prev_fpr[6] = pTargetCPU_REGS->fpr[6];
1445             prev_fpr[7] = pTargetCPU_REGS->fpr[7];
1446 
1447             gui_fprintf(fStatusStream,
1448 
1449                 "FR4-6="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1450 
1451                 ,pTargetCPU_REGS->fpr[4]
1452                 ,pTargetCPU_REGS->fpr[5]
1453                 ,pTargetCPU_REGS->fpr[6]
1454                 ,pTargetCPU_REGS->fpr[7]
1455             );
1456         }
1457     }
1458 
1459     if (gui_wants_fregs64)
1460     {
1461         if (0
1462             || prev_fpr64[0] != pTargetCPU_REGS->fpr[0]
1463             || prev_fpr64[1] != pTargetCPU_REGS->fpr[1]
1464             || prev_fpr64[2] != pTargetCPU_REGS->fpr[2]
1465             || prev_fpr64[3] != pTargetCPU_REGS->fpr[3]
1466         )
1467         {
1468             prev_fpr64[0] = pTargetCPU_REGS->fpr[0];
1469             prev_fpr64[1] = pTargetCPU_REGS->fpr[1];
1470             prev_fpr64[2] = pTargetCPU_REGS->fpr[2];
1471             prev_fpr64[3] = pTargetCPU_REGS->fpr[3];
1472 
1473             gui_fprintf(fStatusStream,
1474 
1475                 "64_FR0-1="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1476 
1477                 ,pTargetCPU_REGS->fpr[0]  ,pTargetCPU_REGS->fpr[1]
1478                 ,pTargetCPU_REGS->fpr[2]  ,pTargetCPU_REGS->fpr[3]
1479             );
1480         }
1481 
1482         if (0
1483             || prev_fpr64[4] != pTargetCPU_REGS->fpr[4]
1484             || prev_fpr64[5] != pTargetCPU_REGS->fpr[5]
1485             || prev_fpr64[6] != pTargetCPU_REGS->fpr[6]
1486             || prev_fpr64[7] != pTargetCPU_REGS->fpr[7]
1487         )
1488         {
1489             prev_fpr64[4] = pTargetCPU_REGS->fpr[4];
1490             prev_fpr64[5] = pTargetCPU_REGS->fpr[5];
1491             prev_fpr64[6] = pTargetCPU_REGS->fpr[6];
1492             prev_fpr64[7] = pTargetCPU_REGS->fpr[7];
1493 
1494             gui_fprintf(fStatusStream,
1495 
1496                 "64_FR2-3="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1497 
1498                 ,pTargetCPU_REGS->fpr[4]  ,pTargetCPU_REGS->fpr[5]
1499                 ,pTargetCPU_REGS->fpr[6]  ,pTargetCPU_REGS->fpr[7]
1500             );
1501         }
1502 
1503         if (0
1504             || prev_fpr64[8]  != pTargetCPU_REGS->fpr[8]
1505             || prev_fpr64[9]  != pTargetCPU_REGS->fpr[9]
1506             || prev_fpr64[10] != pTargetCPU_REGS->fpr[10]
1507             || prev_fpr64[11] != pTargetCPU_REGS->fpr[11]
1508         )
1509         {
1510             prev_fpr64[8]  = pTargetCPU_REGS->fpr[8];
1511             prev_fpr64[9]  = pTargetCPU_REGS->fpr[9];
1512             prev_fpr64[10] = pTargetCPU_REGS->fpr[10];
1513             prev_fpr64[11] = pTargetCPU_REGS->fpr[11];
1514 
1515             gui_fprintf(fStatusStream,
1516 
1517                 "64_FR4-5="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1518 
1519                 ,pTargetCPU_REGS->fpr[8]  ,pTargetCPU_REGS->fpr[9]
1520                 ,pTargetCPU_REGS->fpr[10] ,pTargetCPU_REGS->fpr[11]
1521 
1522             );
1523         }
1524 
1525         if (0
1526             || prev_fpr64[12] != pTargetCPU_REGS->fpr[12]
1527             || prev_fpr64[13] != pTargetCPU_REGS->fpr[13]
1528             || prev_fpr64[14] != pTargetCPU_REGS->fpr[14]
1529             || prev_fpr64[15] != pTargetCPU_REGS->fpr[15]
1530         )
1531         {
1532             prev_fpr64[12] = pTargetCPU_REGS->fpr[12];
1533             prev_fpr64[13] = pTargetCPU_REGS->fpr[13];
1534             prev_fpr64[14] = pTargetCPU_REGS->fpr[14];
1535             prev_fpr64[15] = pTargetCPU_REGS->fpr[15];
1536 
1537             gui_fprintf(fStatusStream,
1538 
1539                 "64_FR6-7="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1540 
1541                 ,pTargetCPU_REGS->fpr[12] ,pTargetCPU_REGS->fpr[13]
1542                 ,pTargetCPU_REGS->fpr[14] ,pTargetCPU_REGS->fpr[15]
1543 
1544             );
1545         }
1546 
1547         if (0
1548             || prev_fpr64[16] != pTargetCPU_REGS->fpr[16]
1549             || prev_fpr64[17] != pTargetCPU_REGS->fpr[17]
1550             || prev_fpr64[18] != pTargetCPU_REGS->fpr[18]
1551             || prev_fpr64[19] != pTargetCPU_REGS->fpr[19]
1552         )
1553         {
1554             prev_fpr64[16] = pTargetCPU_REGS->fpr[16];
1555             prev_fpr64[17] = pTargetCPU_REGS->fpr[17];
1556             prev_fpr64[18] = pTargetCPU_REGS->fpr[18];
1557             prev_fpr64[19] = pTargetCPU_REGS->fpr[19];
1558 
1559             gui_fprintf(fStatusStream,
1560 
1561                 "64_FR8-9="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1562 
1563                 ,pTargetCPU_REGS->fpr[16] ,pTargetCPU_REGS->fpr[17]
1564                 ,pTargetCPU_REGS->fpr[18] ,pTargetCPU_REGS->fpr[19]
1565             );
1566         }
1567 
1568         if (0
1569             || prev_fpr64[20] != pTargetCPU_REGS->fpr[20]
1570             || prev_fpr64[21] != pTargetCPU_REGS->fpr[21]
1571             || prev_fpr64[22] != pTargetCPU_REGS->fpr[22]
1572             || prev_fpr64[23] != pTargetCPU_REGS->fpr[23]
1573         )
1574         {
1575             prev_fpr64[20] = pTargetCPU_REGS->fpr[20];
1576             prev_fpr64[21] = pTargetCPU_REGS->fpr[21];
1577             prev_fpr64[22] = pTargetCPU_REGS->fpr[22];
1578             prev_fpr64[23] = pTargetCPU_REGS->fpr[23];
1579 
1580             gui_fprintf(fStatusStream,
1581 
1582                 "64_FRA-B="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1583 
1584                 ,pTargetCPU_REGS->fpr[20] ,pTargetCPU_REGS->fpr[21]
1585                 ,pTargetCPU_REGS->fpr[22] ,pTargetCPU_REGS->fpr[23]
1586             );
1587         }
1588 
1589         if (0
1590             || prev_fpr64[24] != pTargetCPU_REGS->fpr[24]
1591             || prev_fpr64[25] != pTargetCPU_REGS->fpr[25]
1592             || prev_fpr64[26] != pTargetCPU_REGS->fpr[26]
1593             || prev_fpr64[27] != pTargetCPU_REGS->fpr[27]
1594         )
1595         {
1596             prev_fpr64[24] = pTargetCPU_REGS->fpr[24];
1597             prev_fpr64[25] = pTargetCPU_REGS->fpr[25];
1598             prev_fpr64[26] = pTargetCPU_REGS->fpr[26];
1599             prev_fpr64[27] = pTargetCPU_REGS->fpr[27];
1600 
1601             gui_fprintf(fStatusStream,
1602 
1603                 "64_FRC-D="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1604 
1605                 ,pTargetCPU_REGS->fpr[24] ,pTargetCPU_REGS->fpr[25]
1606                 ,pTargetCPU_REGS->fpr[26] ,pTargetCPU_REGS->fpr[27]
1607             );
1608         }
1609 
1610         if (0
1611             || prev_fpr64[28] != pTargetCPU_REGS->fpr[28]
1612             || prev_fpr64[29] != pTargetCPU_REGS->fpr[29]
1613             || prev_fpr64[30] != pTargetCPU_REGS->fpr[30]
1614             || prev_fpr64[31] != pTargetCPU_REGS->fpr[31]
1615         )
1616         {
1617             prev_fpr64[28] = pTargetCPU_REGS->fpr[28];
1618             prev_fpr64[29] = pTargetCPU_REGS->fpr[29];
1619             prev_fpr64[30] = pTargetCPU_REGS->fpr[30];
1620             prev_fpr64[31] = pTargetCPU_REGS->fpr[31];
1621 
1622             gui_fprintf(fStatusStream,
1623 
1624                 "64_FRE-F="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1625 
1626                 ,pTargetCPU_REGS->fpr[28] ,pTargetCPU_REGS->fpr[29]
1627                 ,pTargetCPU_REGS->fpr[30] ,pTargetCPU_REGS->fpr[31]
1628             );
1629         }
1630     }
1631 }
1632 
1633 ///////////////////////////////////////////////////////////////////////////////
1634 
1635 char  szQueryDeviceBuff[ MAX_DEVICEQUERY_LEN + 1 ]; // (always +1 for safety!)
1636 
1637 ///////////////////////////////////////////////////////////////////////////////
1638 // Send status information messages back to the gui...  (VERY inefficient!)
1639 
UpdateDeviceStatus()1640 void  UpdateDeviceStatus ()
1641 {
1642     DEVBLK* pDEVBLK;
1643     char*   pDEVClass;
1644     BYTE    chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
1645 
1646     if (sysblk.shutdown) return;
1647 
1648     // Process ALL the devices in the entire configuration each time...
1649 
1650     for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
1651     {
1652         // Does this device actually exist in the configuration?
1653 
1654         if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
1655             continue;   // (no, skip)
1656 
1657         // Retrieve this device's filename and optional settings parameter values...
1658 
1659         szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
1660 
1661         (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
1662 
1663         if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN])    // (buffer overflow?)
1664         {
1665             logmsg
1666             (
1667                 _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
1668 
1669                 ,pDEVBLK->devnum
1670 
1671             );
1672         }
1673 
1674         szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0;   // (enforce NULL termination)
1675 
1676         // Device status flags...
1677                                                                               chOnlineStat  =
1678                                                                               chBusyStat    =
1679                                                                               chPendingStat =
1680                                                                               chOpenStat    = '0';
1681 
1682         if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
1683             ( pDEVBLK->console && pDEVBLK->connected))                        chOnlineStat  = '1';
1684         if (pDEVBLK->busy)                                                    chBusyStat    = '1';
1685         if (IOPENDING(pDEVBLK))                                               chPendingStat = '1';
1686         if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat    = '1';
1687 
1688         // Send status message back to gui...
1689 
1690 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1691         if (pDEVBLK == sysblk.sysgdev)
1692         {
1693             gui_fprintf( fStatusStream,
1694 
1695                 "DEV=0000 SYSG %-4.4s %c%c%c%c %s\n"
1696 
1697                 ,pDEVClass
1698 
1699                 ,chOnlineStat
1700                 ,chBusyStat
1701                 ,chPendingStat
1702                 ,chOpenStat
1703 
1704                 ,szQueryDeviceBuff
1705             );
1706         }
1707         else
1708 #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1709         gui_fprintf(fStatusStream,
1710 
1711             "DEV=%4.4X %4.4X %-4.4s %c%c%c%c %s\n"
1712 
1713             ,pDEVBLK->devnum
1714             ,pDEVBLK->devtype
1715             ,pDEVClass
1716 
1717             ,chOnlineStat
1718             ,chBusyStat
1719             ,chPendingStat
1720             ,chOpenStat
1721 
1722             ,szQueryDeviceBuff
1723         );
1724     }
1725 
1726     // Since the device list can be in any order and devices can be added
1727     // and/or removed at any time, the GUI needs to know "That's all the
1728     // devices there are" so that it can detect when devices are removed...
1729 
1730     gui_fprintf(fStatusStream, "DEV=X\n");    // (indicates end of list)
1731 }
1732 
1733 ///////////////////////////////////////////////////////////////////////////////
1734 // Send device status msgs to the gui IF NEEDED...  (slightly more efficient)
1735 
NewUpdateDevStats()1736 void  NewUpdateDevStats ()
1737 {
1738     DEVBLK*     pDEVBLK;
1739     GUISTAT*    pGUIStat;
1740     char*       pDEVClass;
1741     BYTE        chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
1742     BOOL        bUpdatesSent = FALSE;
1743     static BOOL bFirstBatch  = TRUE;
1744 
1745     if (sysblk.shutdown) return;
1746 
1747     // Process ALL the devices in the entire configuration each time...
1748 
1749     // (But only send device status messages to the GUI only when the
1750     // device's status actually changes and not continuously like before)
1751 
1752     for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
1753     {
1754         pGUIStat = pDEVBLK->pGUIStat;
1755 
1756         // Does this device exist in the configuration?
1757 
1758         if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
1759         {
1760             // This device no longer exists in the configuration...
1761             // If we haven't yet notified the GUI about this device
1762             // being deleted from the configuration, then do so at
1763             // this time...
1764 
1765             if (*pGUIStat->pszNewStatStr)
1766             {
1767                 // Send "device deleted" message...
1768 
1769                 gui_fprintf ( fStatusStream, "DEVD=%4.4X\n", pDEVBLK->devnum );
1770                 bUpdatesSent = TRUE;
1771 
1772                 *pGUIStat->pszNewStatStr = 0;   // (prevent re-reporting it)
1773                 *pGUIStat->pszOldStatStr = 0;   // (prevent re-reporting it)
1774             }
1775 
1776             continue;   // (go on to next device)
1777         }
1778 
1779         // Retrieve this device's filename and optional settings parameter values...
1780 
1781         szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
1782 
1783         (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
1784 
1785         if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN])    // (buffer overflow?)
1786         {
1787             logmsg
1788             (
1789                 _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
1790 
1791                 ,pDEVBLK->devnum
1792             );
1793         }
1794 
1795         szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0;   // (enforce NULL termination)
1796 
1797         // Device status flags...
1798                                                                               chOnlineStat  =
1799                                                                               chBusyStat    =
1800                                                                               chPendingStat =
1801                                                                               chOpenStat    = '0';
1802 
1803         if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
1804             ( pDEVBLK->console && pDEVBLK->connected))                        chOnlineStat  = '1';
1805         if (pDEVBLK->busy)                                                    chBusyStat    = '1';
1806         if (IOPENDING(pDEVBLK))                                               chPendingStat = '1';
1807         if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat    = '1';
1808 
1809         // Build a new "device added" or "device changed"
1810         // status string for this device...
1811 
1812 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1813         if (pDEVBLK == sysblk.sysgdev)
1814         {
1815             snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ,
1816 
1817                 "DEV%c=0000 SYSG %-4.4s %c%c%c%c %s"
1818 
1819                 ,*pGUIStat->pszOldStatStr ? 'C' : 'A'
1820                 ,pDEVClass
1821 
1822                 ,chOnlineStat
1823                 ,chBusyStat
1824                 ,chPendingStat
1825                 ,chOpenStat
1826 
1827                 ,szQueryDeviceBuff
1828             );
1829         }
1830         else
1831 #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1832         snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ,
1833 
1834             "DEV%c=%4.4X %4.4X %-4.4s %c%c%c%c %s"
1835 
1836             ,*pGUIStat->pszOldStatStr ? 'C' : 'A'
1837             ,pDEVBLK->devnum
1838             ,pDEVBLK->devtype
1839             ,pDEVClass
1840 
1841             ,chOnlineStat
1842             ,chBusyStat
1843             ,chPendingStat
1844             ,chOpenStat
1845 
1846             ,szQueryDeviceBuff
1847         );
1848 
1849         *(pGUIStat->pszNewStatStr + GUI_STATSTR_BUFSIZ - 1) = 0;
1850 
1851         // If the new status string is different from the old one,
1852         // then send the new one to the GUI and swap buffer ptrs
1853         // for next time. In this way we only send device status
1854         // msgs to the GUI only when the status actually changes...
1855 
1856         if (strcmp( pGUIStat->pszNewStatStr, pGUIStat->pszOldStatStr ))
1857         {
1858             gui_fprintf ( fStatusStream, "%s\n", pGUIStat->pszNewStatStr );
1859             bUpdatesSent = TRUE;
1860             {
1861                 register char*
1862                           pszSavStatStr = pGUIStat->pszNewStatStr;
1863                 pGUIStat->pszNewStatStr = pGUIStat->pszOldStatStr;
1864                 pGUIStat->pszOldStatStr =           pszSavStatStr;
1865             }
1866         }
1867     }
1868 
1869     // Only send End-of-Batch indicator if we sent any updates or
1870     // if this is the first device-list update since powering on.
1871 
1872     if ( bUpdatesSent || bFirstBatch )
1873     {
1874         bFirstBatch = FALSE;
1875         gui_fprintf(fStatusStream, "DEVX=\n");  // (send end-of-batch indicator)
1876     }
1877 }
1878 
1879 ///////////////////////////////////////////////////////////////////////////////
1880 // Our Hercules "debug_cpu_state" override...
1881 //
1882 // Hercules calls the following function from several different places to fix
1883 // an unintentional problem caused by the new logger mechanism (wherein stdout
1884 // and stderr now point to the same stream) due to a oversight (bug) on my part
1885 // wherein the 'LOAD' and 'MAN' messages are being [mistakenly] written to stdout
1886 // instead of stderr (where they normally should be). The current version of
1887 // the gui expects both messages to come in on the stdout stream, but due to the
1888 // recent logger changes, they now come in on the stderr stream instead (because
1889 // stdout was duped to stderr by the new logger logic) thus causing the gui to
1890 // miss seeing them without the below fix. The below fix simply corrects for the
1891 // problem by simply writing the two messages to the stdout stream where older
1892 // versions of the gui expect to see them.
1893 
gui_debug_cpu_state(REGS * pREGS)1894 void*  gui_debug_cpu_state ( REGS* pREGS )
1895 {
1896 void *(*next_debug_call)(REGS *);
1897 
1898     static BOOL bLoading = FALSE;
1899     static BOOL bStopped = FALSE;
1900 
1901     if (sysblk.shutdown) return NULL;
1902 
1903     if (pTargetCPU_REGS && pREGS != pTargetCPU_REGS)
1904         return NULL;
1905 
1906     if (bLoading != (pREGS->loadstate ? TRUE : FALSE))
1907     {
1908         bLoading  = (pREGS->loadstate ? TRUE : FALSE);
1909         gui_fprintf(stdout,"LOAD=%c\n", bLoading ? '1' : '0');
1910     }
1911 
1912     if (bStopped != ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE))
1913     {
1914         bStopped  = ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE);
1915         gui_fprintf(stdout,"MAN=%c\n", bStopped ? '1' : '0');
1916     }
1917 
1918     if((next_debug_call = HDL_FINDNXT( gui_debug_cpu_state )))
1919         return next_debug_call( pREGS );
1920 
1921     return NULL;    // (I have no idea why this is a void* func)
1922 }
1923 
1924 ///////////////////////////////////////////////////////////////////////////////
1925 // Our Hercules "debug_cd_cmd" hook...
1926 //
1927 // The following function is called by the 'cd_cmd' panel command to notify
1928 // the GUI of what the new current directory was just changed to...
1929 
gui_debug_cd_cmd(char * pszCWD)1930 void* gui_debug_cd_cmd( char* pszCWD )
1931 {
1932     ASSERT( pszCWD );
1933     if (gui_version >= 1.12)
1934         gui_fprintf( fStatusStream, "]CWD=%s\n", pszCWD );
1935     return NULL;
1936 }
1937 
1938 ///////////////////////////////////////////////////////////////////////////////
1939 // Streams 'fprintf' function to prevent interleaving collision problem...
1940 
1941 LOCK gui_fprintf_lock;
1942 
gui_fprintf(FILE * stream,const char * pszFormat,...)1943 void gui_fprintf( FILE* stream, const char* pszFormat, ... )
1944 {
1945     va_list vl;
1946     va_start( vl, pszFormat );
1947     obtain_lock ( &gui_fprintf_lock );
1948     vfprintf( stream, pszFormat, vl );
1949     fflush( stream );
1950     release_lock( &gui_fprintf_lock );
1951 }
1952 
1953 ///////////////////////////////////////////////////////////////////////////////
1954 // Acquire any resources we need in order to operate...
1955 // (called by 'gui_panel_display' before main loop initiates...)
1956 
Initialize()1957 void  Initialize ()
1958 {
1959     // Initialize streams...
1960 
1961     fOutputStream = OUTPUT_STREAM_FILE_PTR;
1962     fStatusStream = STATUS_STREAM_FILE_PTR;
1963 
1964     nInputStreamFileNum = fileno( INPUT_STREAM_FILE_PTR );
1965 
1966     // Allocate input stream buffer...
1967 
1968     if (!(pszInputBuff = (char *) malloc( nInputBuffSize )))
1969     {
1970         fprintf(stderr,
1971             _("HHCDG006S malloc pszInputBuff failed: %s\n")
1972             ,strerror(errno));
1973         exit(0);
1974     }
1975 
1976     memset(pszInputBuff, 0, nInputBuffSize);
1977     nInputLen = 0;
1978 
1979     // Allocate command processing buffer...
1980 
1981     if (!(pszCommandBuff = (char *) malloc( nCommandBuffSize )))
1982     {
1983         fprintf(stderr,
1984             _("HHCDG007S malloc pszCommandBuff failed: %s\n")
1985             ,strerror(errno));
1986         exit(0);
1987     }
1988 
1989     memset(pszCommandBuff, 0, nCommandBuffSize);
1990     nCommandLen = 0;
1991 
1992     // Initialize some variables...
1993 
1994     HandleForcedRefresh();
1995 }
1996 
1997 ///////////////////////////////////////////////////////////////////////////////
1998 // Release any resources we acquired in order to operate...
1999 // (called by 'gui_panel_display' when main loop terminates...)
2000 
Cleanup()2001 void Cleanup()
2002 {
2003     if  (pszInputBuff)
2004     free(pszInputBuff);
2005 
2006     if  (pszCommandBuff)
2007     free(pszCommandBuff);
2008 }
2009 
2010 ///////////////////////////////////////////////////////////////////////////////
2011 // Hercules  "daemon_task"  -or-  "panel_display"  override...
2012 
gui_panel_display()2013 void gui_panel_display ()
2014 {
2015 static char *DisQuietCmd[] = { "$zapcmd", "quiet", "NoCmd" };
2016 
2017     SET_THREAD_NAME("dyngui");
2018 
2019     ProcessConfigCommand(3,DisQuietCmd,NULL); // Disable the quiet command
2020 
2021     if ( !bDoneProcessing )
2022     {
2023         logmsg(_("HHCDG001I dyngui.dll initiated\n"));
2024         Initialize();               // (allocate buffers, etc)
2025         ProcessingLoop();           // (primary processing loop)
2026         logmsg(_("HHCDG002I dyngui.dll terminated\n"));
2027         Cleanup();                  // (de-allocate resources)
2028     }
2029 }
2030 
2031 /*****************************************************************************\
2032                  Hercules Dynamic Loader control sections...
2033 \*****************************************************************************/
2034 /*
2035    Note that ALL of the below "sections" are actually just simple functions
2036    that Hercules's dynamic loader logic calls, thus allowing you to insert
2037    whatever 'C' code you may need directly into any of the below sections.
2038 */
2039 ///////////////////////////////////////////////////////////////////////////////
2040 //                        HDL_DEPENDENCY_SECTION
2041 // The following are the various Hercules structures whose layout this module
2042 // depends on. The layout of the following structures (size and version) MUST
2043 // match the layout that was used to build Hercules with. If the size/version
2044 // of any of the following structures changes (and a new version of Hercules
2045 // is built using the new layout), then THIS module must also be built with
2046 // the new layout as well. The layout (size/version) of the structure as it
2047 // was when Hercules was built MUST MATCH the layout as it was when THIS DLL
2048 // was built)
2049 
2050 /* Libtool static name colision resolution */
2051 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
2052 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
2053 #define hdl_ddev dyngui_LTX_hdl_ddev
2054 #define hdl_depc dyngui_LTX_hdl_depc
2055 #define hdl_reso dyngui_LTX_hdl_reso
2056 #define hdl_init dyngui_LTX_hdl_init
2057 #define hdl_fini dyngui_LTX_hdl_fini
2058 #endif
2059 
2060 HDL_DEPENDENCY_SECTION;         // (define module dependencies)
2061 
2062     HDL_DEPENDENCY ( HERCULES );        // Hercules itself
2063     HDL_DEPENDENCY ( SYSBLK   );        // Master control block
2064     HDL_DEPENDENCY ( REGS     );        // CPU regs and such
2065     HDL_DEPENDENCY ( DEVBLK   );        // Device info block
2066 
2067 END_DEPENDENCY_SECTION
2068 
2069 ///////////////////////////////////////////////////////////////////////////////
2070 //                        HDL_REGISTER_SECTION
2071 // The following section defines the entry points within Hercules that THIS
2072 // module is overriding (replacing). That is to say, THIS module's functions
2073 // will be called by Hercules instead of the normal Hercules function (if any).
2074 // The functions defined below thus provide additional/different functionality
2075 // above/beyond the functionality normally provided by Hercules. (Of course,
2076 // yet OTHER dlls may have further overridden whatever overrides we register
2077 // here, such as would likely be the case for panel command overrides).
2078 
2079 HDL_REGISTER_SECTION;           // ("Register" our entry-points)
2080 {
2081     // Perform static module initialization...
2082 
2083     gui_nounload = 1;                       // (reject any unload attempt)
2084     initialize_lock( &gui_fprintf_lock );   // (initialize GUI fprintf LOCK)
2085 
2086     // Register all of our override entry-points...
2087 
2088     //             Hercules's       Our
2089     //             registered       overriding
2090     //             entry-point      entry-point
2091     //             name             value
2092     HDL_REGISTER ( panel_display,   gui_panel_display   );// (Yep! We override EITHER!)
2093     HDL_REGISTER ( daemon_task,     gui_panel_display   );// (Yep! We override EITHER!)
2094     HDL_REGISTER ( debug_cpu_state, gui_debug_cpu_state );
2095     HDL_REGISTER ( debug_cd_cmd,    gui_debug_cd_cmd    );
2096     HDL_REGISTER ( panel_command,   gui_panel_command   );
2097 }
2098 END_REGISTER_SECTION
2099 
2100 #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL )
2101 #if !defined( _MSVC_ )
2102   #undef sysblk
2103 #endif
2104 ///////////////////////////////////////////////////////////////////////////////
2105 //                        HDL_RESOLVER_SECTION
2106 // The following section "resolves" entry-points that this module needs. The
2107 // below HDL_RESOLVE entries define the names of Hercules's registered entry-
2108 // points that we need "imported" to us (so that we may call those functions
2109 // directly ourselves). The HDL_RESOLVE_PTRVAR entries set the named pointer
2110 // variable value (i.e. the name of OUR pointer variable) to the registered
2111 // entry-point value that was registered by Hercules or some other DLL.
2112 
2113 HDL_RESOLVER_SECTION;           // ("Resolve" needed entry-points)
2114 {
2115     //            Registered
2116     //            entry-points
2117     //            that we call
2118     HDL_RESOLVE ( panel_command );
2119 
2120 #if !defined( _MSVC_ )
2121     //                    Our pointer-     Registered entry-
2122     //                    variable name    point value name
2123     HDL_RESOLVE_PTRVAR (  psysblk,           sysblk         );
2124 #endif
2125 }
2126 END_RESOLVER_SECTION
2127 #endif
2128 
2129 ///////////////////////////////////////////////////////////////////////////////
2130 //                        HDL_FINAL_SECTION
2131 // The following section defines what should be done immediately before this
2132 // module is unloaded. It is nothing more than a function that is called by
2133 // Hercules just before your module is unloaded. You can do anything you want
2134 // but the normal thing to do is release any resources that were acquired when
2135 // your module was loaded (e.g. release memory that was malloc'ed, etc).
2136 
2137 HDL_FINAL_SECTION;
2138 {
2139     bDoneProcessing = TRUE;     // (tell main loop to stop processing)
2140 
2141     usleep(100000);             // (brief delay to give GUI time
2142                                 //  to display ALL shutdown msgs)
2143     return gui_nounload;        // (reject unloads when activated)
2144 }
2145 END_FINAL_SECTION
2146 
2147 ///////////////////////////////////////////////////////////////////////////////
2148 
2149 #endif /*defined(OPTION_DYNAMIC_LOAD)*/
2150 
2151 #endif // EXTERNALGUI
2152