summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pr/include/private/primpl.h31
-rw-r--r--pr/src/md/unix/unix.c6
-rw-r--r--pr/src/md/windows/ntio.c11
-rw-r--r--pr/src/md/windows/ntmisc.c238
-rw-r--r--pr/src/md/windows/w95io.c11
-rw-r--r--pr/src/misc/prtime.c3
6 files changed, 266 insertions, 34 deletions
diff --git a/pr/include/private/primpl.h b/pr/include/private/primpl.h
index a742711f..c0f4a3ab 100644
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -54,17 +54,19 @@
#include <kernel/OS.h>
#endif
-#ifdef WINNT
-/* Need to force service-pack 3 extensions to be defined by
-** setting _WIN32_WINNT to NT 4.0 for winsock.h, winbase.h, winnt.h.
-*/
-#ifndef _WIN32_WINNT
- #define _WIN32_WINNT 0x0400
-#elif (_WIN32_WINNT < 0x0400)
- #undef _WIN32_WINNT
- #define _WIN32_WINNT 0x0400
-#endif /* _WIN32_WINNT */
-#endif /* WINNT */
+#ifdef WIN32
+/*
+ * Allow use of functions and symbols first defined in Win2k.
+ */
+#if !defined(WINVER) || (WINVER < 0x0500)
+#undef WINVER
+#define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#endif /* WIN32 */
#include "nspr.h"
#include "prpriv.h"
@@ -1215,6 +1217,13 @@ extern PRInt32 _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PROsfd *newSock,
extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PROsfd s, PROsfd ls);
#define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT
+/*
+ * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
+ * We store the value in a PRTime variable for convenience.
+ * This constant is used by _PR_FileTimeToPRTime().
+ * This is defined in ntmisc.c
+ */
+extern const PRTime _pr_filetime_offset;
#endif /* WIN32 */
extern PRInt32 _PR_MD_SENDFILE(
diff --git a/pr/src/md/unix/unix.c b/pr/src/md/unix/unix.c
index 35048b9c..e7405dbe 100644
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -78,7 +78,7 @@
#define _PRSockLen_t int
#elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \
|| defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \
- || defined(DGUX) || defined(VMS) || defined(NTO) || defined(RISCOS)
+ || defined(DGUX) || defined(NTO) || defined(RISCOS)
#define _PRSockLen_t size_t
#else
#error "Cannot determine architecture"
@@ -2649,7 +2649,11 @@ PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info)
return rv;
}
+#ifdef SYMBIAN
struct _MD_IOVector _md_iovector;
+#else
+struct _MD_IOVector _md_iovector = { open };
+#endif
/*
** These implementations are to emulate large file routines on systems that
diff --git a/pr/src/md/windows/ntio.c b/pr/src/md/windows/ntio.c
index e2d28a09..5fecc537 100644
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -100,17 +100,6 @@ static DWORD dirAccessTable[] = {
FILE_GENERIC_EXECUTE
};
-/*
- * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
- * We store the value in a PRTime variable for convenience.
- * This constant is used by _PR_FileTimeToPRTime().
- */
-#ifdef __GNUC__
-static const PRTime _pr_filetime_offset = 116444736000000000LL;
-#else
-static const PRTime _pr_filetime_offset = 116444736000000000i64;
-#endif
-
static PRBool IsPrevCharSlash(const char *str, const char *current);
#define _NEED_351_FILE_LOCKING_HACK
diff --git a/pr/src/md/windows/ntmisc.c b/pr/src/md/windows/ntmisc.c
index a62720cf..289c19bb 100644
--- a/pr/src/md/windows/ntmisc.c
+++ b/pr/src/md/windows/ntmisc.c
@@ -41,6 +41,8 @@
*/
#include "primpl.h"
+#include <math.h> /* for fabs() */
+#include <windows.h>
char *_PR_MD_GET_ENV(const char *name)
{
@@ -69,6 +71,116 @@ PRIntn _PR_MD_PUT_ENV(const char *name)
*/
/*
+ * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
+ * We store the value in a PRTime variable for convenience.
+ */
+#ifdef __GNUC__
+const PRTime _pr_filetime_offset = 116444736000000000LL;
+#else
+const PRTime _pr_filetime_offset = 116444736000000000i64;
+#endif
+
+#ifdef WINCE
+
+#define FILETIME2INT64(ft) \
+ (((PRInt64)ft.dwHighDateTime) << 32 | (PRInt64)ft.dwLowDateTime)
+
+static void
+LowResTime(LPFILETIME lpft)
+{
+ GetCurrentFT(lpft);
+}
+
+typedef struct CalibrationData {
+ long double freq; /* The performance counter frequency */
+ long double offset; /* The low res 'epoch' */
+ long double timer_offset; /* The high res 'epoch' */
+
+ /* The last high res time that we returned since recalibrating */
+ PRInt64 last;
+
+ PRBool calibrated;
+
+ CRITICAL_SECTION data_lock;
+ CRITICAL_SECTION calibration_lock;
+ PRInt64 granularity;
+} CalibrationData;
+
+static CalibrationData calibration;
+
+static void
+NowCalibrate(void)
+{
+ FILETIME ft, ftStart;
+ LARGE_INTEGER liFreq, now;
+
+ if (calibration.freq == 0.0) {
+ if(!QueryPerformanceFrequency(&liFreq)) {
+ /* High-performance timer is unavailable */
+ calibration.freq = -1.0;
+ } else {
+ calibration.freq = (long double) liFreq.QuadPart;
+ }
+ }
+ if (calibration.freq > 0.0) {
+ PRInt64 calibrationDelta = 0;
+ /*
+ * By wrapping a timeBegin/EndPeriod pair of calls around this loop,
+ * the loop seems to take much less time (1 ms vs 15ms) on Vista.
+ */
+ timeBeginPeriod(1);
+ LowResTime(&ftStart);
+ do {
+ LowResTime(&ft);
+ } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
+ timeEndPeriod(1);
+
+ calibration.granularity =
+ (FILETIME2INT64(ft) - FILETIME2INT64(ftStart))/10;
+
+ QueryPerformanceCounter(&now);
+
+ calibration.offset = (long double) FILETIME2INT64(ft);
+ calibration.timer_offset = (long double) now.QuadPart;
+ /*
+ * The windows epoch is around 1600. The unix epoch is around 1970.
+ * _pr_filetime_offset is the difference (in windows time units which
+ * are 10 times more highres than the JS time unit)
+ */
+ calibration.offset -= _pr_filetime_offset;
+ calibration.offset *= 0.1;
+ calibration.last = 0;
+
+ calibration.calibrated = PR_TRUE;
+ }
+}
+
+#define CALIBRATIONLOCK_SPINCOUNT 0
+#define DATALOCK_SPINCOUNT 4096
+#define LASTLOCK_SPINCOUNT 4096
+
+static PRStatus
+_MD_InitTime(void)
+{
+ memset(&calibration, 0, sizeof(calibration));
+ NowCalibrate();
+ InitializeCriticalSection(&calibration.calibration_lock);
+ InitializeCriticalSection(&calibration.data_lock);
+ return PR_SUCCESS;
+}
+
+void
+_MD_CleanupTime(void)
+{
+ DeleteCriticalSection(&calibration.calibration_lock);
+ DeleteCriticalSection(&calibration.data_lock);
+}
+
+#define MUTEX_SETSPINCOUNT(m, c)
+
+static PRCallOnceType calibrationOnce;
+
+/*
*-----------------------------------------------------------------------
*
* PR_Now --
@@ -85,6 +197,130 @@ PRIntn _PR_MD_PUT_ENV(const char *name)
PR_IMPLEMENT(PRTime)
PR_Now(void)
{
+ long double lowresTime, highresTimerValue;
+ FILETIME ft;
+ LARGE_INTEGER now;
+ PRBool calibrated = PR_FALSE;
+ PRBool needsCalibration = PR_FALSE;
+ PRInt64 returnedTime;
+ long double cachedOffset = 0.0;
+
+ /* For non threadsafe platforms, _MD_InitTime is not necessary */
+ PR_CallOnce(&calibrationOnce, _MD_InitTime);
+ do {
+ if (!calibration.calibrated || needsCalibration) {
+ EnterCriticalSection(&calibration.calibration_lock);
+ EnterCriticalSection(&calibration.data_lock);
+
+ /* Recalibrate only if no one else did before us */
+ if (calibration.offset == cachedOffset) {
+ /*
+ * Since calibration can take a while, make any other
+ * threads immediately wait
+ */
+ MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
+
+ NowCalibrate();
+
+ calibrated = PR_TRUE;
+
+ /* Restore spin count */
+ MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
+ }
+ LeaveCriticalSection(&calibration.data_lock);
+ LeaveCriticalSection(&calibration.calibration_lock);
+ }
+
+ /* Calculate a low resolution time */
+ LowResTime(&ft);
+ lowresTime = ((long double)(FILETIME2INT64(ft) - _pr_filetime_offset))
+ * 0.1;
+
+ if (calibration.freq > 0.0) {
+ long double highresTime, diff;
+ DWORD timeAdjustment, timeIncrement;
+ BOOL timeAdjustmentDisabled;
+
+ /* Default to 15.625 ms if the syscall fails */
+ long double skewThreshold = 15625.25;
+
+ /* Grab high resolution time */
+ QueryPerformanceCounter(&now);
+ highresTimerValue = (long double)now.QuadPart;
+
+ EnterCriticalSection(&calibration.data_lock);
+ highresTime = calibration.offset + 1000000L *
+ (highresTimerValue-calibration.timer_offset)/calibration.freq;
+ cachedOffset = calibration.offset;
+
+ /*
+ * On some dual processor/core systems, we might get an earlier
+ * time so we cache the last time that we returned.
+ */
+ calibration.last = PR_MAX(calibration.last,(PRInt64)highresTime);
+ returnedTime = calibration.last;
+ LeaveCriticalSection(&calibration.data_lock);
+
+ /* Get an estimate of clock ticks per second from our own test */
+ skewThreshold = calibration.granularity;
+ /* Check for clock skew */
+ diff = lowresTime - highresTime;
+
+ /*
+ * For some reason that I have not determined, the skew can be
+ * up to twice a kernel tick. This does not seem to happen by
+ * itself, but I have only seen it triggered by another program
+ * doing some kind of file I/O. The symptoms are a negative diff
+ * followed by an equally large positive diff.
+ */
+ if (fabs(diff) > 2*skewThreshold) {
+ if (calibrated) {
+ /*
+ * If we already calibrated once this instance, and the
+ * clock is still skewed, then either the processor(s) are
+ * wildly changing clockspeed or the system is so busy that
+ * we get switched out for long periods of time. In either
+ * case, it would be infeasible to make use of high
+ * resolution results for anything, so let's resort to old
+ * behavior for this call. It's possible that in the
+ * future, the user will want the high resolution timer, so
+ * we don't disable it entirely.
+ */
+ returnedTime = (PRInt64)lowresTime;
+ needsCalibration = PR_FALSE;
+ } else {
+ /*
+ * It is possible that when we recalibrate, we will return
+ * a value less than what we have returned before; this is
+ * unavoidable. We cannot tell the different between a
+ * faulty QueryPerformanceCounter implementation and user
+ * changes to the operating system time. Since we must
+ * respect user changes to the operating system time, we
+ * cannot maintain the invariant that Date.now() never
+ * decreases; the old implementation has this behavior as
+ * well.
+ */
+ needsCalibration = PR_TRUE;
+ }
+ } else {
+ /* No detectable clock skew */
+ returnedTime = (PRInt64)highresTime;
+ needsCalibration = PR_FALSE;
+ }
+ } else {
+ /* No high resolution timer is available, so fall back */
+ returnedTime = (PRInt64)lowresTime;
+ }
+ } while (needsCalibration);
+
+ return returnedTime;
+}
+
+#else
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
PRTime prt;
FILETIME ft;
SYSTEMTIME st;
@@ -95,6 +331,8 @@ PR_Now(void)
return prt;
}
+#endif
+
/*
***********************************************************************
***********************************************************************
diff --git a/pr/src/md/windows/w95io.c b/pr/src/md/windows/w95io.c
index 0bc2cfce..f9b2cc43 100644
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -260,17 +260,6 @@ static DWORD dirAccessTable[] = {
FILE_GENERIC_EXECUTE
};
-/*
- * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
- * We store the value in a PRTime variable for convenience.
- * This constant is used by _PR_FileTimeToPRTime().
- */
-#if defined(__MINGW32__)
-static const PRTime _pr_filetime_offset = 116444736000000000LL;
-#else
-static const PRTime _pr_filetime_offset = 116444736000000000i64;
-#endif
-
/* Windows CE has GetFileAttributesEx. */
#ifndef WINCE
typedef BOOL (WINAPI *GetFileAttributesExFn)(LPCTSTR,
diff --git a/pr/src/misc/prtime.c b/pr/src/misc/prtime.c
index 2f2bbfde..9a3be28e 100644
--- a/pr/src/misc/prtime.c
+++ b/pr/src/misc/prtime.c
@@ -604,6 +604,9 @@ void _PR_CleanupTime(void)
monitor = NULL;
}
#endif
+#ifdef WINCE
+ _MD_CleanupTime();
+#endif
}
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)