forked from SDL-Hercules-390/hyperion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dyngui.c
1274 lines (977 loc) · 42.5 KB
/
dyngui.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*********************************************************************/
/* DYNGUI.C Hercules External GUI Interface DLL */
/* (c) Copyright "Fish" (David B. Trout), 2003-2006 */
/* */
/* Primary contact: Fish [[email protected]] */
/* */
/*********************************************************************/
/* */
/* Change log: */
/* */
/* mm/dd/yy Description... */
/* -------- ------------------------------------------------------- */
/* */
/* 06/22/03 Created. */
/* 05/29/04 Minor fix to UpdateTargetCPU, remove max MIPS rate */
/* check in UpdateCPUStatus (trust Herc to be correct), */
/* use Herc-calculate MIPS/SIOS rate. */
/* 06/01/04 Minor fix to detect switching to a different displayed */
/* (target) CPU when no other status has otherwise changed.*/
/* 06/09/04 Minor fix to UpdateDeviceStatus for terminal devices. */
/* 07/28/04 Minor fix to UpdateDeviceStatus for non-terminal devices*/
/* 10/04/04 Change default maxrates interval to 1440 mins (1 day). */
/* 03/12/05 Win32 port... */
/* 04/22/05 Win32 port continued... */
/* 04/24/05 Move "maxrates" command and variables to panel.c */
/* 05/05/05 Fix streams collision issue via locking (gui_fprintf) */
/* 05/13/05 Fix crash @ shutdown when initiated externally. */
/* 08/17/05 Moved "high water mark" code to panel.c. */
/* 09/20/05 sysblk.mipsrate now per second instead of millisecond */
/* 11/18/05 Fix crash in UpdateTargetCPU when NUMCPU=0 (as it might */
/* be when, e.g., running as a shared device server mode) */
/* 11/18/05 Show offline CPUs as OFFLINE. */
/* 12/01/05 SetCurrentDirectory support for shell commands */
/* */
/*********************************************************************/
#include "hstdinc.h"
#include "hercules.h" // (#includes "config." w/#define for VERSION)
#ifdef EXTERNALGUI
#if defined(OPTION_DYNAMIC_LOAD)
#include "devtype.h"
#include "opcode.h"
///////////////////////////////////////////////////////////////////////////////
// Some handy macros... (feel free to add these to hercules.h)
#ifndef min
#define min(a,b) (((a) <= (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) >= (b)) ? (a) : (b))
#endif
#define MINMAX(var,low,high) ((var) = min(max((var),(low)),(high)))
#ifndef BOOL
#define BOOL BYTE
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
///////////////////////////////////////////////////////////////////////////////
// Our global variables... (initialized by our "Initialize" function)
#define INPUT_STREAM_FILE_PTR ( stdin )
#define OUTPUT_STREAM_FILE_PTR ( stdout )
#define STATUS_STREAM_FILE_PTR ( stderr )
#define MAX_COMMAND_LEN ( 1024 )
#define DEF_MAXRATES_RPT_INTVL ( 1440 )
#if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL )
#if !defined( _MSVC_ )
SYSBLK *psysblk; // (ptr to Herc's SYSBLK structure)
#define sysblk (*psysblk)
#endif
#endif
static FILE* fOutputStream = NULL; // (stdout stream)
static FILE* fStatusStream = NULL; // (stderr stream)
static int nInputStreamFileNum = -1; // (file descriptor for stdin stream)
static int gui_nounload = 1; // (nounload indicator)
// The device query buffer SHOULD be the maximum device filename length
// plus the maximum descriptive length of any/all options for the device,
// but there is no #define for either so we have no choice but to impose
// our own maximum.
#define MAX_DEVICEQUERY_LEN ( 1024 + 256 )
///////////////////////////////////////////////////////////////////////////////
// Some forward references... (our own functions that we call)
void Initialize ();
void ProcessingLoop ();
void Cleanup ();
void UpdateTargetCPU ();
void ReadInputData (size_t nTimeoutMillsecs);
void ProcessInputData ();
void* gui_panel_command (char* pszCommand);
void UpdateStatus ();
void UpdateCPUStatus ();
void UpdateRegisters ();
void UpdateDeviceStatus ();
void NewUpdateDevStats ();
void gui_fprintf( FILE* stream, const char* pszFormat, ... );
///////////////////////////////////////////////////////////////////////////////
// Our main processing loop...
BOOL bDoneProcessing = FALSE; // (set to TRUE to exit)
void ProcessingLoop()
{
// Notify logger_thread we're in control
sysblk.panel_init = 1;
// Our main purpose in life: read input stream and process
// any commands that may be entered, and send periodic status
// information back to the external gui via its status stream.
// Note we only exit whenever our bDoneProcessing flag is set
// which is normally not done until just before Herc unloads
// us which is normally not done until immediately before it
// terminates.
// Also note we re-retrieve sysblk.panrate each iteration
// since it could change from one iteration to the next as a result
// of the Hercules "panrate" command being entered and processed.
while (!bDoneProcessing)
{
UpdateTargetCPU(); // ("cpu" command could have changed it)
UpdateStatus(); // (keep sending status back to gui...)
ReadInputData( sysblk.panrate );
ProcessInputData(); // (if there even is any of course...)
}
}
///////////////////////////////////////////////////////////////////////////////
REGS* pTargetCPU_REGS = NULL; // target CPU for commands and displays
REGS* pPrevTargetCPU_REGS = NULL; // target CPU for commands and displays
int pcpu = 0, prev_pcpu = 0; // target cpu#
///////////////////////////////////////////////////////////////////////////////
void UpdateTargetCPU ()
{
if (sysblk.shutdown) return;
// Use the requested CPU for our status information
// unless it's no longer online (enabled), in which case
// we'll default to the first one we find that's online
// sysblk.cpus = number online cpu's
// sysblk.pcpu = panel target cpu
// pTargetCPU_REGS -> panel target cpu
OBTAIN_INTLOCK(NULL);
if (pcpu != sysblk.pcpu)
pcpu = sysblk.pcpu;
if (pcpu >= MAX_CPU)
pcpu = sysblk.pcpu = 0;
if (sysblk.cpus && pcpu >= 0 && IS_CPU_ONLINE(pcpu))
pTargetCPU_REGS = sysblk.regs[pcpu];
else
{
// We *MUST* have a cpu and registers to work with!
pTargetCPU_REGS = &sysblk.dummyregs;
if (pcpu >= 0)
pcpu = -pcpu; // (indicates dummy/offline cpu)
}
// If SIE is active, use the guest regs rather than the host regs...
#if defined(_FEATURE_SIE)
if (pTargetCPU_REGS->sie_active)
pTargetCPU_REGS = pTargetCPU_REGS->guestregs;
#endif
RELEASE_INTLOCK(NULL);
}
///////////////////////////////////////////////////////////////////////////////
char* pszInputBuff = NULL; // ptr to buffer
int nInputBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is
int nInputLen = 0; // amount of data it's holding
///////////////////////////////////////////////////////////////////////////////
void ReadInputData ( size_t nTimeoutMillsecs )
{
size_t nMaxBytesToRead;
int nBytesRead;
char* pReadBuffer;
// Wait for keyboard input data to arrive...
#if !defined( _MSVC_ )
fd_set input_fd_set;
struct timeval wait_interval_timeval;
int rc;
FD_ZERO ( &input_fd_set );
FD_SET ( nInputStreamFileNum, &input_fd_set );
wait_interval_timeval.tv_sec = nTimeoutMillsecs / 1000;
wait_interval_timeval.tv_usec = (nTimeoutMillsecs % 1000) * 1000;
if ((rc = select( nInputStreamFileNum+1, &input_fd_set, NULL, NULL, &wait_interval_timeval )) < 0)
{
if (HSO_EINTR == HSO_errno)
return; // (we were interrupted by a signal)
// A bona fide error occurred; abort...
logmsg
(
_("HHCDG003S select failed on input stream: %s\n")
,strerror(HSO_errno)
);
bDoneProcessing = TRUE; // (force main loop to exit)
return;
}
// Has keyboard input data indeed arrived yet?
if (!FD_ISSET( nInputStreamFileNum, &input_fd_set ))
return; // (nothing for us to do...)
#endif // !defined( _MSVC_ )
// Ensure our buffer never overflows... (-2 because
// we need room for at least 1 byte + NULL terminator)
MINMAX(nInputLen,0,(nInputBuffSize-2));
// Read input data into next available buffer location...
// (nMaxBytesToRead-1 == room for NULL terminator)
pReadBuffer = (pszInputBuff + nInputLen);
nMaxBytesToRead = (nInputBuffSize - nInputLen) - 1;
#if !defined( _MSVC_ )
if ((nBytesRead = read( nInputStreamFileNum, pReadBuffer, nMaxBytesToRead )) < 0)
{
if (EINTR == errno)
return; // (we were interrupted by a signal)
// A bona fide error occurred; abort...
logmsg
(
_("HHCDG004S read failed on input stream: %s\n")
,strerror(errno)
);
bDoneProcessing = TRUE; // (force main loop to exit)
return;
}
#else // defined( _MSVC_ )
if ( ( nBytesRead = w32_get_stdin_char( pReadBuffer, nTimeoutMillsecs ) ) <= 0 )
return;
#endif // !defined( _MSVC_ )
// Update amount of input data we have and
// ensure that it's always NULL terminated...
MINMAX(nBytesRead,0,nInputBuffSize);
nInputLen += nBytesRead;
MINMAX(nInputLen,0,(nInputBuffSize-1));
*(pszInputBuff + nInputLen) = 0;
}
///////////////////////////////////////////////////////////////////////////////
char* pszCommandBuff = NULL; // ptr to buffer
int nCommandBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is
int nCommandLen = 0; // amount of data it's holding
///////////////////////////////////////////////////////////////////////////////
// Process the data we just read from the input stream...
void ProcessInputData ()
{
char* pNewLineChar;
// Ensure our buffer is NULL terminated...
MINMAX(nInputLen,0,(nInputBuffSize-1));
*(pszInputBuff + nInputLen) = 0;
// Input commands are delimited by newline characters...
while (nInputLen && (pNewLineChar = strchr(pszInputBuff,'\n')) != NULL)
{
// Extract command from input buffer
// into our command processing buffer...
nCommandLen = (pNewLineChar - pszInputBuff);
MINMAX(nCommandLen,0,(nCommandBuffSize-1));
memcpy(pszCommandBuff, pszInputBuff, nCommandLen);
*(pszCommandBuff + nCommandLen) = 0;
// Process the extracted command...
// Note that we always call the registered "panel_command" function
// rather than call our "gui_panel_command" function directly. This
// is in case some other DLL has overridden OUR command handler...
panel_command ( pszCommandBuff ); // (call registered handler)
// Shift remaining data back to beginning of input buffer...
nInputLen = ((pszInputBuff + nInputLen) - (pNewLineChar+1));
MINMAX(nInputLen,0,(nInputBuffSize-1));
memmove(pszInputBuff,pNewLineChar+1,nInputLen);
*(pszInputBuff + nInputLen) = 0;
}
}
///////////////////////////////////////////////////////////////////////////////
// (These are actually boolean flags..)
BYTE gui_wants_gregs = 1;
BYTE gui_wants_cregs = 1;
BYTE gui_wants_aregs = 1;
BYTE gui_wants_fregs = 1;
BYTE gui_wants_devlist = 1;
BYTE gui_wants_new_devlist = 0;
#if defined(OPTION_MIPS_COUNTING)
BYTE gui_wants_cpupct = 0;
#endif
#ifdef OPTION_MIPS_COUNTING
U32 prev_mips_rate = 0;
U32 prev_sios_rate = 0;
#endif
///////////////////////////////////////////////////////////////////////////////
// Our Hercules "panel_command" override...
void* gui_panel_command (char* pszCommand)
{
void* (*next_panel_command_handler)(char* pszCommand);
// Special GUI commands start with ']'. At the moment, all these special
// gui commands tell us is what status information it's interested in...
if ( ']' != *pszCommand )
goto NotSpecialGUICommand;
pszCommand++; // (bump past ']')
if (strncasecmp(pszCommand,"SCD=",4) == 0)
{
SetCurrentDirectory(pszCommand+4);
return NULL;
}
if (strncasecmp(pszCommand,"GREGS=",6) == 0)
{
gui_wants_gregs = atoi(pszCommand+6);
return NULL;
}
if (strncasecmp(pszCommand,"CREGS=",6) == 0)
{
gui_wants_cregs = atoi(pszCommand+6);
return NULL;
}
if (strncasecmp(pszCommand,"AREGS=",6) == 0)
{
gui_wants_aregs = atoi(pszCommand+6);
return NULL;
}
if (strncasecmp(pszCommand,"FREGS=",6) == 0)
{
gui_wants_fregs = atoi(pszCommand+6);
return NULL;
}
if (strncasecmp(pszCommand,"DEVLIST=",8) == 0)
{
gui_wants_devlist = atoi(pszCommand+8);
if ( gui_wants_devlist )
gui_wants_new_devlist = 0;
return NULL;
}
if (strncasecmp(pszCommand,"NEWDEVLIST=",11) == 0)
{
gui_wants_new_devlist = atoi(pszCommand+11);
if ( gui_wants_new_devlist )
gui_wants_devlist = 0;
return NULL;
}
if (strncasecmp(pszCommand,"MAINSTOR=",9) == 0)
{
gui_fprintf(fStatusStream,"MAINSTOR=%"UINT_PTR_FMT"d\n",(uintptr_t)pTargetCPU_REGS->mainstor);
// Here's a trick! Hercules reports its version number to the GUI
// by means of the MAINSIZE value! Later releases of HercGUI know
// to interpret mainsizes less than 1000 as Hercule's version number.
// Earlier versions of HercGUI will simply try to interpret it as
// the actual mainsize, but no real harm is done since we immediately
// send it the CORRECT mainsize immediately afterwards. This allows
// future versions of HercGUI to know whether the version of Hercules
// that it's talking to supports a given feature or not. Slick, eh? :)
gui_fprintf(fStatusStream,"MAINSIZE=%s\n",VERSION);
gui_fprintf(fStatusStream,"MAINSIZE=%d\n",(U32)sysblk.mainsize);
return NULL;
}
#if defined(OPTION_MIPS_COUNTING)
if (strncasecmp(pszCommand,"CPUPCT=",7) == 0)
{
gui_wants_cpupct = atoi(pszCommand+7);
return NULL;
}
#endif
// Silently ignore any unrecognized special GUI commands...
return NULL; // (silently ignore it)
NotSpecialGUICommand:
// Ignore "commands" that are actually just comments (start with '*' or '#')
if ('*' == pszCommand[0] || '#' == pszCommand[0])
{
logmsg("%s\n",pszCommand); // (log comment to console)
return NULL; // (and otherwise ignore it)
}
// Otherwise it's not a command that we handle. Call the next higher
// level command handler which, under normal circumstances SHOULD be
// Hercules's "panel_command" function, but which MAY have been over-
// ridden by yet some OTHER dynamically loaded command handler...
next_panel_command_handler = HDL_FINDNXT( gui_panel_command );
if (!next_panel_command_handler) // (extremely unlikely!)
return NULL; // (extremely unlikely!)
return next_panel_command_handler( pszCommand );
}
///////////////////////////////////////////////////////////////////////////////
QWORD psw, prev_psw;
BYTE wait_bit;
BYTE prev_cpustate = 0xFF;
U64 prev_instcount = 0;
///////////////////////////////////////////////////////////////////////////////
// Send status information messages back to the gui...
void UpdateStatus ()
{
BOOL bStatusChanged = FALSE; // (whether or not anything has changed)
if (sysblk.shutdown) return;
copy_psw(pTargetCPU_REGS, psw);
wait_bit = (psw[1] & 0x02);
// The SYS light and %CPU-Utilization
// information we send *ALL* the time...
if (!(0
|| CPUSTATE_STOPPING == pTargetCPU_REGS->cpustate
|| CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate
))
{
gui_fprintf(fStatusStream,
"SYS=%c\n"
,wait_bit ? '0' : '1'
);
}
#if defined(OPTION_MIPS_COUNTING)
if (gui_wants_cpupct)
{
char cpupct[10];
if (CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate)
strcpy(cpupct,"0");
else
snprintf(cpupct,sizeof(cpupct),
"%1.0f",(100.0 * pTargetCPU_REGS->cpupct));
if (isdigit(cpupct[0]))
{
gui_fprintf(fStatusStream,
"CPUPCT=%s\n"
,cpupct
);
}
}
#endif
// Determine if we need to inform the GUI of anything...
bStatusChanged = FALSE; // (whether or not anything has changed)
if (0
|| pTargetCPU_REGS != pPrevTargetCPU_REGS
|| pcpu != prev_pcpu
|| memcmp(prev_psw, psw, sizeof(prev_psw)) != 0
|| prev_cpustate != pTargetCPU_REGS->cpustate
|| (prev_instcount != (
#if defined(_FEATURE_SIE)
SIE_MODE(pTargetCPU_REGS) ? pTargetCPU_REGS->hostregs->instcount :
#endif
pTargetCPU_REGS->instcount)
)
)
{
bStatusChanged = TRUE; // (something has indeed changed...)
// Save new values for next time...
pPrevTargetCPU_REGS = pTargetCPU_REGS;
prev_pcpu = pcpu;
memcpy(prev_psw, psw, sizeof(prev_psw));
prev_cpustate = pTargetCPU_REGS->cpustate;
prev_instcount = (
#if defined(_FEATURE_SIE)
SIE_MODE(pTargetCPU_REGS) ? pTargetCPU_REGS->hostregs->instcount :
#endif
pTargetCPU_REGS->instcount);
}
// If anything has changed, inform the GUI...
if (bStatusChanged)
{
UpdateCPUStatus(); // (update the status line info...)
UpdateRegisters(); // (update the registers display...)
}
// PROGRAMMING NOTE: my original [rather poorly designed I admit] logic
// sent device status messages to the GUI *continuously* (i.e. all the
// time), even when both Herc and the channel subsystem was idle. This
// proved to be terribly inefficient, causing the GUI to consume *FAR*
// too much valuable CPU cycles parsing all of those messages.
// Thus, starting with this version of dyngui, we now only send device
// status messages to the GUI only whenever the device's status actually
// changes, but only if it (the GUI) specifically requests such notifi-
// cations of course (via the new "]NEWDEVLIST=" special message).
// The new(er) version of HercGUI understands (and thus requests) these
// newer format device status messages, but older versions of HercGUI
// of course do not. Thus in order to remain compatible with the current
// (older) version of the GUI, we still need to support the inefficient
// technique of constantly sending a constant stream of device status
// messages.
// Eventually at some point this existing original inefficient technique
// logic will be removed (once everyone has had time to upgrade to the
// newer version of HercGUI), but for now, at least for the next couple
// of HercGUI release cycles, we need to keep it.
if (gui_wants_devlist) // (if the device list is visible)
UpdateDeviceStatus(); // (update the list of devices...)
else // (the two options are mutually exclusive from one another)
if (gui_wants_new_devlist) // (if the device list is visible)
NewUpdateDevStats(); // (update the list of devices...)
}
///////////////////////////////////////////////////////////////////////////////
// Send status information messages back to the gui...
void UpdateCPUStatus ()
{
if (sysblk.shutdown) return;
if (pTargetCPU_REGS == &sysblk.dummyregs || pcpu < 0)
{
// pTargetCPU_REGS == &sysblk.dummyregs; cpu is offline
gui_fprintf(fStatusStream, "STATUS="
"CPU%4.4X (((((((((((((((((((((((( OFFLINE ))))))))))))))))))))))))\n"
,pcpu < 0 ? -pcpu : pcpu);
}
else // pTargetCPU_REGS != &sysblk.dummyregs; cpu is online
{
// CPU status line... (PSW, status indicators, and instruction count)
gui_fprintf(fStatusStream, "STATUS="
"CPU%4.4X "
"PSW=%2.2X%2.2X%2.2X%2.2X "
"%2.2X%2.2X%2.2X%2.2X "
"%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X "
"%c%c%c%c%c%c%c%c "
"instcount=%" I64_FMT "u\n"
,pTargetCPU_REGS->cpuad
,psw[0], psw[1], psw[2], psw[3]
,psw[4], psw[5], psw[6], psw[7]
,psw[8], psw[9], psw[10], psw[11], psw[12], psw[13], psw[14], psw[15]
,CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate ? 'M' : '.'
,sysblk.inststep ? 'T' : '.'
,wait_bit ? 'W' : '.'
,pTargetCPU_REGS->loadstate ? 'L' : '.'
,pTargetCPU_REGS->checkstop ? 'C' : '.'
,PROBSTATE(&pTargetCPU_REGS->psw) ? 'P' : '.'
,
#if defined(_FEATURE_SIE)
SIE_MODE(pTargetCPU_REGS) ? 'S' : '.'
#else // !defined(_FEATURE_SIE)
'.'
#endif // defined(_FEATURE_SIE)
,
#if defined(_900)
ARCH_900 == pTargetCPU_REGS->arch_mode ? 'Z' : '.'
#else // !defined(_900)
'.'
#endif // defined(_900)
,(long long)(
#if defined(_FEATURE_SIE)
SIE_MODE(pTargetCPU_REGS) ? pTargetCPU_REGS->hostregs->instcount :
#endif // defined(_FEATURE_SIE)
pTargetCPU_REGS->instcount)
);
} // endif cpu is online/offline
// MIPS rate and SIOS rate...
#if defined(OPTION_MIPS_COUNTING)
// MIPS rate...
if (sysblk.mipsrate != prev_mips_rate)
{
gui_fprintf(fStatusStream,
"MIPS=%2.1d.%2.2d\n"
, sysblk.mipsrate / 1000000
,(sysblk.mipsrate % 1000000) / 10000
);
prev_mips_rate = sysblk.mipsrate;
}
// SIOS rate...
if (sysblk.siosrate != prev_sios_rate)
{
gui_fprintf(fStatusStream,
"SIOS=%5d\n"
,sysblk.siosrate
);
prev_sios_rate = sysblk.siosrate;
}
update_maxrates_hwm(); // (update high-water-mark values)
#endif // defined(OPTION_MIPS_COUNTING)
}
///////////////////////////////////////////////////////////////////////////////
// Send status information messages back to the gui...
void UpdateRegisters ()
{
if (sysblk.shutdown) return;
if (gui_wants_gregs)
{
gui_fprintf(fStatusStream,
"GR0-3=%8.8X %8.8X %8.8X %8.8X\n"
"GR4-7=%8.8X %8.8X %8.8X %8.8X\n"
"GR8-B=%8.8X %8.8X %8.8X %8.8X\n"
"GRC-F=%8.8X %8.8X %8.8X %8.8X\n"
,pTargetCPU_REGS->GR_L(0)
,pTargetCPU_REGS->GR_L(1)
,pTargetCPU_REGS->GR_L(2)
,pTargetCPU_REGS->GR_L(3)
,pTargetCPU_REGS->GR_L(4)
,pTargetCPU_REGS->GR_L(5)
,pTargetCPU_REGS->GR_L(6)
,pTargetCPU_REGS->GR_L(7)
,pTargetCPU_REGS->GR_L(8)
,pTargetCPU_REGS->GR_L(9)
,pTargetCPU_REGS->GR_L(10)
,pTargetCPU_REGS->GR_L(11)
,pTargetCPU_REGS->GR_L(12)
,pTargetCPU_REGS->GR_L(13)
,pTargetCPU_REGS->GR_L(14)
,pTargetCPU_REGS->GR_L(15)
);
}
if (gui_wants_cregs)
{
gui_fprintf(fStatusStream,
"CR0-3=%8.8X %8.8X %8.8X %8.8X\n"
"CR4-7=%8.8X %8.8X %8.8X %8.8X\n"
"CR8-B=%8.8X %8.8X %8.8X %8.8X\n"
"CRC-F=%8.8X %8.8X %8.8X %8.8X\n"
,pTargetCPU_REGS->CR_L(0)
,pTargetCPU_REGS->CR_L(1)
,pTargetCPU_REGS->CR_L(2)
,pTargetCPU_REGS->CR_L(3)
,pTargetCPU_REGS->CR_L(4)
,pTargetCPU_REGS->CR_L(5)
,pTargetCPU_REGS->CR_L(6)
,pTargetCPU_REGS->CR_L(7)
,pTargetCPU_REGS->CR_L(8)
,pTargetCPU_REGS->CR_L(9)
,pTargetCPU_REGS->CR_L(10)
,pTargetCPU_REGS->CR_L(11)
,pTargetCPU_REGS->CR_L(12)
,pTargetCPU_REGS->CR_L(13)
,pTargetCPU_REGS->CR_L(14)
,pTargetCPU_REGS->CR_L(15)
);
}
if (gui_wants_aregs)
{
gui_fprintf(fStatusStream,
"AR0-3=%8.8X %8.8X %8.8X %8.8X\n"
"AR4-7=%8.8X %8.8X %8.8X %8.8X\n"
"AR8-B=%8.8X %8.8X %8.8X %8.8X\n"
"ARC-F=%8.8X %8.8X %8.8X %8.8X\n"
,pTargetCPU_REGS->AR(0)
,pTargetCPU_REGS->AR(1)
,pTargetCPU_REGS->AR(2)
,pTargetCPU_REGS->AR(3)
,pTargetCPU_REGS->AR(4)
,pTargetCPU_REGS->AR(5)
,pTargetCPU_REGS->AR(6)
,pTargetCPU_REGS->AR(7)
,pTargetCPU_REGS->AR(8)
,pTargetCPU_REGS->AR(9)
,pTargetCPU_REGS->AR(10)
,pTargetCPU_REGS->AR(11)
,pTargetCPU_REGS->AR(12)
,pTargetCPU_REGS->AR(13)
,pTargetCPU_REGS->AR(14)
,pTargetCPU_REGS->AR(15)
);
}
if (gui_wants_fregs)
{
gui_fprintf(fStatusStream,
"FR0-2=%8.8X %8.8X %8.8X %8.8X\n"
"FR4-6=%8.8X %8.8X %8.8X %8.8X\n"
,pTargetCPU_REGS->fpr[0]
,pTargetCPU_REGS->fpr[1]
,pTargetCPU_REGS->fpr[2]
,pTargetCPU_REGS->fpr[3]
,pTargetCPU_REGS->fpr[4]
,pTargetCPU_REGS->fpr[5]
,pTargetCPU_REGS->fpr[6]
,pTargetCPU_REGS->fpr[7]
);
}
}
///////////////////////////////////////////////////////////////////////////////
char szQueryDeviceBuff[ MAX_DEVICEQUERY_LEN + 1 ]; // (always +1 for safety!)
///////////////////////////////////////////////////////////////////////////////
// Send status information messages back to the gui... (VERY inefficient!)
void UpdateDeviceStatus ()
{
DEVBLK* pDEVBLK;
char* pDEVClass;
BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
if (sysblk.shutdown) return;
// Process ALL the devices in the entire configuration each time...
for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
{
// Does this device actually exist in the configuration?
if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
continue; // (no, skip)
// Retrieve this device's filename and optional settings parameter values...
szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
(pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?)
{
logmsg
(
_("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
,pDEVBLK->devnum
);
}
szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination)
// Device status flags...
chOnlineStat =
chBusyStat =
chPendingStat =
chOpenStat = '0';
if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1';
if (pDEVBLK->busy) chBusyStat = '1';
if (IOPENDING(pDEVBLK)) chPendingStat = '1';
if (pDEVBLK->fd > max(STDIN_FILENO,max(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1';
// Send status message back to gui...
gui_fprintf(fStatusStream,
"DEV=%4.4X %4.4X %-4.4s %c%c%c%c %s\n"
,pDEVBLK->devnum
,pDEVBLK->devtype
,pDEVClass
,chOnlineStat
,chBusyStat
,chPendingStat
,chOpenStat
,szQueryDeviceBuff
);
}
// Since the device list can be in any order and devices can be added
// and/or removed at any time, the GUI needs to know "That's all the
// devices there are" so that it can detect when devices are removed...
gui_fprintf(fStatusStream, "DEV=X\n"); // (indicates end of list)
}
///////////////////////////////////////////////////////////////////////////////
// Send device status msgs to the gui IF NEEDED... (slightly more efficient)
#ifdef EXTERNALGUI
void NewUpdateDevStats ()
{
DEVBLK* pDEVBLK;
GUISTAT* pGUIStat;
char* pDEVClass;
BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
BOOL bUpdatesSent = FALSE;
if (sysblk.shutdown) return;
// Process ALL the devices in the entire configuration each time...
// (But only send device status messages to the GUI only when the
// device's status actually changes and not continuously like before)
for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
{
pGUIStat = pDEVBLK->pGUIStat;
// Does this device exist in the configuration?
if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
{
// This device no longer exists in the configuration...
// If we haven't yet notified the GUI about this device
// being deleted from the configuration, then do so at
// this time...
if (*pGUIStat->pszNewStatStr)
{
// Send "device deleted" message...
gui_fprintf ( fStatusStream, "DEVD=%4.4X\n", pDEVBLK->devnum );
bUpdatesSent = TRUE;
*pGUIStat->pszNewStatStr = 0; // (prevent re-reporting it)
*pGUIStat->pszOldStatStr = 0; // (prevent re-reporting it)
}
continue; // (go on to next device)
}
// Retrieve this device's filename and optional settings parameter values...
szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
(pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?)
{
logmsg
(
_("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
,pDEVBLK->devnum
);
}
szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination)
// Device status flags...
chOnlineStat =
chBusyStat =
chPendingStat =
chOpenStat = '0';
if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1';
if (pDEVBLK->busy) chBusyStat = '1';
if (IOPENDING(pDEVBLK)) chPendingStat = '1';
if (pDEVBLK->fd > max(STDIN_FILENO,max(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1';
// Build a new "device added" or "device changed"
// status string for this device...
snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ,
"DEV%c=%4.4X %4.4X %-4.4s %c%c%c%c %s"
,*pGUIStat->pszOldStatStr ? 'C' : 'A'
,pDEVBLK->devnum
,pDEVBLK->devtype
,pDEVClass
,chOnlineStat
,chBusyStat
,chPendingStat
,chOpenStat
,szQueryDeviceBuff
);