summaryrefslogtreecommitdiffstats
path: root/win/tclWin32Dll.c
diff options
context:
space:
mode:
authorKevin B Kenny <kennykb@acm.org>2004-06-05 17:25:39 (GMT)
committerKevin B Kenny <kennykb@acm.org>2004-06-05 17:25:39 (GMT)
commita1a9fa86902eae4d02cbe6b9415a3bc8e0609277 (patch)
tree617dc620eece18a088428f04a8adc51bba840ae6 /win/tclWin32Dll.c
parent82bd902b0af8b51295647f43a1610ca1f37ae613 (diff)
downloadtcl-a1a9fa86902eae4d02cbe6b9415a3bc8e0609277.zip
tcl-a1a9fa86902eae4d02cbe6b9415a3bc8e0609277.tar.gz
tcl-a1a9fa86902eae4d02cbe6b9415a3bc8e0609277.tar.bz2
* generic/tcl.h: Corrected Tcl_WideInt declarations so that the mingw
build works again. * generic/tclInt.decls: Changes to the tests for * generic/tclIntPlatDecls.h: clock frequency in Tcl_WinTime * generic/tclStubInit.c: so that any clock frequency * tests/platform.test (platform-1.3): is accepted provided that * win/tclWin32Dll.c (TclWinCPUID): all CPU's in the system share * win/tclWinTest.c (TestwincpuidCmd): a common chip, and hence, * win/tclWinTime.c (Tcl_GetTime): presumably, a common clock. This change necessitated a small burst of assembly code to read CPU ID information, which was added as TclWinCPUID in the internal Stubs. To test this code in the common case of a single-processor machine, a 'testwincpuid' command was added to tclWinTest.c, and a test case in platform.test. Thanks to Jeff Godfrey and Richard Suchenwirth for reporting this bug. [Bug #976722]
Diffstat (limited to 'win/tclWin32Dll.c')
-rw-r--r--win/tclWin32Dll.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index 2e3368c..4cfd944 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.2 2004/05/06 01:04:32 davygrvy Exp $
+ * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.3 2004/06/05 17:25:40 kennykb Exp $
*/
#include "tclWinInt.h"
@@ -946,3 +946,152 @@ Tcl_WinTCharToUtf(string, len, dsPtr)
return Tcl_ExternalToUtfDString(tclWinTCharEncoding,
(CONST char *) string, len, dsPtr);
}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * TclWinCPUID --
+ *
+ * Get CPU ID information on an Intel box under Windows
+ *
+ * Results:
+ * Returns TCL_OK if successful, TCL_ERROR if CPUID is not
+ * supported or fails.
+ *
+ * Side effects:
+ * If successful, stores EAX, EBX, ECX and EDX registers after
+ * the CPUID instruction in the four integers designated by 'regsPtr'
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve */
+ register unsigned int * regsPtr ) /* Registers after the CPUID */
+{
+
+ int status = TCL_ERROR;
+
+#if defined(__GNUC__)
+
+ /* Establish structured exception handling */
+
+# ifdef HAVE_NO_SEH
+ __asm__ __volatile__ (
+ "pushl %ebp" "\n\t"
+ "pushl $__except_TclWinCPUID_detach_handler" "\n\t"
+ "pushl %fs:0" "\n\t"
+ "movl %esp, %fs:0" );
+# else
+ __try {
+# endif
+
+ /*
+ * Execute the CPUID instruction with the given index, and
+ * store results off 'regPtr'.
+ */
+
+ __asm__ __volatile__ (
+ "movl %4, %%eax" "\n\t"
+ "cpuid" "\n\t"
+ "movl %%eax, %0" "\n\t"
+ "movl %%ebx, %1" "\n\t"
+ "movl %%ecx, %2" "\n\t"
+ "movl %%edx, %3"
+ :
+ "=m"(regsPtr[0]),
+ "=m"(regsPtr[1]),
+ "=m"(regsPtr[2]),
+ "=m"(regsPtr[3])
+ : "m"(index)
+ : "%eax", "%ebx", "%ecx", "%edx" );
+ status = TCL_OK;
+
+ /* End the structured exception handler */
+
+# ifndef HAVE_NO_SEH
+ } __except( EXCEPTION_EXECUTE_HANDLER ) {
+ /* do nothing */
+ }
+# else
+ __asm __volatile__ (
+ "jmp TclWinCPUID_detach_pop" "\n"
+ "TclWinCPUID_detach_reentry:" "\n\t"
+ "movl %%fs:0, %%eax" "\n\t"
+ "movl 0x8(%%eax), %%esp" "\n\t"
+ "movl 0x8(%%esp), %%ebp" "\n"
+ "TclWinCPUID_detach_pop:" "\n\t"
+ "movl (%%esp), %%eax" "\n\t"
+ "movl %%eax, %%fs:0" "\n\t"
+ "add $12, %%esp" "\n\t"
+ :
+ :
+ : "%eax");
+# endif
+
+
+#elif defined(_MSC_VER)
+
+ /* Define a structure in the stack frame to hold the registers */
+
+ struct {
+ DWORD dw0;
+ DWORD dw1;
+ DWORD dw2;
+ DWORD dw3;
+ } regs;
+ regs.dw0 = index;
+
+ /* Execute the CPUID instruction and save regs in the stack frame */
+
+ _try {
+ _asm {
+ push ebx
+ push ecx
+ push edx
+ mov eax, regs.dw0
+ cpuid
+ mov regs.dw0, eax
+ mov regs.dw1, ebx
+ mov regs.dw2, ecx
+ mov regs.dw3, edx
+ pop edx
+ pop ecx
+ pop ebx
+ }
+
+ /* Copy regs back out to the caller */
+
+ regsPtr[0]=regs.dw0;
+ regsPtr[1]=regs.dw1;
+ regsPtr[2]=regs.dw2;
+ regsPtr[3]=regs.dw3;
+
+ status = TCL_OK;
+ } __except( EXCEPTION_EXECUTE_HANDLER ) {
+ }
+
+#else
+ /* Don't know how to do assembly code for
+ * this compiler */
+#endif
+ return status;
+}
+
+#if defined( __GNUC__ ) && defined( HAVE_NO_SEH )
+static __attribute__((cdecl)) EXCEPTION_DISPOSITION
+_except_TclWinCPUID_detach_handler(
+ struct _EXCEPTION_RECORD *ExceptionRecord,
+ void *EstablisherFrame,
+ struct _CONTEXT *ContextRecord,
+ void *DispatcherContext)
+{
+ __asm__ __volatile__ (
+ "jmp TclWinCPUID_detach_reentry" );
+ /* Nuke compiler warning about unused static function */
+ _except_TclWinCPUID_detach_handler(NULL, NULL, NULL, NULL);
+ return 0; /* Function does not return */
+}
+#endif
+
+