/
sqUnixMain.c
2325 lines (1984 loc) · 67 KB
/
sqUnixMain.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
/* sqUnixMain.c -- support for Unix.
*
* Copyright (C) 1996-2007 by Ian Piumarta and other authors/contributors
* listed elsewhere in this file.
* All rights reserved.
*
* This file is part of Unix Squeak.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* Author: Ian Piumarta <ian.piumarta@squeakland.org>
* Merged with
* http://squeakvm.org/svn/squeak/trunk/platforms/unix/vm/sqUnixMain.c
* Revision: 2148
* Last Changed Rev: 2132
* by eliot Wed Jan 20 10:57:26 PST 2010
*/
#include "sq.h"
#include "sqAssert.h"
#include "sqMemoryAccess.h"
#include "sqaio.h"
#include "sqUnixCharConv.h"
#include "sqSCCSVersion.h"
#include "sqUnixMain.h"
#include "debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /* for toupper isdigit */
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include "include_ucontext.h"
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#if !defined(NOEXECINFO) && defined(HAVE_EXECINFO_H)
# include <execinfo.h>
# define BACKTRACE_DEPTH 64
#endif
#if __sun__
# include <limits.h>
#endif
#if defined(__alpha__) && defined(__osf__)
# include <sys/sysinfo.h>
# include <sys/proc.h>
#endif
#undef DEBUG_MODULES
#ifdef MUSL
void pushOutputFile(char *fileNameOrStdioIndex) {;}
void popOutputFile() {;}
#endif
#undef IMAGE_DUMP /* define to enable SIGHUP and SIGQUIT handling */
#define IMAGE_NAME_SIZE MAXPATHLEN
#define DefaultHeapSize 20 /* megabytes BEYOND actual image size */
#define DefaultMmapSize 1024 /* megabytes of virtual memory */
char *documentName= 0; /* name if launced from document */
char shortImageName[MAXPATHLEN+1]; /* image name */
char imageName[MAXPATHLEN+1]; /* full path to image */
static char vmName[MAXPATHLEN+1]; /* full path to vm */
char vmPath[MAXPATHLEN+1]; /* full path to image directory */
static char vmLogDirA[PATH_MAX+1]; /* where to write crash.dmp */
char *exeName; /* short vm name, e.g. "squeak" */
int argCnt= 0; /* global copies for access from plugins */
char **argVec= 0;
char **envVec= 0;
static int vmArgCnt= 0; /* for getAttributeIntoLength() */
static char **vmArgVec= 0;
static int squeakArgCnt= 0;
static char **squeakArgVec= 0;
static long extraMemory= 0;
int useMmap= DefaultMmapSize * 1024 * 1024;
static int useItimer= 1; /* 0 to disable itimer-based clock */
static int installHandlers= 1; /* 0 to disable sigusr1 & sigsegv handlers */
int noEvents= 0; /* 1 to disable new event handling */
int noSoundMixer= 0; /* 1 to disable writing sound mixer levels */
char *squeakPlugins= 0; /* plugin path */
int runAsSingleInstance=0;
#if !STACKVM && !COGVM
int useJit= 0; /* use default */
int jitProcs= 0; /* use default */
int jitMaxPIC= 0; /* use default */
#else
# define useJit 0
#endif
int withSpy= 0;
int uxDropFileCount= 0; /* number of dropped items */
char **uxDropFileNames= 0; /* dropped filenames */
int textEncodingUTF8= 1; /* 1 if copy from external selection uses UTF8 */
#if defined(IMAGE_DUMP)
static int dumpImageFile= 0; /* 1 after SIGHUP received */
#endif
#if defined(DARWIN)
int inModalLoop= 0;
#endif
int sqIgnorePluginErrors = 0;
int runInterpreter = 1;
#include "SqDisplay.h"
#include "SqSound.h"
struct SqDisplay *dpy= 0;
struct SqSound *snd= 0;
extern void dumpPrimTraceLog(void);
extern void printPhaseTime(int);
char *getVersionInfo(int verbose);
#ifdef PharoVM
void ioProcessEventsDefault(void);
void (*ioProcessEventsHandler) (void) = ioProcessEventsDefault;
#endif
/*
* In the Cog VMs time management is in platforms/unix/vm/sqUnixHeartbeat.c.
*/
#if !STACKVM
/*** timer support ***/
#define LOW_RES_TICK_MSECS 20 /* 1/50 second resolution */
static unsigned int lowResMSecs= 0;
static struct timeval startUpTime;
static void sigalrm(int signum)
{
lowResMSecs+= LOW_RES_TICK_MSECS;
forceInterruptCheck();
}
void
ioInitTime(void)
{
/* set up the micro/millisecond clock */
gettimeofday(&startUpTime, 0);
if (useItimer)
{
/* set up the low-res (50th second) millisecond clock */
/* WARNING: all system calls must check for EINTR!!! */
{
struct sigaction sa;
sigset_t ss1, ss2;
sigemptyset(&ss1);
sigprocmask(SIG_BLOCK, &ss1, &ss2);
sa.sa_handler= sigalrm;
sa.sa_mask= ss2;
# ifdef SA_RESTART /* we're probably on Linux */
sa.sa_flags= SA_RESTART;
# else
sa.sa_flags= 0; /* assume we already have BSD behaviour */
# endif
# if defined(__linux__) && !defined(__ia64) && !defined(__alpha__)
sa.sa_restorer= 0;
# endif
sigaction(SIGALRM, &sa, 0);
}
{
struct itimerval iv;
iv.it_interval.tv_sec= 0;
iv.it_interval.tv_usec= LOW_RES_TICK_MSECS * 1000;
iv.it_value= iv.it_interval;
setitimer(ITIMER_REAL, &iv, 0);
}
}
}
long ioMSecs(void)
{
struct timeval now;
gettimeofday(&now, 0);
if ((now.tv_usec-= startUpTime.tv_usec) < 0)
{
now.tv_usec+= 1000000;
now.tv_sec-= 1;
}
now.tv_sec-= startUpTime.tv_sec;
return lowResMSecs= (now.tv_usec / 1000 + now.tv_sec * 1000);
}
long ioMicroMSecs(void)
{
/* return the highest available resolution of the millisecond clock */
return ioMSecs(); /* this already to the nearest millisecond */
}
time_t convertToSqueakTime(time_t unixTime);
sqLong convertToLongSqueakTime(time_t unixTime);
/* returns the local wall clock time */
sqInt ioSeconds(void)
{
return convertToSqueakTime(time(0));
}
#define SecondsFrom1901To1970 2177452800ULL
#define MicrosecondsFrom1901To1970 2177452800000000ULL
#define MicrosecondsPerSecond 1000000ULL
#define MillisecondsPerSecond 1000ULL
#define MicrosecondsPerMillisecond 1000ULL
/* Compute the current VM time basis, the number of microseconds from 1901. */
static unsigned long long
currentUTCMicroseconds()
{
struct timeval utcNow;
gettimeofday(&utcNow,0);
return ((utcNow.tv_sec * MicrosecondsPerSecond) + utcNow.tv_usec)
+ MicrosecondsFrom1901To1970;
}
usqLong
ioUTCMicroseconds() { return currentUTCMicroseconds(); }
/* This is an expensive interface for use by profiling code that wants the time
* now rather than as of the last heartbeat.
*/
usqLong
ioUTCMicrosecondsNow() { return currentUTCMicroseconds(); }
#endif /* STACKVM */
/*
* Convert the supplied Unix (UTC) time to Squeak time.
*
* WARNING: On 32 bit platforms time_t is only 32 bits long.
* Since Squeak has an Epoch of 1901 while Unix uses 1970 the
* result is that overflow always occurs for times beyond about 1967.
* The expected result ends up in the image because the value is treated
* as an unsigned integer when converting to an oop.
* convertToSqueakTime should be deprecated in favour of
* convertToLongSqueakTime.
*
*/
time_t convertToSqueakTime(time_t unixTime)
{
#ifdef HAVE_TM_GMTOFF
unixTime+= localtime(&unixTime)->tm_gmtoff;
#else
# ifdef HAVE_TIMEZONE
unixTime+= ((daylight) * 60*60) - timezone;
# else
# error: cannot determine timezone correction
# endif
#endif
/* Squeak epoch is Jan 1, 1901. Unix epoch is Jan 1, 1970: 17 leap years
and 52 non-leap years later than Squeak. */
return unixTime + ((52*365UL + 17*366UL) * 24*60*60UL);
}
/*
* Convert the supplied Unix (UTC) time to Squeak time.
*
* Squeak time has an epoch of 1901 and uses local time
* i.e. timezone + daylight savings
*
* Answer an sqLong which is guaranteed to be 64 bits on all platforms.
*/
sqLong convertToLongSqueakTime(time_t unixTime)
{
sqLong result;
result = unixTime;
#ifdef HAVE_TM_GMTOFF
result += localtime(&unixTime)->tm_gmtoff;
#else
# ifdef HAVE_TIMEZONE
result += ((daylight) * 60*60) - timezone;
# else
# error: cannot determine timezone correction
# endif
#endif
/* Squeak epoch is Jan 1, 1901. Unix epoch is Jan 1, 1970: 17 leap years
and 52 non-leap years later than Squeak. */
result += ((52*365UL + 17*366UL) * 24*60*60UL);
return result;
}
/*** VM & Image File Naming ***/
/* copy src filename to target, if src is not an absolute filename,
* prepend the cwd to make target absolute
*/
static void pathCopyAbs(char *target, const char *src, size_t targetSize)
{
if (src[0] == '/')
strcpy(target, src);
else
{
0 == getcwd(target, targetSize);
strcat(target, "/");
strcat(target, src);
}
}
static void
recordPathsForVMName(const char *localVmName)
{
#if defined(__linux__)
char name[MAXPATHLEN+1];
int len;
#endif
exeName = strrchr(localVmName,'/')
? strrchr(localVmName,'/') + 1
: (char *)localVmName;
#if defined(__linux__)
if ((len= readlink("/proc/self/exe", name, sizeof(name))) > 0)
{
struct stat st;
name[len]= '\0';
if (!stat(name, &st))
localVmName= name;
}
#endif
/* get canonical path to vm */
if (realpath(localVmName, vmPath) == 0)
pathCopyAbs(vmPath, localVmName, sizeof(vmPath));
/* truncate vmPath to dirname */
{
int i= 0;
for (i= strlen(vmPath); i >= 0; i--)
if ('/' == vmPath[i])
{
vmPath[i+1]= '\0';
break;
}
}
}
static void
recordFullPathForImageName(const char *localImageName)
{
struct stat s;
/* get canonical path to image */
if ((stat(localImageName, &s) == -1)
|| (realpath(localImageName, imageName) == 0))
pathCopyAbs(imageName, localImageName, sizeof(imageName));
/* Set the directory into which to write the crash.dmp file. */
/* By default this is the image file's directory (strange but true). */
#if CRASH_DUMP_IN_CWD
getcwd(vmLogDirA,PATH_MAX);
#else
strcpy(vmLogDirA,imageName);
if (strrchr(vmLogDirA,'/'))
*strrchr(vmLogDirA,'/') = 0;
else
getcwd(vmLogDirA,PATH_MAX);
#endif
}
/* vm access */
sqInt imageNameSize(void) { return strlen(imageName); }
sqInt imageNameGetLength(sqInt sqImageNameIndex, sqInt length)
{
char *sqImageName= pointerForOop(sqImageNameIndex);
int count, i;
count= strlen(imageName);
count= (length < count) ? length : count;
/* copy the file name into the Squeak string */
for (i= 0; i < count; i++)
sqImageName[i]= imageName[i];
return count;
}
sqInt imageNamePutLength(sqInt sqImageNameIndex, sqInt length)
{
char *sqImageName= pointerForOop(sqImageNameIndex);
int count, i;
count= (IMAGE_NAME_SIZE < length) ? IMAGE_NAME_SIZE : length;
/* copy the file name into a null-terminated C string */
for (i= 0; i < count; i++)
imageName[i]= sqImageName[i];
imageName[count]= 0;
dpy->winSetName(imageName);
return count;
}
char *getImageName(void) { return imageName; }
/*** VM Home Directory Path ***/
sqInt vmPathSize(void) { return strlen(vmPath); }
sqInt vmPathGetLength(sqInt sqVMPathIndex, sqInt length)
{
char *stVMPath= pointerForOop(sqVMPathIndex);
int count, i;
count= strlen(vmPath);
count= (length < count) ? length : count;
/* copy the file name into the Squeak string */
for (i= 0; i < count; i++)
stVMPath[i]= vmPath[i];
return count;
}
char* ioGetLogDirectory(void) { return ""; };
sqInt ioSetLogDirectoryOfSize(void* lblIndex, sqInt sz){ return 1; }
/*** power management ***/
sqInt ioDisablePowerManager(sqInt disableIfNonZero)
{
return true;
}
/*** Access to system attributes and command-line arguments ***/
/* OS_TYPE may be set in configure.in and passed via the Makefile */
#ifndef OS_TYPE
# ifdef UNIX
# define OS_TYPE "unix"
# else
# define OS_TYPE "unknown"
# endif
#endif
char *
GetAttributeString(sqInt id)
{
if (id < 0) /* VM argument */
{
if (-id < vmArgCnt)
return vmArgVec[-id];
}
else
switch (id)
{
case 0:
return vmName[0] ? vmName : vmArgVec[0];
case 1:
return imageName;
case 1001:
/* OS type: "unix", "win32", "mac", ... */
return OS_TYPE;
case 1002:
/* OS name: e.g. "solaris2.5" on unix, "win95" on win32, ... */
return VM_TARGET_OS;
case 1003:
/* processor architecture: e.g. "68k", "x86", "PowerPC", ... */
return VM_TARGET_CPU;
case 1004:
/* Interpreter version string */
return (char *)interpreterVersion;
case 1005:
/* window system name */
return dpy->winSystemName();
case 1006:
/* vm build string */
return VM_BUILD_STRING;
#if STACKVM
case 1007: { /* interpreter build info */
extern char *__interpBuildInfo;
return __interpBuildInfo;
}
# if COGVM
case 1008: { /* cogit build info */
extern char *__cogitBuildInfo;
return __cogitBuildInfo;
}
# endif
#endif
case 1009: /* source tree version info */
return sourceVersionString(' ');
default:
if ((id - 2) < squeakArgCnt)
return squeakArgVec[id - 2];
}
success(false);
return "";
}
sqInt attributeSize(sqInt id)
{
return strlen(GetAttributeString(id));
}
sqInt getAttributeIntoLength(sqInt id, sqInt byteArrayIndex, sqInt length)
{
if (length > 0)
strncpy(pointerForOop(byteArrayIndex), GetAttributeString(id), length);
return 0;
}
/*** event handling ***/
sqInt inputEventSemaIndex= 0;
/* set asynchronous input event semaphore */
sqInt ioSetInputSemaphore(sqInt semaIndex)
{
if ((semaIndex == 0) || (noEvents == 1))
success(false);
else
inputEventSemaIndex= semaIndex;
return true;
}
/*** display functions ***/
sqInt ioFormPrint(sqInt bitsAddr, sqInt width, sqInt height, sqInt depth, double hScale, double vScale, sqInt landscapeFlag)
{
return dpy->ioFormPrint(bitsAddr, width, height, depth, hScale, vScale, landscapeFlag);
}
#if STACKVM
sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
{
# if ITIMER_HEARTBEAT
extern void checkHeartStillBeats();
checkHeartStillBeats();
# endif
dpy->ioRelinquishProcessorForMicroseconds(us);
return 0;
}
#else /* STACKVM */
static int lastInterruptCheck= 0;
sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
{
int now;
dpy->ioRelinquishProcessorForMicroseconds(us);
now= ioLowResMSecs();
if (now - lastInterruptCheck > (1000/25)) /* avoid thrashing intr checks from 1ms loop in idle proc */
{
forceInterruptCheck(); /* ensure timely poll for semaphore activity */
lastInterruptCheck= now;
}
return 0;
}
#endif /* STACKVM */
sqInt ioBeep(void) { return dpy->ioBeep(); }
/* Right now this funciton isn't responded to so we simply provide a dummy
* definition here. If any of the display subsystems do need it then it will
* have to be reimplemented as per the functions above.
*/
void ioNoteDisplayChangedwidthheightdepth(void *b, int w, int h, int d) {}
#if defined(IMAGE_DUMP)
static void emergencyDump(int quit)
{
extern sqInt preSnapshot(void);
extern sqInt postSnapshot(void);
extern void writeImageFile(sqInt);
char savedName[MAXPATHLEN];
char baseName[MAXPATHLEN];
char *term;
int dataSize, i;
strncpy(savedName, imageName, MAXPATHLEN);
strncpy(baseName, imageName, MAXPATHLEN);
if ((term= strrchr(baseName, '.')))
*term= '\0';
for (i= 0; ++i;)
{
struct stat sb;
snprintf(imageName, sizeof(imageName), "%s-emergency-dump-%d.image",
baseName, i);
if (stat(imageName, &sb))
break;
}
dataSize= preSnapshot();
writeImageFile(dataSize);
#if STACKVM
printf("\nMost recent primitives\n");
dumpPrimTraceLog();
#endif
fprintf(stderr, "\n");
printCallStack();
fprintf(stderr, "\nTo recover valuable content from this image:\n");
fprintf(stderr, " %s %s\n", exeName, imageName);
fprintf(stderr, "and then evaluate\n");
fprintf(stderr, " Smalltalk processStartUpList: true\n");
fprintf(stderr, "in a workspace. DESTROY the dumped image after recovering content!");
if (quit) abort();
strncpy(imageName, savedName, sizeof(imageName));
}
#endif
#ifdef PharoVM
void ioProcessEventsDefault(void)
{
sqInt result;
extern sqInt inIOProcessEvents;
#if defined(IMAGE_DUMP)
if (dumpImageFile) {
emergencyDump(0);
dumpImageFile= 0;
}
#endif
/* inIOProcessEvents controls ioProcessEvents. If negative then
* ioProcessEvents is disabled. If >= 0 inIOProcessEvents is incremented
* to avoid reentrancy (i.e. for native GUIs).
*/
if (inIOProcessEvents) return;
inIOProcessEvents += 1;
result = dpy->ioProcessEvents();
if (inIOProcessEvents > 0)
inIOProcessEvents -= 1;
}
extern void setIoProcessEventsHandler(void * handler) {
ioProcessEventsHandler = (void(*)()) handler;
}
sqInt ioProcessEvents(void) {
aioPoll(0);
if(ioProcessEventsHandler)
ioProcessEventsHandler();
return 0;
}
#else
sqInt ioProcessEvents(void)
{
sqInt result;
extern sqInt inIOProcessEvents;
#if defined(IMAGE_DUMP)
if (dumpImageFile) {
emergencyDump(0);
dumpImageFile= 0;
}
#endif
/* inIOProcessEvents controls ioProcessEvents. If negative then
* ioProcessEvents is disabled. If >= 0 inIOProcessEvents is incremented
* to avoid reentrancy (i.e. for native GUIs).
*/
if (inIOProcessEvents) return 0;
inIOProcessEvents += 1;
result = dpy->ioProcessEvents();
if (inIOProcessEvents > 0)
inIOProcessEvents -= 1;
return result;
}
#endif
void ioDrainEventQueue() {}
double ioScreenScaleFactor(void) { return dpy->ioScreenScaleFactor(); }
sqInt ioScreenDepth(void) { return dpy->ioScreenDepth(); }
sqInt ioScreenSize(void) { return dpy->ioScreenSize(); }
sqInt ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY)
{
return dpy->ioSetCursorWithMask(cursorBitsIndex, cursorMaskIndex, offsetX, offsetY);
}
sqInt ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY)
{
return dpy->ioSetCursorARGB(cursorBitsIndex, extentX, extentY, offsetX, offsetY);
}
sqInt ioSetCursor(sqInt cursorBitsIndex, sqInt offsetX, sqInt offsetY)
{
return ioSetCursorWithMask(cursorBitsIndex, 0, offsetX, offsetY);
}
sqInt ioSetFullScreen(sqInt fullScreen) { return dpy->ioSetFullScreen(fullScreen); }
sqInt ioForceDisplayUpdate(void) { return dpy->ioForceDisplayUpdate(); }
sqInt ioShowDisplay(sqInt dispBitsIndex, sqInt width, sqInt height, sqInt depth, sqInt l, sqInt r, sqInt t, sqInt b)
{
return dpy->ioShowDisplay(dispBitsIndex, width, height, depth, l, r, t, b);
}
sqInt ioHasDisplayDepth(sqInt i) { return dpy->ioHasDisplayDepth(i); }
sqInt ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag)
{
return dpy->ioSetDisplayMode(width, height, depth, fullscreenFlag);
}
sqInt clipboardSize(void)
{
return dpy->clipboardSize();
}
sqInt clipboardWriteFromAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
{
return dpy->clipboardWriteFromAt(count, byteArrayIndex, startIndex);
}
sqInt clipboardReadIntoAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
{
return dpy->clipboardReadIntoAt(count, byteArrayIndex, startIndex);
}
char **clipboardGetTypeNames(void)
{
return dpy->clipboardGetTypeNames();
}
sqInt clipboardSizeWithType(char *typeName, int ntypeName)
{
return dpy->clipboardSizeWithType(typeName, ntypeName);
}
void clipboardWriteWithType(char *data, size_t nData, char *typeName, size_t nTypeNames, int isDnd, int isClaiming)
{
dpy->clipboardWriteWithType(data, nData, typeName, nTypeNames, isDnd, isClaiming);
}
sqInt ioGetButtonState(void) { return dpy->ioGetButtonState(); }
sqInt ioPeekKeystroke(void) { return dpy->ioPeekKeystroke(); }
sqInt ioGetKeystroke(void) { return dpy->ioGetKeystroke(); }
sqInt ioGetNextEvent(sqInputEvent *evt) { return dpy->ioGetNextEvent(evt); }
sqInt ioMousePoint(void) { return dpy->ioMousePoint(); }
/*** Window labeling ***/
char* ioGetWindowLabel(void) {return "";}
sqInt ioSetWindowLabelOfSize(void* lbl, sqInt size)
{ return dpy->hostWindowSetTitle((long)dpy->ioGetWindowHandle(), lbl, size); }
sqInt ioIsWindowObscured(void) {return false;}
/** Misplaced Window-Size stubs, so the VM will link. **/
sqInt ioGetWindowWidth()
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
return wh >> 16; }
sqInt ioGetWindowHeight()
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
return (short)wh; }
void* ioGetWindowHandle(void) { return dpy->ioGetWindowHandle(); }
sqInt ioSetWindowWidthHeight(sqInt w, sqInt h)
{ return dpy->hostWindowSetSize((long)dpy->ioGetWindowHandle(),w,h); }
/*** Drag and Drop ***/
sqInt dndOutStart(char *types, int ntypes) { return dpy->dndOutStart(types, ntypes); }
sqInt dndOutAcceptedType(char *type, int ntype) { return dpy->dndOutAcceptedType(type, ntype); }
void dndOutSend(char *bytes, int nbytes) { dpy->dndOutSend(bytes, nbytes); }
void dndReceived(char *fileName) { dpy->dndReceived(fileName); }
/*** OpenGL ***/
int verboseLevel= 1;
struct SqDisplay *ioGetDisplayModule(void) { return dpy; }
void *ioGetDisplay(void) { return dpy->ioGetDisplay(); }
void *ioGetWindow(void) { return dpy->ioGetWindow(); }
sqInt ioGLinitialise(void) { return dpy->ioGLinitialise(); }
sqInt ioGLcreateRenderer(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h, sqInt flags)
{
return dpy->ioGLcreateRenderer(r, x, y, w, h, flags);
}
sqInt ioGLmakeCurrentRenderer(glRenderer *r) { return dpy->ioGLmakeCurrentRenderer(r); }
void ioGLdestroyRenderer(glRenderer *r) { dpy->ioGLdestroyRenderer(r); }
void ioGLswapBuffers(glRenderer *r) { dpy->ioGLswapBuffers(r); }
void ioGLsetBufferRect(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h)
{
dpy->ioGLsetBufferRect(r, x, y, w, h);
}
sqInt primitivePluginBrowserReady(void) { return dpy->primitivePluginBrowserReady(); }
sqInt primitivePluginRequestURLStream(void) { return dpy->primitivePluginRequestURLStream(); }
sqInt primitivePluginRequestURL(void) { return dpy->primitivePluginRequestURL(); }
sqInt primitivePluginPostURL(void) { return dpy->primitivePluginPostURL(); }
sqInt primitivePluginRequestFileHandle(void) { return dpy->primitivePluginRequestFileHandle(); }
sqInt primitivePluginDestroyRequest(void) { return dpy->primitivePluginDestroyRequest(); }
sqInt primitivePluginRequestState(void) { return dpy->primitivePluginRequestState(); }
/*** errors ***/
static void outOfMemory(void)
{
/* pushing stderr outputs the error report on stderr instead of stdout */
pushOutputFile((char *)STDERR_FILENO);
error("out of memory\n");
}
/* Print an error message, possibly a stack trace, do /not/ exit.
* Allows e.g. writing to a log file and stderr.
*/
static void *printRegisterState(ucontext_t *uap);
static void
reportStackState(const char *msg, char *date, int printAll, ucontext_t *uap)
{
#if !defined(NOEXECINFO) && defined(HAVE_EXECINFO_H)
void *addrs[BACKTRACE_DEPTH];
void *pc;
int depth;
#endif
/* flag prevents recursive error when trying to print a broken stack */
static sqInt printingStack = false;
#if COGVM
/* Testing stackLimit tells us whether the VM is initialized. */
extern usqInt stackLimitAddress(void);
#endif
printf("\n%s%s%s\n\n", msg, date ? " " : "", date ? date : "");
printf("%s\n%s\n\n", GetAttributeString(0), getVersionInfo(1));
#if COGVM
/* Do not attempt to report the stack until the VM is initialized!! */
if (!*(char **)stackLimitAddress())
return;
#endif
#if !defined(NOEXECINFO) && defined(HAVE_EXECINFO_H)
printf("C stack backtrace & registers:\n");
if (uap) {
addrs[0] = printRegisterState(uap);
depth = 1 + backtrace(addrs + 1, BACKTRACE_DEPTH);
}
else
depth = backtrace(addrs, BACKTRACE_DEPTH);
putchar('*'); /* indicate where pc is */
fflush(stdout); /* backtrace_symbols_fd uses unbuffered i/o */
backtrace_symbols_fd(addrs, depth + 1, fileno(stdout));
#endif
if (ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) {
if (!printingStack) {
#if COGVM
/* If we're in generated machine code then the only way the stack
* dump machinery has of giving us an accurate report is if we set
* stackPointer & framePointer to the native stack & frame pointers.
*/
void *fp = (void *)(uap ? uap->_FP_IN_UCONTEXT : 0);
void *sp = (void *)(uap ? uap->_SP_IN_UCONTEXT : 0);
char *savedSP, *savedFP;
ifValidWriteBackStackPointersSaveTo(fp,sp,&savedFP,&savedSP);
#endif /* COGVM */
printingStack = true;
if (printAll) {
printf("\n\nAll Smalltalk process stacks (active first):\n");
printAllStacks();
}
else {
printf("\n\nSmalltalk stack dump:\n");
printCallStack();
}
printingStack = false;
#if COGVM
/* Now restore framePointer and stackPointer via same function */
ifValidWriteBackStackPointersSaveTo(savedFP,savedSP,0,0);
#endif
}
}
else
printf("\nCan't dump Smalltalk stack(s). Not in VM thread\n");
#if STACKVM
printf("\nMost recent primitives\n");
dumpPrimTraceLog();
# if COGVM
printf("\n");
reportMinimumUnusedHeadroom();
# endif
#endif
printf("\n\t(%s)\n", msg);
fflush(stdout);
}
/* Attempt to dump the registers to stdout. Only do so if we know how. */
static void *
printRegisterState(ucontext_t *uap)
{
#if __linux__ && __i386__
greg_t *regs = (greg_t *)&uap->uc_mcontext.gregs;
printf( "\teax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"
"\tedi 0x%08x esi 0x%08x ebp 0x%08x esp 0x%08x\n"
"\teip 0x%08x\n",
regs[REG_EAX], regs[REG_EBX], regs[REG_ECX], regs[REG_EDX],
regs[REG_EDI], regs[REG_EDI], regs[REG_EBP], regs[REG_ESP],
regs[REG_EIP]);
return (void *)regs[REG_EIP];
#elif __FreeBSD__ && __i386__
struct mcontext *regs = &uap->uc_mcontext;
printf( "\teax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"
"\tedi 0x%08x esi 0x%08x ebp 0x%08x esp 0x%08x\n"
"\teip 0x%08x\n",
regs->mc_eax, regs->mc_ebx, regs->mc_ecx, regs->mc_edx,
regs->mc_edi, regs->mc_edi, regs->mc_ebp, regs->mc_esp,
regs->mc_eip);
return regs->mc_eip;
#elif __linux__ && __x86_64__
greg_t *regs = (greg_t *)&uap->uc_mcontext.gregs;
printf( "\trax 0x%08lx rbx 0x%08lx rcx 0x%08lx rdx 0x%08lx\n"
"\trdi 0x%08lx rsi 0x%08lx rbp 0x%08lx rsp 0x%08lx\n"
"\tr8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n"
"\tr12 0x%08lx r13 0x%08lx r14 0x%08lx r15 0x%08lx\n"
"\trip 0x%08lx\n",
regs[REG_RAX], regs[REG_RBX], regs[REG_RCX], regs[REG_RDX],
regs[REG_RDI], regs[REG_RSI], regs[REG_RBP], regs[REG_RSP],
regs[REG_R8 ], regs[REG_R9 ], regs[REG_R10], regs[REG_R11],
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15],
regs[REG_RIP]);
return (void *)regs[REG_RIP];
# elif __OpenBSD__ && __x86_64__
printf( "\trax 0x%08lx rbx 0x%08lx rcx 0x%08lx rdx 0x%08lx\n"