diff options
author | Kevin B Kenny <kennykb@acm.org> | 2004-06-05 17:25:39 (GMT) |
---|---|---|
committer | Kevin B Kenny <kennykb@acm.org> | 2004-06-05 17:25:39 (GMT) |
commit | a1a9fa86902eae4d02cbe6b9415a3bc8e0609277 (patch) | |
tree | 617dc620eece18a088428f04a8adc51bba840ae6 /win/tclWin32Dll.c | |
parent | 82bd902b0af8b51295647f43a1610ca1f37ae613 (diff) | |
download | tcl-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.c | 151 |
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 + + |