diff --git a/makefile b/makefile index 1fc9737..a48a3f3 100644 --- a/makefile +++ b/makefile @@ -182,7 +182,7 @@ ifneq ($(findstring Windows,${OS}),) endif find_exe = $(abspath $(strip $(firstword $(foreach dir,$(strip $(subst :, ,${PATH})),$(wildcard $(dir)/$(1)))))) -find_lib = $(abspath $(strip $(firstword $(foreach dir,$(strip ${LIBPATH}),$(wildcard $(dir)/lib$(1).${LIBEXT}))))) +find_lib = $(firstword $(abspath $(strip $(firstword $(foreach dir,$(strip ${LIBPATH}),$(foreach ext,$(strip ${LIBEXT}),$(wildcard $(dir)/lib$(1).$(ext)))))))) find_include = $(abspath $(strip $(firstword $(foreach dir,$(strip ${INCPATH}),$(wildcard $(dir)/$(1).h))))) ifneq (0,$(TESTS)) find_test = RegisterSanityCheck $(abspath $(wildcard $(1)/tests/$(2)_test.ini)) /' | sed 's/^.* => //'),$(dir $(lib)))) endif endif - LIBEXT = so + LIBSOEXT = so + LIBEXT = $(LIBSOEXT) a else ifeq (SunOS,$(OSTYPE)) OSNAME = Solaris @@ -441,7 +442,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) else ifeq (,$(strip $(LPATH))) $(info *** Warning ***) - $(info *** Warning *** The library search path on your $(OSTYPE) platform can't be) + $(info *** Warning *** The library search path on your $(OSTYPE) platform can not be) $(info *** Warning *** determined. This should be resolved before you can expect) $(info *** Warning *** to have fully working simulators.) $(info *** Warning ***) @@ -486,6 +487,9 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) endif endif endif + ifeq (,$(LIBSOEXT)) + LIBSOEXT = $(LIBEXT) + endif ifeq (,$(filter /lib/,$(LIBPATH))) ifeq (existlib,$(shell if $(TEST) -d /lib/; then echo existlib; fi)) LIBPATH += /lib/ @@ -496,6 +500,8 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) LIBPATH += /usr/lib/ endif endif + export CPATH = $(subst $() $(),:,$(INCPATH)) + export LIBRARY_PATH = $(subst $() $(),:,$(LIBPATH)) # Some gcc versions don't support LTO, so only use LTO when the compiler is known to support it ifeq (,$(NO_LTO)) ifneq (,$(GCC_VERSION)) @@ -575,7 +581,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) endif ifneq (,$(call find_include,dlfcn)) ifneq (,$(call find_lib,dl)) - OS_CCDEFS += -DHAVE_DLOPEN=${LIBEXT} + OS_CCDEFS += -DHAVE_DLOPEN=$(LIBSOEXT) OS_LDFLAGS += -ldl $(info using libdl: $(call find_lib,dl) $(call find_include,dlfcn)) else @@ -584,7 +590,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) $(info using libdl: $(call find_include,dlfcn)) else ifneq (,$(call find_lib,dld)) - OS_CCDEFS += -DHAVE_DLOPEN=${LIBEXT} + OS_CCDEFS += -DHAVE_DLOPEN=$(LIBSOEXT) OS_LDFLAGS += -ldld $(info using libdld: $(call find_lib,dld) $(call find_include,dlfcn)) else @@ -1047,8 +1053,8 @@ else $(info ***********************************************************************) $(info ***********************************************************************) $(info ** This build could produce simulators with video capabilities. **) - $(info ** However, the required files to achieve this can't be found on **) - $(info ** this system. Download the file: **) + $(info ** However, the required files to achieve this can not be found on **) + $(info ** on this system. Download the file: **) $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) $(info ** Extract the windows-build-windows-build folder it contains to **) $(info ** $(abspath ..\) **) diff --git a/scp.c b/scp.c index 37cbcdc..ffd69ad 100644 --- a/scp.c +++ b/scp.c @@ -7145,7 +7145,8 @@ if (strcmp (ctx->LastDir, directory)) { strcpy (ctx->LastDir, directory); } local = localtime (&filestat->st_mtime); -sim_printf ("%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM"); +if (local) + sim_printf ("%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM"); if (filestat->st_mode & S_IFDIR) { ++ctx->DirCount; ++ctx->TotalDirs; diff --git a/sim_disk.c b/sim_disk.c index a61d1b8..57214ae 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -2255,6 +2255,7 @@ static t_stat store_disk_footer (UNIT *uptr, const char *dtype) { DEVICE *dptr; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +struct stat statb; struct simh_disk_footer *f; time_t now = time (NULL); t_offset total_sectors; @@ -2263,6 +2264,7 @@ if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; if (uptr->flags & UNIT_RO) return SCPE_RO; +sim_stat (uptr->filename, &statb); f = (struct simh_disk_footer *)calloc (1, sizeof (*f)); f->AccessFormat = DK_GET_FMT (uptr); total_sectors = (((t_offset)uptr->capac) * ctx->capac_factor * ((dptr->flags & DEV_SECTORS) ? 512 : 1)) / ctx->sector_size; @@ -2284,13 +2286,18 @@ switch (f->AccessFormat) { case DKUF_F_STD: /* SIMH format */ if (sim_fseeko ((FILE *)uptr->fileref, total_sectors * ctx->sector_size, SEEK_SET) == 0) { sim_fwrite (f, sizeof (*f), 1, (FILE *)uptr->fileref); - fflush ((FILE *)uptr->fileref); + fclose ((FILE *)uptr->fileref); + sim_set_file_times (uptr->filename, statb.st_atime, statb.st_mtime); + uptr->fileref = sim_fopen (uptr->filename, "rb+"); } break; case DKUF_F_VHD: /* VHD format */ break; case DKUF_F_RAW: /* Raw Physical Disk Access */ sim_os_disk_write (uptr, total_sectors * ctx->sector_size, (uint8 *)f, NULL, sizeof (*f)); + sim_os_disk_close_raw (uptr->fileref); + sim_set_file_times (uptr->filename, statb.st_atime, statb.st_mtime); + uptr->fileref = sim_os_disk_open_raw (uptr->filename, "rb+"); break; default: break; @@ -2868,19 +2875,30 @@ if (container_size && (container_size != (t_offset)-1)) { sim_messagef (SCPE_OK, "%s: No File System found on '%s', skipping autosizing\n", sim_uname (uptr), cptr); } } - if ((container_size != current_unit_size) && - ((DKUF_F_VHD == DK_GET_FMT (uptr)) || (0 != (uptr->flags & UNIT_RO)) || - (ctx->footer))) { + if (filesystem_size != (t_offset)-1) { + if (filesystem_size > current_unit_size) { + if (!sim_quiet) { + uptr->capac = (t_addr)(filesystem_size/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); + sim_printf ("%s: The file system on the %s disk container is larger than simulated device (%s > ", sim_uname (uptr), cptr, sprint_capac (dptr, uptr)); + uptr->capac = saved_capac; + sim_printf ("%s)\n", sprint_capac (dptr, uptr)); + } + sim_disk_detach (uptr); + return SCPE_FSSIZE; + } + } + if ((container_size != current_unit_size)) { + if ((DKUF_F_VHD == DK_GET_FMT (uptr)) && + (0 == (uptr->flags & UNIT_RO))) { if (!sim_quiet) { int32 saved_switches = sim_switches; const char *container_dtype = ctx->footer ? (const char *)ctx->footer->DriveType : ""; sim_switches = SWMASK ('R'); uptr->capac = (t_addr)(container_size/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); - sim_printf ("%s: non expandable %s%sdisk container '%s' is %s than simulated device (%s %s ", + sim_printf ("%s: non expandable %s%sdisk container '%s' is smaller than simulated device (%s < ", sim_uname (uptr), container_dtype, (*container_dtype != '\0') ? " " : "", cptr, - (container_size < current_unit_size) ? "smaller" : "larger", sprint_capac (dptr, uptr), - (container_size < current_unit_size) ? "<" : ">"); + sprint_capac (dptr, uptr)); uptr->capac = saved_capac; sim_printf ("%s)\n", sprint_capac (dptr, uptr)); sim_switches = saved_switches; @@ -2889,6 +2907,7 @@ if (container_size && (container_size != (t_offset)-1)) { return SCPE_OPENERR; } } + } else { /* Autosize by changing capacity */ if (filesystem_size != (t_offset)-1) { /* Known file system data size AND */ if (filesystem_size > container_size) /* Data size greater than container size? */ @@ -6052,13 +6071,18 @@ t_offset container_size; sprintf (FullPath, "%s%s", directory, filename); if (info->flag) { /* zap type */ + struct stat statb; container = sim_vhd_disk_open (FullPath, "r"); if (container != NULL) { sim_vhd_disk_close (container); info->stat = sim_messagef (SCPE_OPENERR, "Cannot change the disk type of a VHD container file\n"); return; } - container = sim_fopen (FullPath, "r+"); + if (sim_stat (FullPath, &statb)) { + info->stat = sim_messagef (SCPE_OPENERR, "Cannot stat file: '%s' - %s\n", FullPath, strerror (errno)); + return; + } + container = sim_fopen (FullPath, "rb+"); if (container == NULL) { info->stat = sim_messagef (SCPE_OPENERR, "Cannot open container file '%s' - %s\n", FullPath, strerror (errno)); return; @@ -6077,7 +6101,7 @@ if (info->flag) { /* zap type */ zero_sector = (uint8 *)calloc (sector_size, sizeof (*sector_data)); /* Chop off the disk footer and trailing zero sectors */ container_size -= sizeof (*f); - while (container_size > 0) { + while ((sim_switches & SWMASK ('Z')) && (container_size > 0)) { if ((sim_fseeko (container, container_size - sector_size, SEEK_SET) != 0) || (sector_size != sim_fread (sector_data, 1, sector_size, container)) || (0 != memcmp (sector_data, zero_sector, sector_size))) @@ -6088,6 +6112,7 @@ if (info->flag) { /* zap type */ free (zero_sector); (void)sim_set_fsize (container, (t_addr)container_size); fclose (container); + sim_set_file_times (FullPath, statb.st_atime, statb.st_mtime); info->stat = sim_messagef (SCPE_OK, "Disk Type Removed from container '%s'\n", FullPath); return; } @@ -6114,7 +6139,7 @@ if (info->flag == 0) { container = sim_vhd_disk_open (FullPath, "r"); if (container == NULL) { sim_disk_set_fmt (uptr, 0, "SIMH", NULL); - container = sim_fopen (FullPath, "r+"); + container = sim_fopen (FullPath, "rb+"); close_function = fclose; size_function = sim_fsize_ex; } diff --git a/sim_fio.c b/sim_fio.c index e27d26c..bf492c1 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -508,6 +508,40 @@ if (CopyFileA (sourcename, destname, !overwrite_existing)) return sim_messagef (SCPE_ARG, "Error Copying '%s' to '%s': %s\n", source_file, dest_file, sim_get_os_error_text (GetLastError ())); } +static void _time_t_to_filetime (time_t ttime, FILETIME *filetime) +{ +t_uint64 time64; + +time64 = 134774; /* Days betwen Jan 1, 1601 and Jan 1, 1970 */ +time64 *= 24; /* Hours */ +time64 *= 3600; /* Seconds */ +time64 += (t_uint64)ttime; /* include time_t seconds */ + +time64 *= 10000000; /* Convert seconds to 100ns units */ +filetime->dwLowDateTime = (DWORD)time64; +filetime->dwHighDateTime = (DWORD)(time64 >> 32); +} + +t_stat sim_set_file_times (const char *file_name, time_t access_time, time_t write_time) +{ +char filename[PATH_MAX + 1]; +FILETIME accesstime, writetime; +HANDLE hFile; +BOOL bStat; + +_time_t_to_filetime (access_time, &accesstime); +_time_t_to_filetime (write_time, &writetime); +if (NULL == _sim_expand_homedir (file_name, filename, sizeof (filename))) + return sim_messagef (SCPE_ARG, "Error Setting File Times - Problem Source Filename '%s'\n", filename); +hFile = CreateFileA (filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +if (hFile == INVALID_HANDLE_VALUE) + return sim_messagef (SCPE_ARG, "Can't open file '%s' to set it's times: %s\n", filename, sim_get_os_error_text (GetLastError ())); +bStat = SetFileTime (hFile, NULL, &accesstime, &writetime); +CloseHandle (hFile); +return bStat ? SCPE_OK : sim_messagef (SCPE_ARG, "Error setting file '%s' times: %s\n", filename, sim_get_os_error_text (GetLastError ())); +} + + #include #include int sim_set_fsize (FILE *fptr, t_addr size) @@ -611,7 +645,7 @@ return ftruncate(fileno(fptr), (off_t)size); #include #include -#if HAVE_UTIME +#if defined (HAVE_UTIME) #include #endif @@ -666,6 +700,22 @@ if (st == SCPE_OK) { return st; } +t_stat sim_set_file_times (const char *file_name, time_t access_time, time_t write_time) +{ +t_stat st = SCPE_IOERR; +#if defined (HAVE_UTIME) +struct utimbuf utim; + +utim.actime = access_time; +utim.modtime = write_time; +if (!utime (file_name, &utim)) + st = SCPE_OK; +#else +st = SCPE_NOFNC; +#endif +return st; +} + int sim_set_fifo_nonblock (FILE *fptr) { struct stat stbuf; @@ -682,7 +732,10 @@ return -1; } #if defined (__linux__) || defined (__APPLE__) || defined (__CYGWIN__) || defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) + +#if defined (HAVE_SHM_OPEN) #include +#endif struct SHMEM { int shm_fd; @@ -751,7 +804,7 @@ if ((*shmem)->shm_base == MAP_FAILED) { return SCPE_OK; #else *shmem = NULL; -return SCPE_NOFNC; +return sim_messagef (SCPE_NOFNC, "Shared memory not available - Missing shm_open() API\n"); #endif } diff --git a/sim_fio.h b/sim_fio.h index b7ef07b..bd099d6 100644 --- a/sim_fio.h +++ b/sim_fio.h @@ -64,6 +64,7 @@ int sim_fseek (FILE *st, t_addr offset, int whence); int sim_fseeko (FILE *st, t_offset offset, int whence); t_bool sim_can_seek (FILE *st); int sim_set_fsize (FILE *fptr, t_addr size); +t_stat sim_set_file_times (const char *file_name, time_t access_time, time_t write_time); int sim_set_fifo_nonblock (FILE *fptr); size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr); size_t sim_fwrite (const void *bptr, size_t size, size_t count, FILE *fptr); diff --git a/sim_timer.c b/sim_timer.c index 38a2def..dc46d90 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -1994,16 +1994,33 @@ switch (sim_throt_state) { d_cps = (double) sim_throt_val * 1000.0; else d_cps = (sim_throt_peak_cps * sim_throt_val) / 100.0; - if (d_cps > a_cps) { + if (d_cps >= a_cps) { + /* the initial throttling calibration measures a slower cps rate than the desired cps rate, */ sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() CPU too slow. Values a_cps = %f, d_cps = %f\n", a_cps, d_cps); - sim_throt_state = SIM_THROT_STATE_INIT; - sim_printf ("*********** WARNING ***********\n"); - sim_printf ("Host CPU is too slow to simulate %s %s per second\n", sim_fmt_numeric(d_cps), sim_vm_interval_units); - sim_printf ("Host CPU can only simulate %s %s per second\n", sim_fmt_numeric(sim_throt_peak_cps), sim_vm_interval_units); - sim_printf ("Throttling disabled.\n"); - sim_set_throt (0, NULL); - return SCPE_OK; + /* if the measured rate is well below the measured peak rate? */ + if (sim_throt_peak_cps >= (2.0 * d_cps)) { + /* distrust the measured rate and instead use half the peak rate as measured + cps rate. */ + sim_printf ("*********** WARNING ***********\n"); + sim_printf ("Host CPU could be too slow to simulate %s %s per second\n", sim_fmt_numeric(d_cps), sim_vm_interval_units); + sim_printf ("Host CPU did only simulate %s %s per second\n", sim_fmt_numeric(a_cps), sim_vm_interval_units); + sim_printf ("But peak rate was: %s %s per second\n", sim_fmt_numeric(sim_throt_peak_cps), sim_vm_interval_units); + + a_cps = (sim_throt_peak_cps / 2.0) + 1.0; + + sim_printf ("Assuming rate: %s %s per second\n", sim_fmt_numeric(a_cps), sim_vm_interval_units); + } + else { + sim_throt_state = SIM_THROT_STATE_INIT; + sim_printf ("*********** WARNING ***********\n"); + sim_printf ("Host CPU is too slow to simulate %s %s per second\n", sim_fmt_numeric(d_cps), sim_vm_interval_units); + sim_printf ("Host CPU did only simulate %s %s per second\n", sim_fmt_numeric(a_cps), sim_vm_interval_units); + sim_printf ("Peak rate: %s %s per second\n", sim_fmt_numeric(sim_throt_peak_cps), sim_vm_interval_units); + sim_printf ("Throttling disabled.\n"); + sim_set_throt (0, NULL); + return SCPE_OK; + } } while (1) { sim_throt_wait = (int32) /* cycles between sleeps */