From a24aba69aeb51cd9e3ed032a334fcdf519c4d95a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 11 Jun 2016 09:52:33 -0700 Subject: [PATCH] VIDEO: Added priority boost to thread performing SDL processing and updates Reworked all priority adjustment code to leverage a new sim_os_set_thread_priority API which is coded to use pthreads or OS priority adjustment APIs as necessary. --- scp.c | 3 +- sim_console.c | 27 ++++----------- sim_disk.c | 6 +--- sim_ether.c | 12 ++----- sim_tape.c | 6 +--- sim_timer.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++-- sim_timer.h | 4 +++ sim_tmxr.c | 23 ++----------- sim_video.c | 2 ++ 9 files changed, 114 insertions(+), 63 deletions(-) diff --git a/scp.c b/scp.c index 7f118ca4..c06eaa24 100644 --- a/scp.c +++ b/scp.c @@ -7698,7 +7698,8 @@ if (double_quote_found && (!single_quote_found)) *tptr++ = quote; while (size--) { switch (*iptr) { - case '\r': *tptr++ = '\\'; *tptr++ = 'r'; break; + case '\r': + *tptr++ = '\\'; *tptr++ = 'r'; break; case '\n': *tptr++ = '\\'; *tptr++ = 'n'; break; case '\f': diff --git a/sim_console.c b/sim_console.c index 5b030553..6e707367 100644 --- a/sim_console.c +++ b/sim_console.c @@ -2156,17 +2156,13 @@ pthread_cond_t sim_console_startup_cond; static void * _console_poll(void *arg) { -int sched_policy; -struct sched_param sched_priority; int wait_count = 0; DEVICE *d; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - starting\n"); @@ -2529,7 +2525,7 @@ if (sim_log) { fflush (sim_log); _setmode (_fileno (sim_log), _O_BINARY); } -SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); +sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL); return SCPE_OK; } @@ -2539,7 +2535,7 @@ if (sim_log) { fflush (sim_log); _setmode (_fileno (sim_log), _O_TEXT); } -SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); +sim_os_set_thread_priority (PRIORITY_NORMAL); if ((std_input) && /* If Not Background process? */ (std_input != INVALID_HANDLE_VALUE) && (!SetConsoleMode(std_input, saved_mode))) /* Restore Normal mode */ @@ -2952,13 +2948,13 @@ if (ioctl (0, TIOCSETC, &runtchars) < 0) return SCPE_TTIERR; if (ioctl (0, TIOCSLTC, &runltchars) < 0) return SCPE_TTIERR; -nice (10); /* lower priority */ +sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL)l /* lower priority */ return SCPE_OK; } static t_stat sim_os_ttcmd (void) { -nice (-10); /* restore priority */ +sim_os_set_thread_priority (PRIORITY_NORMAL); /* restore priority */ fcntl (0, F_SETFL, cmdfl); /* block mode */ if (ioctl (0, TIOCSETP, &cmdtty) < 0) return SCPE_TTIERR; @@ -3026,7 +3022,6 @@ return SCPE_OK; #include struct termios cmdtty, runtty; -static int prior_norm = 1; static t_stat sim_os_ttinit (void) { @@ -3085,11 +3080,7 @@ runtty.c_cc[VINTR] = sim_int_char; /* in case changed */ #endif if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR; -if (prior_norm) { /* at normal pri? */ - errno = 0; - (void)nice (10); /* try to lower pri */ - prior_norm = errno; /* if no error, done */ - } +sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL); /* try to lower pri */ return SCPE_OK; } @@ -3097,11 +3088,7 @@ static t_stat sim_os_ttcmd (void) { if (!isatty (fileno (stdin))) /* skip if !tty */ return SCPE_OK; -if (!prior_norm) { /* priority down? */ - errno = 0; - (void)nice (-10); /* try to raise pri */ - prior_norm = (errno == 0); /* if no error, done */ - } +sim_os_set_thread_priority (PRIORITY_NORMAL); /* try to raise pri */ if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR; return SCPE_OK; diff --git a/sim_disk.c b/sim_disk.c index 926b9252..b946f22a 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -162,16 +162,12 @@ static void * _disk_io(void *arg) { UNIT* volatile uptr = (UNIT*)arg; -int sched_policy; -struct sched_param sched_priority; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which in general won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units)); diff --git a/sim_ether.c b/sim_ether.c index ef4c9c0c..d8fb77e2 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1689,8 +1689,6 @@ _eth_reader(void *arg) { ETH_DEV* volatile dev = (ETH_DEV*)arg; int status = 0; -int sched_policy; -struct sched_param sched_priority; int sel_ret = 0; int do_select = 0; SOCKET select_fd = 0; @@ -1721,9 +1719,7 @@ sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); while (dev->handle) { #if defined (_WIN32) @@ -1880,15 +1876,11 @@ _eth_writer(void *arg) { ETH_DEV* volatile dev = (ETH_DEV*)arg; ETH_WRITE_REQUEST *request; -int sched_policy; -struct sched_param sched_priority; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which in general won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n"); diff --git a/sim_tape.c b/sim_tape.c index 6b6f2ced..cff9e361 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -216,16 +216,12 @@ static void * _tape_io(void *arg) { UNIT* volatile uptr = (UNIT*)arg; -int sched_policy; -struct sched_param sched_priority; struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which in general won't be readily yielding the processor when this thread needs to run */ - pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); - ++sched_priority.sched_priority; - pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); + sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (ctx->dbit, ctx->dptr, "_tape_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units)); diff --git a/sim_timer.c b/sim_timer.c index ce3b6f12..2636c4c1 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -164,6 +164,59 @@ return sim_os_msec() - start_time; #define SIM_IDLE_MS_SLEEP sim_os_ms_sleep #endif +/* Mark the need for the sim_os_set_thread_priority routine, */ +/* allowing the feature and/or platform dependent code to provide it */ +#define NEED_THREAD_PRIORITY + +/* If we've got pthreads support then use pthreads mechanisms */ +#if defined(USE_READER_THREAD) + +#undef NEED_THREAD_PRIORITY + +#if defined(_WIN32) +/* On Windows there are several potentially disjoint threading APIs */ +/* in use (base win32 pthreads, libSDL provided threading, and direct */ +/* calls to beginthreadex), so go directly to the Win32 threading APIs */ +/* to manage thread priority */ +t_stat sim_os_set_thread_priority (int below_normal_above) +{ +const static int val[3] = {THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL}; + +if ((below_normal_above < -1) || (below_normal_above > 1)) + return SCPE_ARG; +SetThreadPriority (GetCurrentThread(), val[1 + below_normal_above]); +return SCPE_OK; +} +#else +/* Native pthreads priority implementation */ +t_stat sim_os_set_thread_priority (int below_normal_above) +{ +int sched_policy, min_prio, max_prio; +struct sched_param sched_priority; + +if ((below_normal_above < -1) || (below_normal_above > 1)) + return SCPE_ARG; + +pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); +min_prio = sched_get_priority_min(sched_policy); +max_prio = sched_get_priority_max(sched_policy); +switch (below_normal_above) { + case PRIORITY_BELOW_NORMAL: + sched_priority.sched_priority = min_prio; + break; + case PRIORITY_NORMAL: + sched_priority.sched_priority = (max_prio + min_prio) / 2; + break; + case PRIORITY_ABOVE_NORMAL: + sched_priority.sched_priority = max_prio; + break; + } +pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +return SCPE_OK; +} +#endif +#endif /* defined(USE_READER_THREAD) */ + /* OS-dependent timer and clock routines */ /* VMS */ @@ -261,8 +314,6 @@ return 0; /* Win32 routines */ -#include - const t_bool rtc_avail = TRUE; uint32 sim_os_msec (void) @@ -494,6 +545,45 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; return sim_os_msec () - stime; } +#if defined(NEED_THREAD_PRIORITY) +#undef NEED_THREAD_PRIORITY +#include +#include + +t_stat sim_os_set_thread_priority (int below_normal_above) +{ +if ((below_normal_above < -1) || (below_normal_above > 1)) + return SCPE_ARG; + +errno = 0; +switch (below_normal_above) { + case PRIORITY_BELOW_NORMAL: + if ((getpriority (PRIO_PROCESS, 0) <= 0) && /* at or above normal pri? */ + (errno == 0)) + setpriority (PRIO_PROCESS, 0, 10); + break; + case PRIORITY_NORMAL: + if (getpriority (PRIO_PROCESS, 0) != 0) /* at or above normal pri? */ + setpriority (PRIO_PROCESS, 0, 0); + break; + case PRIORITY_ABOVE_NORMAL: + if ((getpriority (PRIO_PROCESS, 0) <= 0) && /* at or above normal pri? */ + (errno == 0)) + setpriority (PRIO_PROCESS, 0, -10); + break; + } +return SCPE_OK; +} +#endif /* defined(NEED_THREAD_PRIORITY) */ + +#endif + +/* If one hasn't been provided yet, then just stub it */ +#if defined(NEED_THREAD_PRIORITY) +t_stat sim_os_set_thread_priority (int below_normal_above) +{ +return SCPE_OK; +} #endif /* diff = min - sub */ diff --git a/sim_timer.h b/sim_timer.h index 1dc28a30..9b4548de 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -136,6 +136,10 @@ t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval); t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 interval); double sim_timer_inst_per_sec (void); t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms); +#define PRIORITY_BELOW_NORMAL -1 +#define PRIORITY_NORMAL 0 +#define PRIORITY_ABOVE_NORMAL 1 +t_stat sim_os_set_thread_priority (int below_normal_above); extern t_bool sim_idle_enab; /* idle enabled flag */ extern volatile t_bool sim_idle_wait; /* idle waiting flag */ diff --git a/sim_tmxr.c b/sim_tmxr.c index 75874755..8eb4fa03 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -2960,8 +2960,6 @@ t_bool sim_tmxr_poll_running = FALSE; static void * _tmxr_poll(void *arg) { -int sched_policy; -struct sched_param sched_priority; struct timeval timeout; int timeout_usec; DEVICE *dptr = tmxr_open_devices[0]->dptr; @@ -2973,9 +2971,7 @@ int wait_count = 0; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - starting\n"); @@ -3180,8 +3176,6 @@ return NULL; static void * _tmxr_serial_poll(void *arg) { -int sched_policy; -struct sched_param sched_priority; int timeout_usec; DEVICE *dptr = tmxr_open_devices[0]->dptr; UNIT **units = NULL; @@ -3192,9 +3186,7 @@ int wait_count = 0; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - starting\n"); @@ -3316,8 +3308,6 @@ static void * _tmxr_serial_line_poll(void *arg) { TMLN *lp = (TMLN *)arg; -int sched_policy; -struct sched_param sched_priority; DEVICE *dptr = tmxr_open_devices[0]->dptr; UNIT *uptr = (lp->uptr ? lp->uptr : lp->mp->uptr); DEVICE *d = find_dev_from_unit(uptr); @@ -3326,9 +3316,7 @@ int wait_count = 0; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_line_poll() - starting\n"); @@ -3398,8 +3386,6 @@ return NULL; static void * _tmxr_serial_poll(void *arg) { -int sched_policy; -struct sched_param sched_priority; int timeout_usec; DEVICE *dptr = tmxr_open_devices[0]->dptr; TMLN **lines = NULL; @@ -3408,9 +3394,6 @@ pthread_t *threads = NULL; /* Boost Priority for this I/O thread vs the CPU instruction execution thread which, in general, won't be readily yielding the processor when this thread needs to run */ -pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); -++sched_priority.sched_priority; -pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - starting\n"); diff --git a/sim_video.c b/sim_video.c index cb431677..99d6b190 100644 --- a/sim_video.c +++ b/sim_video.c @@ -419,6 +419,8 @@ SDL_Init (SDL_INIT_VIDEO); vid_main_thread_handle = SDL_CreateThread (main_thread , "simh-main", NULL); #endif +sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); + vid_beep_setup (400, 660); while (1) {