475 |
|
sigaction(SIGINT, &sigint_sa, NULL); |
476 |
|
#endif |
477 |
|
|
478 |
< |
#if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) |
478 |
> |
#if defined(HAVE_PTHREADS) |
479 |
> |
|
480 |
> |
// POSIX threads available, start 60Hz thread |
481 |
> |
pthread_attr_init(&tick_thread_attr); |
482 |
> |
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) |
483 |
> |
if (geteuid() == 0) { |
484 |
> |
pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED); |
485 |
> |
pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO); |
486 |
> |
struct sched_param fifo_param; |
487 |
> |
fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2; |
488 |
> |
pthread_attr_setschedparam(&tick_thread_attr, &fifo_param); |
489 |
> |
} |
490 |
> |
#endif |
491 |
> |
tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0); |
492 |
> |
if (!tick_thread_active) { |
493 |
> |
sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno)); |
494 |
> |
ErrorAlert(str); |
495 |
> |
QuitEmulator(); |
496 |
> |
} |
497 |
> |
D(bug("60Hz thread started\n")); |
498 |
> |
|
499 |
> |
#elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) |
500 |
|
|
501 |
|
// POSIX.4 timers and real-time signals available, start 60Hz timer |
502 |
|
sigemptyset(&timer_sa.sa_mask); |
527 |
|
} |
528 |
|
D(bug("60Hz timer started\n")); |
529 |
|
|
509 |
– |
#elif defined(HAVE_PTHREADS) |
510 |
– |
|
511 |
– |
// POSIX threads available, start 60Hz thread |
512 |
– |
pthread_attr_init(&tick_thread_attr); |
513 |
– |
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) |
514 |
– |
if (geteuid() == 0) { |
515 |
– |
pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED); |
516 |
– |
pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO); |
517 |
– |
struct sched_param fifo_param; |
518 |
– |
fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2; |
519 |
– |
pthread_attr_setschedparam(&tick_thread_attr, &fifo_param); |
520 |
– |
} |
521 |
– |
#endif |
522 |
– |
tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0); |
523 |
– |
if (!tick_thread_active) { |
524 |
– |
sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno)); |
525 |
– |
ErrorAlert(str); |
526 |
– |
QuitEmulator(); |
527 |
– |
} |
528 |
– |
D(bug("60Hz thread started\n")); |
529 |
– |
|
530 |
|
#else |
531 |
|
|
532 |
|
// Start 60Hz timer |
575 |
|
Exit680x0(); |
576 |
|
#endif |
577 |
|
|
578 |
< |
#if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) |
579 |
< |
// Stop 60Hz timer |
580 |
< |
timer_delete(timer); |
581 |
< |
#elif defined(HAVE_PTHREADS) |
578 |
> |
#if defined(HAVE_PTHREADS) |
579 |
|
// Stop 60Hz thread |
580 |
|
if (tick_thread_active) { |
581 |
|
tick_thread_cancel = true; |
584 |
|
#endif |
585 |
|
pthread_join(tick_thread, NULL); |
586 |
|
} |
587 |
+ |
#elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) |
588 |
+ |
// Stop 60Hz timer |
589 |
+ |
timer_delete(timer); |
590 |
|
#else |
591 |
|
struct itimerval req; |
592 |
|
req.it_interval.tv_sec = req.it_value.tv_sec = 0; |
849 |
|
#ifdef HAVE_PTHREADS |
850 |
|
static void *tick_func(void *arg) |
851 |
|
{ |
852 |
+ |
uint64 start = GetTicks_usec(); |
853 |
+ |
int64 ticks = 0; |
854 |
|
uint64 next = GetTicks_usec(); |
855 |
|
while (!tick_thread_cancel) { |
856 |
|
one_tick(); |
860 |
|
Delay_usec(delay); |
861 |
|
else if (delay < -16625) |
862 |
|
next = GetTicks_usec(); |
863 |
+ |
ticks++; |
864 |
|
} |
865 |
+ |
uint64 end = GetTicks_usec(); |
866 |
+ |
D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); |
867 |
|
return NULL; |
868 |
|
} |
869 |
|
#endif |
870 |
|
|
871 |
|
|
867 |
– |
/* |
868 |
– |
* Get current value of microsecond timer |
869 |
– |
*/ |
870 |
– |
|
871 |
– |
uint64 GetTicks_usec(void) |
872 |
– |
{ |
873 |
– |
#ifdef HAVE_CLOCK_GETTIME |
874 |
– |
struct timespec t; |
875 |
– |
clock_gettime(CLOCK_REALTIME, &t); |
876 |
– |
return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; |
877 |
– |
#else |
878 |
– |
struct timeval t; |
879 |
– |
gettimeofday(&t, NULL); |
880 |
– |
return (uint64)t.tv_sec * 1000000 + t.tv_usec; |
881 |
– |
#endif |
882 |
– |
} |
883 |
– |
|
884 |
– |
|
885 |
– |
/* |
886 |
– |
* Delay by specified number of microseconds (<1 second) |
887 |
– |
* (adapted from SDL_Delay() source; this function is designed to provide |
888 |
– |
* the highest accuracy possible) |
889 |
– |
*/ |
890 |
– |
|
891 |
– |
#if defined(linux) |
892 |
– |
// Linux select() changes its timeout parameter upon return to contain |
893 |
– |
// the remaining time. Most other unixen leave it unchanged or undefined. |
894 |
– |
#define SELECT_SETS_REMAINING |
895 |
– |
#elif defined(__FreeBSD__) || defined(__sun__) |
896 |
– |
#define USE_NANOSLEEP |
897 |
– |
#elif defined(HAVE_PTHREADS) && defined(sgi) |
898 |
– |
// SGI pthreads has a bug when using pthreads+signals+nanosleep, |
899 |
– |
// so instead of using nanosleep, wait on a CV which is never signalled. |
900 |
– |
#define USE_COND_TIMEDWAIT |
901 |
– |
#endif |
902 |
– |
|
903 |
– |
void Delay_usec(uint32 usec) |
904 |
– |
{ |
905 |
– |
int was_error; |
906 |
– |
|
907 |
– |
#if defined(USE_NANOSLEEP) |
908 |
– |
struct timespec elapsed, tv; |
909 |
– |
#elif defined(USE_COND_TIMEDWAIT) |
910 |
– |
// Use a local mutex and cv, so threads remain independent |
911 |
– |
pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER; |
912 |
– |
pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER; |
913 |
– |
struct timespec elapsed; |
914 |
– |
uint64 future; |
915 |
– |
#else |
916 |
– |
struct timeval tv; |
917 |
– |
#ifndef SELECT_SETS_REMAINING |
918 |
– |
uint64 then, now, elapsed; |
919 |
– |
#endif |
920 |
– |
#endif |
921 |
– |
|
922 |
– |
// Set the timeout interval - Linux only needs to do this once |
923 |
– |
#if defined(SELECT_SETS_REMAINING) |
924 |
– |
tv.tv_sec = 0; |
925 |
– |
tv.tv_usec = usec; |
926 |
– |
#elif defined(USE_NANOSLEEP) |
927 |
– |
elapsed.tv_sec = 0; |
928 |
– |
elapsed.tv_nsec = usec * 1000; |
929 |
– |
#elif defined(USE_COND_TIMEDWAIT) |
930 |
– |
future = GetTicks_usec() + usec; |
931 |
– |
elapsed.tv_sec = future / 1000000; |
932 |
– |
elapsed.tv_nsec = (future % 1000000) * 1000; |
933 |
– |
#else |
934 |
– |
then = GetTicks_usec(); |
935 |
– |
#endif |
936 |
– |
|
937 |
– |
do { |
938 |
– |
errno = 0; |
939 |
– |
#if defined(USE_NANOSLEEP) |
940 |
– |
tv.tv_sec = elapsed.tv_sec; |
941 |
– |
tv.tv_nsec = elapsed.tv_nsec; |
942 |
– |
was_error = nanosleep(&tv, &elapsed); |
943 |
– |
#elif defined(USE_COND_TIMEDWAIT) |
944 |
– |
was_error = pthread_mutex_lock(&delay_mutex); |
945 |
– |
was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed); |
946 |
– |
was_error = pthread_mutex_unlock(&delay_mutex); |
947 |
– |
#else |
948 |
– |
#ifndef SELECT_SETS_REMAINING |
949 |
– |
// Calculate the time interval left (in case of interrupt) |
950 |
– |
now = GetTicks_usec(); |
951 |
– |
elapsed = now - then; |
952 |
– |
then = now; |
953 |
– |
if (elapsed >= usec) |
954 |
– |
break; |
955 |
– |
usec -= elapsed; |
956 |
– |
tv.tv_sec = 0; |
957 |
– |
tv.tv_usec = usec; |
958 |
– |
#endif |
959 |
– |
was_error = select(0, NULL, NULL, NULL, &tv); |
960 |
– |
#endif |
961 |
– |
} while (was_error && (errno == EINTR)); |
962 |
– |
} |
963 |
– |
|
964 |
– |
|
872 |
|
#if !EMULATED_68K |
873 |
|
/* |
874 |
|
* Virtual 68k interrupt handler |