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.36 by cebix, 2001-06-30T17:21:54Z 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-2001 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 51 | Line 58 | struct sigstate {
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 58 | 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 72 | Line 85 | struct sigstate {
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 83 | 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 103 | 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 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 123 | 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  
126 #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 140 | 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 187 | 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("Usage: %s [OPTION...]\n", prg_name);
380 <        printf("\nUnix options:\n");
381 <        printf("  --display STRING\n    X display to use\n");
382 <        printf("  --break ADDRESS\n    set ROM breakpoint\n");
383 <        printf("  --rominfo\n    dump ROM information\n");
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   }
# Line 215 | 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  
218 #ifdef ENABLE_GTK
219        // Init GTK
220        gtk_set_locale();
221        gtk_init(&argc, &argv);
222        x_display_name = gdk_get_display(); // gtk_init() handles and removes the "--display" argument
223 #endif
224
225        // Read preferences
226        PrefsInit(argc, argv);
227
406          // Parse command line arguments
407          for (int i=1; i<argc; i++) {
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++;
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 <                        i++;
418 <                        if (i < argc)
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 <                } else if (argv[i][0] == '-') {
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 258 | 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
487 + #endif
488 +
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 267 | Line 513 | int main(int argc, char **argv)
513                  if (!PrefsEditor())
514                          QuitEmulator();
515  
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
528          if (RAMSize < 1024*1024) {
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          RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
# Line 281 | Line 539 | int main(int argc, char **argv)
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          // Flag: RAM and ROM are contigously allocated from address 0
549          bool memory_mapped_from_zero = false;
550 <        
551 <        // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
552 <        // when trying to map a too big chunk of memory starting at address 0
553 < #if defined(OS_solaris) || defined(OS_netbsd)
554 <        const bool can_map_all_memory = false;
292 < #else
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 +        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_fixed(0, RAMSize + 0x100000) == 0)) {
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          
566 + #ifndef PAGEZERO_HACK
567          // Otherwise, just create the Low Memory area (0x0000..0x2000)
568 <        else if (vm_acquire_fixed(0, 0x2000) == 0) {
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          }
# Line 312 | Line 577 | int main(int argc, char **argv)
577                  QuitEmulator();
578          }
579   #endif
580 <
316 < #if USE_SCRATCHMEM_SUBTERFUGE
317 <        // Allocate scratch memory
318 <        ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
319 <        if (ScratchMem == VM_MAP_FAILED) {
320 <                ErrorAlert(STR_NO_MEM_ERR);
321 <                QuitEmulator();
322 <        }
323 <        ScratchMem += SCRATCH_MEM_SIZE/2;       // ScratchMem points to middle of block
324 < #endif
580 > #endif /* REAL_ADDRESSING */
581  
582          // Create areas for Mac RAM and ROM
583   #if REAL_ADDRESSING
# Line 332 | Line 588 | int main(int argc, char **argv)
588          else
589   #endif
590          {
591 <                RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
592 <                ROMBaseHost = (uint8 *)vm_acquire(0x100000);
337 <                if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
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 +                RAMBaseHost = ram_rom_area;
597 +                ROMBaseHost = RAMBaseHost + RAMSize;
598 +        }
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          // RAMBaseMac shall always be zero
# Line 347 | Line 614 | int main(int argc, char **argv)
614          ROMBaseMac = Host2MacAddr(ROMBaseHost);
615   #endif
616   #if REAL_ADDRESSING
617 <        RAMBaseMac = (uint32)RAMBaseHost;
618 <        ROMBaseMac = (uint32)ROMBaseHost;
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 410 | 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  
418 #if !EMULATED_68K
419        // (Virtual) supervisor mode, disable interrupts
420        EmulatedSR = 0x2700;
421
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));
# Line 469 | 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 500 | Line 780 | int main(int argc, char **argv)
780          }
781          D(bug("60Hz timer started\n"));
782  
503 #elif defined(HAVE_PTHREADS)
504
505        // POSIX threads available, start 60Hz thread
506        pthread_attr_init(&tick_thread_attr);
507 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
508        if (geteuid() == 0) {
509                pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
510                pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
511                struct sched_param fifo_param;
512                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
513                pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
514        }
515 #endif
516        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
517        if (!tick_thread_active) {
518                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
519                ErrorAlert(str);
520                QuitEmulator();
521        }
522        D(bug("60Hz thread started\n"));
523
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 539 | 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 569 | 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 581 | 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 588 | 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 604 | Line 872 | void QuitEmulator(void)
872  
873          // Free ROM/RAM areas
874          if (RAMBaseHost != VM_MAP_FAILED) {
875 <                vm_release(RAMBaseHost, RAMSize);
875 >                vm_release(RAMBaseHost, RAMSize + 0x100000);
876                  RAMBaseHost = NULL;
609        }
610        if (ROMBaseHost != VM_MAP_FAILED) {
611                vm_release(ROMBaseHost, 0x100000);
877                  ROMBaseHost = NULL;
878          }
879  
# Line 636 | 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 650 | 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 668 | Line 939 | static void sigint_handler(...)
939          extern void m68k_dumpstate(uaecptr *nextpc);
940          m68k_dumpstate(&nextpc);
941   #endif
942 +        VideoQuitFullScreen();
943          char *arg[4] = {"mon", "-m", "-r", NULL};
944          mon(3, arg);
945          QuitEmulator();
# Line 675 | Line 947 | static void sigint_handler(...)
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 +
1062   /*
1063   *  Interrupt flags (must be handled atomically!)
1064   */
# Line 684 | Line 1068 | uint32 InterruptFlags = 0;
1068   #if EMULATED_68K
1069   void SetInterruptFlag(uint32 flag)
1070   {
1071 < #ifdef HAVE_PTHREADS
688 <        pthread_mutex_lock(&intflag_lock);
1071 >        LOCK_INTFLAGS;
1072          InterruptFlags |= flag;
1073 <        pthread_mutex_unlock(&intflag_lock);
691 < #else
692 <        InterruptFlags |= flag;         // Pray that this is an atomic operation...
693 < #endif
1073 >        UNLOCK_INTFLAGS;
1074   }
1075  
1076   void ClearInterruptFlag(uint32 flag)
1077   {
1078 < #ifdef HAVE_PTHREADS
699 <        pthread_mutex_lock(&intflag_lock);
700 <        InterruptFlags &= ~flag;
701 <        pthread_mutex_unlock(&intflag_lock);
702 < #else
1078 >        LOCK_INTFLAGS;
1079          InterruptFlags &= ~flag;
1080 < #endif
1080 >        UNLOCK_INTFLAGS;
1081   }
1082   #endif
1083  
# Line 728 | 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) {
# Line 759 | 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 776 | 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 788 | 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 800 | 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  
809 /*
810 *  Get current value of microsecond timer
811 */
812
813 uint64 GetTicks_usec(void)
814 {
815 #ifdef HAVE_CLOCK_GETTIME
816        struct timespec t;
817        clock_gettime(CLOCK_REALTIME, &t);
818        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
819 #else
820        struct timeval t;
821        gettimeofday(&t, NULL);
822        return (uint64)t.tv_sec * 1000000 + t.tv_usec;
823 #endif
824 }
825
826
827 /*
828 *  Delay by specified number of microseconds (<1 second)
829 *  (adapted from SDL_Delay() source; this function is designed to provide
830 *  the highest accuracy possible)
831 */
832
833 #if defined(linux)
834 // Linux select() changes its timeout parameter upon return to contain
835 // the remaining time. Most other unixen leave it unchanged or undefined.
836 #define SELECT_SETS_REMAINING
837 #elif defined(__FreeBSD__) || defined(__sun__)
838 #define USE_NANOSLEEP
839 #elif defined(HAVE_PTHREADS) && defined(sgi)
840 // SGI pthreads has a bug when using pthreads+signals+nanosleep,
841 // so instead of using nanosleep, wait on a CV which is never signalled.
842 #define USE_COND_TIMEDWAIT
843 #endif
844
845 void Delay_usec(uint32 usec)
846 {
847        int was_error;
848
849 #if defined(USE_NANOSLEEP)
850        struct timespec elapsed, tv;
851 #elif defined(USE_COND_TIMEDWAIT)
852        // Use a local mutex and cv, so threads remain independent
853        pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
854        pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
855        struct timespec elapsed;
856        uint64 future;
857 #else
858        struct timeval tv;
859 #ifndef SELECT_SETS_REMAINING
860        uint64 then, now, elapsed;
861 #endif
862 #endif
863
864        // Set the timeout interval - Linux only needs to do this once
865 #if defined(SELECT_SETS_REMAINING)
866    tv.tv_sec = 0;
867    tv.tv_usec = usec;
868 #elif defined(USE_NANOSLEEP)
869    elapsed.tv_sec = 0;
870    elapsed.tv_nsec = usec * 1000;
871 #elif defined(USE_COND_TIMEDWAIT)
872        future = GetTicks_usec() + usec;
873        elapsed.tv_sec = future / 1000000;
874        elapsed.tv_nsec = (future % 1000000) * 1000;
875 #else
876    then = GetTicks_usec();
877 #endif
878
879        do {
880                errno = 0;
881 #if defined(USE_NANOSLEEP)
882                tv.tv_sec = elapsed.tv_sec;
883                tv.tv_nsec = elapsed.tv_nsec;
884                was_error = nanosleep(&tv, &elapsed);
885 #elif defined(USE_COND_TIMEDWAIT)
886                was_error = pthread_mutex_lock(&delay_mutex);
887                was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
888                was_error = pthread_mutex_unlock(&delay_mutex);
889 #else
890 #ifndef SELECT_SETS_REMAINING
891                // Calculate the time interval left (in case of interrupt)
892                now = GetTicks_usec();
893                elapsed = now - then;
894                then = now;
895                if (elapsed >= usec)
896                        break;
897                usec -= elapsed;
898                tv.tv_sec = 0;
899                tv.tv_usec = usec;
900 #endif
901                was_error = select(0, NULL, NULL, NULL, &tv);
902 #endif
903        } while (was_error && (errno == EINTR));
904 }
905
906
1195   #if !EMULATED_68K
1196   /*
1197   *  Virtual 68k interrupt handler
# Line 1197 | 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 1257 | 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 1276 | 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