ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/main_unix.cpp (file contents):
Revision 1.27 by cebix, 2000-11-30T16:20:52Z vs.
Revision 1.72 by gbeauche, 2006-02-27T07:24:58Z

# Line 1 | Line 1
1   /*
2   *  main_unix.cpp - Startup code for Unix
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
4 > *  Basilisk II (C) 1997-2005 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 24 | Line 24
24   #include <stdlib.h>
25   #include <signal.h>
26   #include <errno.h>
27 < #include <X11/Xlib.h>
27 >
28 > #ifdef USE_SDL
29 > # include <SDL.h>
30 > #endif
31 >
32 > #ifndef USE_SDL_VIDEO
33 > # include <X11/Xlib.h>
34 > #endif
35  
36   #ifdef HAVE_PTHREADS
37   # include <pthread.h>
# Line 50 | Line 57 | struct sigstate {
57  
58   #ifdef ENABLE_GTK
59   # include <gtk/gtk.h>
60 + # include <gdk/gdk.h>
61 + # ifdef HAVE_GNOMEUI
62 + #  include <gnome.h>
63 + # endif
64   #endif
65  
66   #ifdef ENABLE_XF86_DGA
# Line 57 | Line 68 | struct sigstate {
68   # include <X11/extensions/xf86dga.h>
69   #endif
70  
71 + #include <string>
72 + using std::string;
73 +
74   #include "cpu_emulation.h"
75   #include "sys.h"
76   #include "rom_patches.h"
# Line 70 | Line 84 | struct sigstate {
84   #include "user_strings.h"
85   #include "version.h"
86   #include "main.h"
87 + #include "vm_alloc.h"
88 + #include "sigsegv.h"
89 +
90 + #if USE_JIT
91 + extern void flush_icache_range(uint32 start, uint32 size); // from compemu_support.cpp
92 + #endif
93  
94   #ifdef ENABLE_MON
95   # include "mon.h"
# Line 81 | Line 101 | struct sigstate {
101  
102   // Constants
103   const char ROM_FILE_NAME[] = "ROM";
104 + #if !EMULATED_68K
105   const int SIG_STACK_SIZE = SIGSTKSZ;    // Size of signal stack
106 + #endif
107   const int SCRATCH_MEM_SIZE = 0x10000;   // Size of scratch memory area
108  
109  
# Line 101 | Line 123 | int CPUType;
123   bool CPUIs68060;
124   int FPUType;
125   bool TwentyFourBitAddressing;
126 + bool ThirtyThreeBitAddressing = false;
127  
128  
129   // Global variables
130 < char *x_display_name = NULL;                                            // X11 display name
131 < Display *x_display = NULL;                                                      // X11 display handle
130 > #ifndef USE_SDL_VIDEO
131 > extern char *x_display_name;                                            // X11 display name
132 > extern Display *x_display;                                                      // X11 display handle
133 > #ifdef X11_LOCK_TYPE
134 > X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT;           // X11 display lock
135 > #endif
136 > #endif
137  
138 < static int zero_fd = -1;                                                        // FD of /dev/zero
111 < static uint8 last_xpram[256];                                           // Buffer for monitoring XPRAM changes
138 > static uint8 last_xpram[XPRAM_SIZE];                            // Buffer for monitoring XPRAM changes
139  
140   #ifdef HAVE_PTHREADS
141 + #if !EMULATED_68K
142   static pthread_t emul_thread;                                           // Handle of MacOS emulation thread (main thread)
143 + #endif
144  
145   static bool xpram_thread_active = false;                        // Flag: XPRAM watchdog installed
146   static volatile bool xpram_thread_cancel = false;       // Flag: Cancel XPRAM thread
# Line 122 | Line 151 | static volatile bool tick_thread_cancel
151   static pthread_t tick_thread;                                           // 60Hz thread
152   static pthread_attr_t tick_thread_attr;                         // 60Hz thread attributes
153  
125 #if EMULATED_68K
154   static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect InterruptFlags
155 < #endif
155 > #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock)
156 > #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock)
157 >
158 > #else
159 >
160 > #define LOCK_INTFLAGS
161 > #define UNLOCK_INTFLAGS
162 >
163   #endif
164  
165   #if !EMULATED_68K
# Line 139 | Line 174 | uint16 EmulatedSR;                                     // Emulated bits
174   uint8 *ScratchMem = NULL;                       // Scratch memory for Mac ROM writes
175   #endif
176  
177 + #if !defined(HAVE_PTHREADS)
178   static struct sigaction timer_sa;       // sigaction used for timer
179  
180   #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
181   #define SIG_TIMER SIGRTMIN
182   static timer_t timer;                           // 60Hz timer
183   #endif
184 + #endif // !HAVE_PTHREADS
185  
186   #ifdef ENABLE_MON
187   static struct sigaction sigint_sa;      // sigaction for SIGINT handler
# Line 153 | Line 190 | static void sigint_handler(...);
190  
191   #if REAL_ADDRESSING
192   static bool lm_area_mapped = false;     // Flag: Low Memory area mmap()ped
156 static bool memory_mapped_from_zero = false; // Flag: Could allocate RAM area from 0
157 #endif
158
159 #if REAL_ADDRESSING || DIRECT_ADDRESSING
160 static uint32 mapped_ram_rom_size;              // Total size of mmap()ed RAM/ROM area
193   #endif
194  
195  
# Line 191 | Line 223 | char *strdup(const char *s)
223  
224  
225   /*
226 + *  Helpers to map memory that can be accessed from the Mac side
227 + */
228 +
229 + // NOTE: VM_MAP_33BIT is only used when compiling a 64-bit JIT on specific platforms
230 + void *vm_acquire_mac(size_t size)
231 + {
232 +        void *m = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_33BIT);
233 + #ifdef USE_33BIT_ADDRESSING
234 +        if (m == VM_MAP_FAILED) {
235 +                printf("WARNING: Cannot acquire memory in 33-bit address space (%s)\n", strerror(errno));
236 +                ThirtyThreeBitAddressing = false;
237 +                m = vm_acquire(size);
238 +        }
239 + #endif
240 +        return m;
241 + }
242 +
243 + static int vm_acquire_mac_fixed(void *addr, size_t size)
244 + {
245 +        int ret = vm_acquire_fixed(addr, size, VM_MAP_DEFAULT | VM_MAP_33BIT);
246 + #ifdef USE_33BIT_ADDRESSING
247 +        if (ret < 0) {
248 +                printf("WARNING: Cannot acquire fixed memory in 33-bit address space (%s)\n", strerror(errno));
249 +                ThirtyThreeBitAddressing = false;
250 +                ret = vm_acquire_fixed(addr, size);
251 +        }
252 + #endif
253 +        return ret;
254 + }
255 +
256 +
257 + /*
258 + *  SIGSEGV handler
259 + */
260 +
261 + static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
262 + {
263 + #if ENABLE_VOSF
264 +        // Handle screen fault
265 +        extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
266 +        if (Screen_fault_handler(fault_address, fault_instruction))
267 +                return SIGSEGV_RETURN_SUCCESS;
268 + #endif
269 +
270 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
271 +        // Ignore writes to ROM
272 +        if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
273 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
274 +
275 +        // Ignore all other faults, if requested
276 +        if (PrefsFindBool("ignoresegv"))
277 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
278 + #endif
279 +
280 +        return SIGSEGV_RETURN_FAILURE;
281 + }
282 +
283 + /*
284 + *  Dump state when everything went wrong after a SEGV
285 + */
286 +
287 + static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
288 + {
289 +        fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
290 +        if (fault_instruction != SIGSEGV_INVALID_PC)
291 +                fprintf(stderr, " [IP=%p]", fault_instruction);
292 +        fprintf(stderr, "\n");
293 + #if EMULATED_68K
294 +        uaecptr nextpc;
295 +        extern void m68k_dumpstate(uaecptr *nextpc);
296 +        m68k_dumpstate(&nextpc);
297 + #endif
298 + #if USE_JIT && JIT_DEBUG
299 +        extern void compiler_dumpstate(void);
300 +        compiler_dumpstate();
301 + #endif
302 +        VideoQuitFullScreen();
303 + #ifdef ENABLE_MON
304 +        char *arg[4] = {"mon", "-m", "-r", NULL};
305 +        mon(3, arg);
306 + #endif
307 +        QuitEmulator();
308 + }
309 +
310 +
311 + /*
312 + *  Update virtual clock and trigger interrupts if necessary
313 + */
314 +
315 + #ifdef USE_CPU_EMUL_SERVICES
316 + static uint64 n_check_ticks = 0;
317 + static uint64 emulated_ticks_start = 0;
318 + static uint64 emulated_ticks_count = 0;
319 + static int64 emulated_ticks_current = 0;
320 + static int32 emulated_ticks_quantum = 1000;
321 + int32 emulated_ticks = emulated_ticks_quantum;
322 +
323 + void cpu_do_check_ticks(void)
324 + {
325 + #if DEBUG
326 +        n_check_ticks++;
327 + #endif
328 +
329 +        uint64 now;
330 +        static uint64 next = 0;
331 +        if (next == 0)
332 +                next = emulated_ticks_start = GetTicks_usec();
333 +
334 +        // Update total instructions count
335 +        if (emulated_ticks <= 0) {
336 +                emulated_ticks_current += (emulated_ticks_quantum - emulated_ticks);
337 +                // XXX: can you really have a machine fast enough to overflow
338 +                // a 63-bit m68k instruction counter within 16 ms?
339 +                if (emulated_ticks_current < 0) {
340 +                        printf("WARNING: Overflowed 63-bit m68k instruction counter in less than 16 ms!\n");
341 +                        goto recalibrate_quantum;
342 +                }
343 +        }
344 +
345 +        // Check for interrupt opportunity
346 +        now = GetTicks_usec();
347 +        if (next < now) {
348 +                one_tick();
349 +                do {
350 +                        next += 16625;
351 +                } while (next < now);
352 +                emulated_ticks_count++;
353 +
354 +                // Recalibrate 1000 Hz quantum every 10 ticks
355 +                static uint64 last = 0;
356 +                if (last == 0)
357 +                        last = now;
358 +                else if (now - last > 166250) {
359 +                  recalibrate_quantum:
360 +                        emulated_ticks_quantum = ((uint64)emulated_ticks_current * 1000) / (now - last);
361 +                        emulated_ticks_current = 0;
362 +                        last = now;
363 +                }
364 +        }
365 +
366 +        // Update countdown
367 +        if (emulated_ticks <= 0)
368 +                emulated_ticks += emulated_ticks_quantum;
369 + }
370 + #endif
371 +
372 +
373 + /*
374   *  Main program
375   */
376  
377 + static void usage(const char *prg_name)
378 + {
379 +        printf(
380 +                "Usage: %s [OPTION...]\n"
381 +                "\nUnix options:\n"
382 +                "  --config FILE\n    read/write configuration from/to FILE\n"
383 +                "  --display STRING\n    X display to use\n"
384 +                "  --break ADDRESS\n    set ROM breakpoint\n"
385 +                "  --rominfo\n    dump ROM information\n", prg_name
386 +        );
387 +        LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
388 +        PrefsPrintUsage();
389 +        exit(0);
390 + }
391 +
392   int main(int argc, char **argv)
393   {
394          char str[256];
# Line 208 | Line 403 | int main(int argc, char **argv)
403          printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
404          printf(" %s\n", GetString(STR_ABOUT_TEXT2));
405  
406 <        // Parse arguments
406 >        // Parse command line arguments
407          for (int i=1; i<argc; i++) {
408 <                if (strcmp(argv[i], "-display") == 0 && ++i < argc)
409 <                        x_display_name = argv[i];
410 <                else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
411 <                        ROMBreakpoint = strtol(argv[i], NULL, 0);
412 <                else if (strcmp(argv[i], "-rominfo") == 0)
408 >                if (strcmp(argv[i], "--help") == 0) {
409 >                        usage(argv[0]);
410 > #ifndef USE_SDL_VIDEO
411 >                } else if (strcmp(argv[i], "--display") == 0) {
412 >                        i++; // don't remove the argument, gtk_init() needs it too
413 >                        if (i < argc)
414 >                                x_display_name = strdup(argv[i]);
415 > #endif
416 >                } else if (strcmp(argv[i], "--break") == 0) {
417 >                        argv[i++] = NULL;
418 >                        if (i < argc) {
419 >                                ROMBreakpoint = strtol(argv[i], NULL, 0);
420 >                                argv[i] = NULL;
421 >                        }
422 >                } else if (strcmp(argv[i], "--config") == 0) {
423 >                        argv[i++] = NULL;
424 >                        if (i < argc) {
425 >                                extern string UserPrefsPath; // from prefs_unix.cpp
426 >                                UserPrefsPath = argv[i];
427 >                                argv[i] = NULL;
428 >                        }
429 >                } else if (strcmp(argv[i], "--rominfo") == 0) {
430 >                        argv[i] = NULL;
431                          PrintROMInfo = true;
432 +                }
433 +        }
434 +
435 +        // Remove processed arguments
436 +        for (int i=1; i<argc; i++) {
437 +                int k;
438 +                for (k=i; k<argc; k++)
439 +                        if (argv[k] != NULL)
440 +                                break;
441 +                if (k > i) {
442 +                        k -= i;
443 +                        for (int j=i+k; j<argc; j++)
444 +                                argv[j-k] = argv[j];
445 +                        argc -= k;
446 +                }
447 +        }
448 +
449 + #ifdef ENABLE_GTK
450 + #ifdef HAVE_GNOMEUI
451 +        // Init GNOME/GTK
452 +        char version[16];
453 +        sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
454 +        gnome_init("Basilisk II", version, argc, argv);
455 + #else
456 +        // Init GTK
457 +        gtk_set_locale();
458 +        gtk_init(&argc, &argv);
459 + #endif
460 + #endif
461 +
462 +        // Read preferences
463 +        PrefsInit(argc, argv);
464 +
465 +        // Any command line arguments left?
466 +        for (int i=1; i<argc; i++) {
467 +                if (argv[i][0] == '-') {
468 +                        fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
469 +                        usage(argv[0]);
470 +                }
471          }
472  
473 + #ifndef USE_SDL_VIDEO
474          // Open display
475          x_display = XOpenDisplay(x_display_name);
476          if (x_display == NULL) {
# Line 231 | Line 484 | int main(int argc, char **argv)
484          // Fork out, so we can return from fullscreen mode when things get ugly
485          XF86DGAForkApp(DefaultScreen(x_display));
486   #endif
234
235 #ifdef ENABLE_GTK
236        // Init GTK
237        gtk_set_locale();
238        gtk_init(&argc, &argv);
487   #endif
488  
489 <        // Read preferences
490 <        PrefsInit();
489 > #ifdef USE_SDL
490 >        // Initialize SDL system
491 >        int sdl_flags = 0;
492 > #ifdef USE_SDL_VIDEO
493 >        sdl_flags |= SDL_INIT_VIDEO;
494 > #endif
495 > #ifdef USE_SDL_AUDIO
496 >        sdl_flags |= SDL_INIT_AUDIO;
497 > #endif
498 >        assert(sdl_flags != 0);
499 >        if (SDL_Init(sdl_flags) == -1) {
500 >                char str[256];
501 >                sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
502 >                ErrorAlert(str);
503 >                QuitEmulator();
504 >        }
505 >        atexit(SDL_Quit);
506 > #endif
507  
508          // Init system routines
509          SysInit();
# Line 249 | Line 513 | int main(int argc, char **argv)
513                  if (!PrefsEditor())
514                          QuitEmulator();
515  
516 <        // Open /dev/zero
517 <        zero_fd = open("/dev/zero", O_RDWR);
518 <        if (zero_fd < 0) {
255 <                sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
516 >        // Install the handler for SIGSEGV
517 >        if (!sigsegv_install_handler(sigsegv_handler)) {
518 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
519                  ErrorAlert(str);
520                  QuitEmulator();
521          }
522 +        
523 +        // Register dump state function when we got mad after a segfault
524 +        sigsegv_set_dump_state(sigsegv_dump_state);
525  
526          // Read RAM size
527          RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;       // Round down to 1MB boundary
# Line 263 | Line 529 | int main(int argc, char **argv)
529                  WarningAlert(GetString(STR_SMALL_RAM_WARN));
530                  RAMSize = 1024*1024;
531          }
532 +        if (RAMSize > 1023*1024*1024)                                           // Cap to 1023MB (APD crashes at 1GB)
533 +                RAMSize = 1023*1024*1024;
534  
535   #if REAL_ADDRESSING || DIRECT_ADDRESSING
536 <        const uint32 page_size = getpagesize();
537 <        const uint32 page_mask = page_size - 1;
538 <        const uint32 aligned_ram_size = (RAMSize + page_mask) & ~page_mask;
539 <        mapped_ram_rom_size = aligned_ram_size + 0x100000;
536 >        RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
537 > #endif
538 >        
539 >        // Initialize VM system
540 >        vm_init();
541 >
542 > #ifdef USE_33BIT_ADDRESSING
543 >        // Speculatively enables 33-bit addressing
544 >        ThirtyThreeBitAddressing = true;
545   #endif
546  
547   #if REAL_ADDRESSING
548 <        // Try to allocate the complete address space from zero
549 <        // gb-- the Solaris manpage about mmap(2) states that using MAP_FIXED
550 <        // implies undefined behaviour for further use of sbrk(), malloc(), etc.
551 <        // cebix-- on NetBSD/m68k, this causes a segfault
552 < #if defined(OS_solaris) || defined(OS_netbsd)
553 <        // Anyway, it doesn't work...
554 <        if (0) {
548 >        // Flag: RAM and ROM are contigously allocated from address 0
549 >        bool memory_mapped_from_zero = false;
550 >
551 >        // Make sure to map RAM & ROM at address 0 only on platforms that
552 >        // supports linker scripts to relocate the Basilisk II executable
553 >        // above 0x70000000
554 > #if HAVE_LINKER_SCRIPT
555 >        const bool can_map_all_memory = true;
556   #else
557 <        if (mmap((caddr_t)0x0000, mapped_ram_rom_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) != MAP_FAILED) {
557 >        const bool can_map_all_memory = false;
558   #endif
559 +        
560 +        // Try to allocate all memory from 0x0000, if it is not known to crash
561 +        if (can_map_all_memory && (vm_acquire_mac_fixed(0, RAMSize + 0x100000) == 0)) {
562                  D(bug("Could allocate RAM and ROM from 0x0000\n"));
563                  memory_mapped_from_zero = true;
564          }
565 <        // Create Low Memory area (0x0000..0x2000)
566 <        else if (mmap((char *)0x0000, 0x2000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) != MAP_FAILED) {
565 >        
566 > #ifndef PAGEZERO_HACK
567 >        // Otherwise, just create the Low Memory area (0x0000..0x2000)
568 >        else if (vm_acquire_mac_fixed(0, 0x2000) == 0) {
569                  D(bug("Could allocate the Low Memory globals\n"));
570                  lm_area_mapped = true;
571          }
572 <        // Exit on error
572 >        
573 >        // Exit on failure
574          else {
575                  sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
576                  ErrorAlert(str);
577                  QuitEmulator();
578          }
579   #endif
580 <
301 < #if USE_SCRATCHMEM_SUBTERFUGE
302 <        // Allocate scratch memory
303 <        ScratchMem = (uint8 *)malloc(SCRATCH_MEM_SIZE);
304 <        if (ScratchMem == NULL) {
305 <                ErrorAlert(GetString(STR_NO_MEM_ERR));
306 <                QuitEmulator();
307 <        }
308 <        ScratchMem += SCRATCH_MEM_SIZE/2;       // ScratchMem points to middle of block
309 < #endif
580 > #endif /* REAL_ADDRESSING */
581  
582          // Create areas for Mac RAM and ROM
312 #if REAL_ADDRESSING || DIRECT_ADDRESSING
313        // gb-- Overkill, needs to be cleaned up. Probably explode it for either
314        // real or direct addressing mode.
583   #if REAL_ADDRESSING
584          if (memory_mapped_from_zero) {
585                  RAMBaseHost = (uint8 *)0;
586 <                ROMBaseHost = RAMBaseHost + aligned_ram_size;
586 >                ROMBaseHost = RAMBaseHost + RAMSize;
587          }
588          else
589   #endif
590          {
591 <                RAMBaseHost = (uint8 *)mmap(0, mapped_ram_rom_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
592 <                if (RAMBaseHost == (uint8 *)MAP_FAILED) {
593 <                        ErrorAlert(GetString(STR_NO_MEM_ERR));
591 >                uint8 *ram_rom_area = (uint8 *)vm_acquire_mac(RAMSize + 0x100000);
592 >                if (ram_rom_area == VM_MAP_FAILED) {    
593 >                        ErrorAlert(STR_NO_MEM_ERR);
594                          QuitEmulator();
595                  }
596 <                ROMBaseHost = RAMBaseHost + aligned_ram_size;
596 >                RAMBaseHost = ram_rom_area;
597 >                ROMBaseHost = RAMBaseHost + RAMSize;
598          }
599 < #else
600 <        RAMBaseHost = (uint8 *)malloc(RAMSize);
601 <        ROMBaseHost = (uint8 *)malloc(0x100000);
602 <        if (RAMBaseHost == NULL || ROMBaseHost == NULL) {
603 <                ErrorAlert(GetString(STR_NO_MEM_ERR));
599 >
600 > #if USE_SCRATCHMEM_SUBTERFUGE
601 >        // Allocate scratch memory
602 >        ScratchMem = (uint8 *)vm_acquire_mac(SCRATCH_MEM_SIZE);
603 >        if (ScratchMem == VM_MAP_FAILED) {
604 >                ErrorAlert(STR_NO_MEM_ERR);
605                  QuitEmulator();
606          }
607 +        ScratchMem += SCRATCH_MEM_SIZE/2;       // ScratchMem points to middle of block
608   #endif
609  
610   #if DIRECT_ADDRESSING
611 <        // Initialize MEMBaseDiff now so that Host2MacAddr in the Video module
612 <        // will return correct results
611 >        // RAMBaseMac shall always be zero
612 >        MEMBaseDiff = (uintptr)RAMBaseHost;
613          RAMBaseMac = 0;
614 <        ROMBaseMac = RAMBaseMac + aligned_ram_size;
344 <        InitMEMBaseDiff(RAMBaseHost, RAMBaseMac);
614 >        ROMBaseMac = Host2MacAddr(ROMBaseHost);
615   #endif
616 < #if REAL_ADDRESSING // && !EMULATED_68K
617 <        RAMBaseMac = (uint32)RAMBaseHost;
618 <        ROMBaseMac = (uint32)ROMBaseHost;
616 > #if REAL_ADDRESSING
617 >        RAMBaseMac = Host2MacAddr(RAMBaseHost);
618 >        ROMBaseMac = Host2MacAddr(ROMBaseHost);
619   #endif
620          D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
621          D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
# Line 356 | Line 626 | int main(int argc, char **argv)
626          // Load Mac ROM
627          int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
628          if (rom_fd < 0) {
629 <                ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
629 >                ErrorAlert(STR_NO_ROM_FILE_ERR);
630                  QuitEmulator();
631          }
632          printf(GetString(STR_READING_ROM_FILE));
633          ROMSize = lseek(rom_fd, 0, SEEK_END);
634          if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
635 <                ErrorAlert(GetString(STR_ROM_SIZE_ERR));
635 >                ErrorAlert(STR_ROM_SIZE_ERR);
636                  close(rom_fd);
637                  QuitEmulator();
638          }
639          lseek(rom_fd, 0, SEEK_SET);
640          if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) {
641 <                ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
641 >                ErrorAlert(STR_ROM_FILE_READ_ERR);
642                  close(rom_fd);
643                  QuitEmulator();
644          }
# Line 407 | Line 677 | int main(int argc, char **argv)
677                  QuitEmulator();
678          D(bug("Initialization complete\n"));
679  
680 + #if !EMULATED_68K
681 +        // (Virtual) supervisor mode, disable interrupts
682 +        EmulatedSR = 0x2700;
683 +
684   #ifdef HAVE_PTHREADS
685          // Get handle of main thread
686          emul_thread = pthread_self();
687   #endif
688  
415 #if !EMULATED_68K
416        // (Virtual) supervisor mode, disable interrupts
417        EmulatedSR = 0x2700;
418
689          // Create and install stack for signal handlers
690          sig_stack = malloc(SIG_STACK_SIZE);
691          D(bug("Signal stack at %p\n", sig_stack));
692          if (sig_stack == NULL) {
693 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
693 >                ErrorAlert(STR_NOT_ENOUGH_MEMORY_ERR);
694                  QuitEmulator();
695          }
696          stack_t new_stack;
# Line 466 | Line 736 | int main(int argc, char **argv)
736          sigaction(SIGINT, &sigint_sa, NULL);
737   #endif
738  
739 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
739 > #ifndef USE_CPU_EMUL_SERVICES
740 > #if defined(HAVE_PTHREADS)
741 >
742 >        // POSIX threads available, start 60Hz thread
743 >        Set_pthread_attr(&tick_thread_attr, 0);
744 >        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
745 >        if (!tick_thread_active) {
746 >                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
747 >                ErrorAlert(str);
748 >                QuitEmulator();
749 >        }
750 >        D(bug("60Hz thread started\n"));
751 >
752 > #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
753  
754          // POSIX.4 timers and real-time signals available, start 60Hz timer
755          sigemptyset(&timer_sa.sa_mask);
# Line 497 | Line 780 | int main(int argc, char **argv)
780          }
781          D(bug("60Hz timer started\n"));
782  
500 #elif defined(HAVE_PTHREADS)
501
502        // POSIX threads available, start 60Hz thread
503        pthread_attr_init(&tick_thread_attr);
504 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
505        if (geteuid() == 0) {
506                pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
507                pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
508                struct sched_param fifo_param;
509                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
510                pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
511        }
512 #endif
513        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
514        if (!tick_thread_active) {
515                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
516                ErrorAlert(str);
517                QuitEmulator();
518        }
519        D(bug("60Hz thread started\n"));
520
783   #else
784  
785          // Start 60Hz timer
786          sigemptyset(&timer_sa.sa_mask);         // Block virtual 68k interrupts during SIGARLM handling
787 + #if !EMULATED_68K
788          sigaddset(&timer_sa.sa_mask, SIG_IRQ);
789 + #endif
790          timer_sa.sa_handler = one_tick;
791          timer_sa.sa_flags = SA_ONSTACK | SA_RESTART;
792          if (sigaction(SIGALRM, &timer_sa, NULL) < 0) {
# Line 536 | Line 800 | int main(int argc, char **argv)
800          setitimer(ITIMER_REAL, &req, NULL);
801  
802   #endif
803 + #endif
804  
805 < #ifdef HAVE_PTHREADS
805 > #ifdef USE_PTHREADS_SERVICES
806          // Start XPRAM watchdog thread
807 <        memcpy(last_xpram, XPRAM, 256);
807 >        memcpy(last_xpram, XPRAM, XPRAM_SIZE);
808          xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0);
809          D(bug("XPRAM thread started\n"));
810   #endif
# Line 566 | Line 831 | void QuitEmulator(void)
831          Exit680x0();
832   #endif
833  
834 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
835 <        // Stop 60Hz timer
836 <        timer_delete(timer);
837 < #elif defined(HAVE_PTHREADS)
834 > #if defined(USE_CPU_EMUL_SERVICES)
835 >        // Show statistics
836 >        uint64 emulated_ticks_end = GetTicks_usec();
837 >        D(bug("%ld ticks in %ld usec = %f ticks/sec [%ld tick checks]\n",
838 >                  (long)emulated_ticks_count, (long)(emulated_ticks_end - emulated_ticks_start),
839 >                  emulated_ticks_count * 1000000.0 / (emulated_ticks_end - emulated_ticks_start), (long)n_check_ticks));
840 > #elif defined(USE_PTHREADS_SERVICES)
841          // Stop 60Hz thread
842          if (tick_thread_active) {
843                  tick_thread_cancel = true;
# Line 578 | Line 846 | void QuitEmulator(void)
846   #endif
847                  pthread_join(tick_thread, NULL);
848          }
849 + #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
850 +        // Stop 60Hz timer
851 +        timer_delete(timer);
852   #else
853          struct itimerval req;
854          req.it_interval.tv_sec = req.it_value.tv_sec = 0;
# Line 585 | Line 856 | void QuitEmulator(void)
856          setitimer(ITIMER_REAL, &req, NULL);
857   #endif
858  
859 < #ifdef HAVE_PTHREADS
859 > #ifdef USE_PTHREADS_SERVICES
860          // Stop XPRAM watchdog thread
861          if (xpram_thread_active) {
862                  xpram_thread_cancel = true;
# Line 600 | Line 871 | void QuitEmulator(void)
871          ExitAll();
872  
873          // Free ROM/RAM areas
874 < #if REAL_ADDRESSING
875 <        if (memory_mapped_from_zero)
605 <                munmap((caddr_t)0x0000, mapped_ram_rom_size);
606 <        else
607 < #endif
608 < #if REAL_ADDRESSING || DIRECT_ADDRESSING
609 <        if (RAMBaseHost != (uint8 *)MAP_FAILED) {
610 <                munmap((caddr_t)RAMBaseHost, mapped_ram_rom_size);
874 >        if (RAMBaseHost != VM_MAP_FAILED) {
875 >                vm_release(RAMBaseHost, RAMSize + 0x100000);
876                  RAMBaseHost = NULL;
612        }
613 #else
614        if (ROMBaseHost) {
615                free(ROMBaseHost);
877                  ROMBaseHost = NULL;
878          }
618        if (RAMBaseHost) {
619                free(RAMBaseHost);
620                RAMBaseHost = NULL;
621        }
622 #endif
879  
880   #if USE_SCRATCHMEM_SUBTERFUGE
881          // Delete scratch memory area
882 <        if (ScratchMem) {
883 <                free((void *)(ScratchMem - SCRATCH_MEM_SIZE/2));
882 >        if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
883 >                vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
884                  ScratchMem = NULL;
885          }
886   #endif
# Line 632 | Line 888 | void QuitEmulator(void)
888   #if REAL_ADDRESSING
889          // Delete Low Memory area
890          if (lm_area_mapped)
891 <                munmap((char *)0x0000, 0x2000);
891 >                vm_release(0, 0x2000);
892   #endif
893 <
894 <        // Close /dev/zero
895 <        if (zero_fd > 0)
640 <                close(zero_fd);
893 >        
894 >        // Exit VM wrappers
895 >        vm_exit();
896  
897          // Exit system routines
898          SysExit();
# Line 646 | Line 901 | void QuitEmulator(void)
901          PrefsExit();
902  
903          // Close X11 server connection
904 + #ifndef USE_SDL_VIDEO
905          if (x_display)
906                  XCloseDisplay(x_display);
907 + #endif
908  
909          exit(0);
910   }
# Line 660 | Line 917 | void QuitEmulator(void)
917  
918   void FlushCodeCache(void *start, uint32 size)
919   {
920 + #if USE_JIT
921 +    if (UseJIT)
922 +                flush_icache_range((uintptr)start, size);
923 + #endif
924   #if !EMULATED_68K && defined(__NetBSD__)
925          m68k_sync_icache(start, size);
926   #endif
# Line 677 | Line 938 | static void sigint_handler(...)
938          uaecptr nextpc;
939          extern void m68k_dumpstate(uaecptr *nextpc);
940          m68k_dumpstate(&nextpc);
941 < #else
941 > #endif
942 >        VideoQuitFullScreen();
943          char *arg[4] = {"mon", "-m", "-r", NULL};
944          mon(3, arg);
945          QuitEmulator();
946 + }
947   #endif
948 +
949 +
950 + #ifdef HAVE_PTHREADS
951 + /*
952 + *  Pthread configuration
953 + */
954 +
955 + void Set_pthread_attr(pthread_attr_t *attr, int priority)
956 + {
957 +        pthread_attr_init(attr);
958 + #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
959 +        // Some of these only work for superuser
960 +        if (geteuid() == 0) {
961 +                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
962 +                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
963 +                struct sched_param fifo_param;
964 +                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
965 +                                              sched_get_priority_max(SCHED_FIFO)) / 2 +
966 +                                             priority);
967 +                pthread_attr_setschedparam(attr, &fifo_param);
968 +        }
969 +        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
970 + #ifdef PTHREAD_SCOPE_BOUND_NP
971 +            // If system scope is not available (eg. we're not running
972 +            // with CAP_SCHED_MGT capability on an SGI box), try bound
973 +            // scope.  It exposes pthread scheduling to the kernel,
974 +            // without setting realtime priority.
975 +            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
976 + #endif
977 +        }
978 + #endif
979 + }
980 + #endif // HAVE_PTHREADS
981 +
982 +
983 + /*
984 + *  Mutexes
985 + */
986 +
987 + #ifdef HAVE_PTHREADS
988 +
989 + struct B2_mutex {
990 +        B2_mutex() {
991 +            pthread_mutexattr_t attr;
992 +            pthread_mutexattr_init(&attr);
993 +            // Initialize the mutex for priority inheritance --
994 +            // required for accurate timing.
995 + #if defined(HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL) && !defined(__CYGWIN__)
996 +            pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
997 + #endif
998 + #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
999 +            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
1000 + #endif
1001 + #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
1002 +            pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
1003 + #endif
1004 +            pthread_mutex_init(&m, &attr);
1005 +            pthread_mutexattr_destroy(&attr);
1006 +        }
1007 +        ~B2_mutex() {
1008 +            pthread_mutex_trylock(&m); // Make sure it's locked before
1009 +            pthread_mutex_unlock(&m);  // unlocking it.
1010 +            pthread_mutex_destroy(&m);
1011 +        }
1012 +        pthread_mutex_t m;
1013 + };
1014 +
1015 + B2_mutex *B2_create_mutex(void)
1016 + {
1017 +        return new B2_mutex;
1018 + }
1019 +
1020 + void B2_lock_mutex(B2_mutex *mutex)
1021 + {
1022 +        pthread_mutex_lock(&mutex->m);
1023 + }
1024 +
1025 + void B2_unlock_mutex(B2_mutex *mutex)
1026 + {
1027 +        pthread_mutex_unlock(&mutex->m);
1028 + }
1029 +
1030 + void B2_delete_mutex(B2_mutex *mutex)
1031 + {
1032 +        delete mutex;
1033 + }
1034 +
1035 + #else
1036 +
1037 + struct B2_mutex {
1038 +        int dummy;
1039 + };
1040 +
1041 + B2_mutex *B2_create_mutex(void)
1042 + {
1043 +        return new B2_mutex;
1044 + }
1045 +
1046 + void B2_lock_mutex(B2_mutex *mutex)
1047 + {
1048 + }
1049 +
1050 + void B2_unlock_mutex(B2_mutex *mutex)
1051 + {
1052   }
1053 +
1054 + void B2_delete_mutex(B2_mutex *mutex)
1055 + {
1056 +        delete mutex;
1057 + }
1058 +
1059   #endif
1060  
1061  
# Line 695 | Line 1068 | uint32 InterruptFlags = 0;
1068   #if EMULATED_68K
1069   void SetInterruptFlag(uint32 flag)
1070   {
1071 < #ifdef HAVE_PTHREADS
699 <        pthread_mutex_lock(&intflag_lock);
1071 >        LOCK_INTFLAGS;
1072          InterruptFlags |= flag;
1073 <        pthread_mutex_unlock(&intflag_lock);
702 < #else
703 <        InterruptFlags |= flag;         // Pray that this is an atomic operation...
704 < #endif
1073 >        UNLOCK_INTFLAGS;
1074   }
1075  
1076   void ClearInterruptFlag(uint32 flag)
1077   {
1078 < #ifdef HAVE_PTHREADS
710 <        pthread_mutex_lock(&intflag_lock);
711 <        InterruptFlags &= ~flag;
712 <        pthread_mutex_unlock(&intflag_lock);
713 < #else
1078 >        LOCK_INTFLAGS;
1079          InterruptFlags &= ~flag;
1080 < #endif
1080 >        UNLOCK_INTFLAGS;
1081   }
1082   #endif
1083  
# Line 739 | Line 1104 | void TriggerNMI(void)
1104  
1105   static void xpram_watchdog(void)
1106   {
1107 <        if (memcmp(last_xpram, XPRAM, 256)) {
1108 <                memcpy(last_xpram, XPRAM, 256);
1107 >        if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1108 >                memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1109                  SaveXPRAM();
1110          }
1111   }
1112  
1113 < #ifdef HAVE_PTHREADS
1113 > #ifdef USE_PTHREADS_SERVICES
1114   static void *xpram_func(void *arg)
1115   {
1116          while (!xpram_thread_cancel) {
1117                  for (int i=0; i<60 && !xpram_thread_cancel; i++)
1118 <                        Delay_usec(999999);
1118 >                        Delay_usec(999999);             // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
1119                  xpram_watchdog();
1120          }
1121          return NULL;
# Line 770 | Line 1135 | static void one_second(void)
1135          SetInterruptFlag(INTFLAG_1HZ);
1136          TriggerInterrupt();
1137  
1138 < #ifndef HAVE_PTHREADS
1138 > #ifndef USE_PTHREADS_SERVICES
1139          static int second_counter = 0;
1140          if (++second_counter > 60) {
1141                  second_counter = 0;
# Line 787 | Line 1152 | static void one_tick(...)
1152                  one_second();
1153          }
1154  
1155 < #ifndef HAVE_PTHREADS
1156 <        // No threads available, perform video refresh from here
1155 > #ifndef USE_PTHREADS_SERVICES
1156 >        // Threads not used to trigger interrupts, perform video refresh from here
1157          VideoRefresh();
1158   #endif
1159  
1160 + #ifndef HAVE_PTHREADS
1161 +        // No threads available, perform networking from here
1162 +        SetInterruptFlag(INTFLAG_ETHER);
1163 + #endif
1164 +
1165          // Trigger 60Hz interrupt
1166          if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
1167                  SetInterruptFlag(INTFLAG_60HZ);
# Line 799 | Line 1169 | static void one_tick(...)
1169          }
1170   }
1171  
1172 < #ifdef HAVE_PTHREADS
1172 > #ifdef USE_PTHREADS_SERVICES
1173   static void *tick_func(void *arg)
1174   {
1175 +        uint64 start = GetTicks_usec();
1176 +        int64 ticks = 0;
1177          uint64 next = GetTicks_usec();
1178          while (!tick_thread_cancel) {
1179                  one_tick();
# Line 811 | Line 1183 | static void *tick_func(void *arg)
1183                          Delay_usec(delay);
1184                  else if (delay < -16625)
1185                          next = GetTicks_usec();
1186 +                ticks++;
1187          }
1188 +        uint64 end = GetTicks_usec();
1189 +        D(bug("%lld ticks in %lld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
1190          return NULL;
1191   }
1192   #endif
1193  
1194  
820 /*
821 *  Get current value of microsecond timer
822 */
823
824 uint64 GetTicks_usec(void)
825 {
826 #ifdef HAVE_CLOCK_GETTIME
827        struct timespec t;
828        clock_gettime(CLOCK_REALTIME, &t);
829        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
830 #else
831        struct timeval t;
832        gettimeofday(&t, NULL);
833        return (uint64)t.tv_sec * 1000000 + t.tv_usec;
834 #endif
835 }
836
837
838 /*
839 *  Delay by specified number of microseconds (<1 second)
840 *  (adapted from SDL_Delay() source; this function is designed to provide
841 *  the highest accuracy possible)
842 */
843
844 #if defined(linux)
845 // Linux select() changes its timeout parameter upon return to contain
846 // the remaining time. Most other unixen leave it unchanged or undefined.
847 #define SELECT_SETS_REMAINING
848 #elif defined(__FreeBSD__) || defined(__sun__) || defined(sgi)
849 #define USE_NANOSLEEP
850 #endif
851
852 void Delay_usec(uint32 usec)
853 {
854        int was_error;
855
856 #ifdef USE_NANOSLEEP
857        struct timespec elapsed, tv;
858 #else
859        struct timeval tv;
860 #ifndef SELECT_SETS_REMAINING
861        uint64 then, now, elapsed;
862 #endif
863 #endif
864
865        // Set the timeout interval - Linux only needs to do this once
866 #ifdef SELECT_SETS_REMAINING
867    tv.tv_sec = 0;
868    tv.tv_usec = usec;
869 #elif defined(USE_NANOSLEEP)
870    elapsed.tv_sec = 0;
871    elapsed.tv_nsec = usec * 1000;
872 #else
873    then = GetTicks_usec();
874 #endif
875
876        do {
877                errno = 0;
878 #ifdef USE_NANOSLEEP
879                tv.tv_sec = elapsed.tv_sec;
880                tv.tv_nsec = elapsed.tv_nsec;
881                was_error = nanosleep(&tv, &elapsed);
882 #else
883 #ifndef SELECT_SETS_REMAINING
884                // Calculate the time interval left (in case of interrupt)
885                now = GetTicks_usec();
886                elapsed = now - then;
887                then = now;
888                if (elapsed >= usec)
889                        break;
890                usec -= elapsed;
891                tv.tv_sec = 0;
892                tv.tv_usec = usec;
893 #endif
894                was_error = select(0, NULL, NULL, NULL, &tv);
895 #endif
896        } while (was_error && (errno == EINTR));
897 }
898
899
1195   #if !EMULATED_68K
1196   /*
1197   *  Virtual 68k interrupt handler
# Line 1087 | Line 1382 | static void sigill_handler(int sig, int
1382                  }
1383  
1384                  case 0xf327:    // fsave -(sp)
1385 <                        if (CPUIs68060) {
1386 <                                regs->a[7] -= 4;
1092 <                                WriteMacInt32(regs->a[7], 0x60000000);  // Idle frame
1093 <                                regs->a[7] -= 4;
1094 <                                WriteMacInt32(regs->a[7], 0);
1095 <                                regs->a[7] -= 4;
1096 <                                WriteMacInt32(regs->a[7], 0);
1097 <                        } else {
1098 <                                regs->a[7] -= 4;
1099 <                                WriteMacInt32(regs->a[7], 0x41000000);  // Idle frame
1100 <                        }
1385 >                        regs->a[7] -= 4;
1386 >                        WriteMacInt32(regs->a[7], 0x41000000);  // Idle frame
1387                          scp->sc_sp = regs->a[7];
1388                          INC_PC(2);
1389                          break;
1390  
1391                  case 0xf35f:    // frestore (sp)+
1392 <                        if (CPUIs68060)
1107 <                                regs->a[7] += 12;
1108 <                        else
1109 <                                regs->a[7] += 4;
1392 >                        regs->a[7] += 4;
1393                          scp->sc_sp = regs->a[7];
1394                          INC_PC(2);
1395                          break;
# Line 1202 | Line 1485 | ill:           printf("SIGILL num %d, code %d\n",
1485                          for (int i=0; i<8; i++)
1486                                  printf("  a%d %08x\n", i, state->ss_frame.f_regs[i+8]);
1487  
1488 +                        VideoQuitFullScreen();
1489   #ifdef ENABLE_MON
1490                          char *arg[4] = {"mon", "-m", "-r", NULL};
1491                          mon(3, arg);
# Line 1262 | Line 1546 | void display_alert(int title_id, int pre
1546  
1547   void ErrorAlert(const char *text)
1548   {
1549 < #ifdef ENABLE_GTK
1549 > #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
1550          if (PrefsFindBool("nogui") || x_display == NULL) {
1551                  printf(GetString(STR_SHELL_ERROR_PREFIX), text);
1552                  return;
# Line 1281 | Line 1565 | void ErrorAlert(const char *text)
1565  
1566   void WarningAlert(const char *text)
1567   {
1568 < #ifdef ENABLE_GTK
1568 > #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
1569          if (PrefsFindBool("nogui") || x_display == NULL) {
1570                  printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1571                  return;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines