www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [Warning] Fiber in tango.core.Thread still bug, dont use it in any scientific calculation

reply "Swer" <swer yoyocowo.com.nb> writes:
Any float point calculation in both main Fiber/slave Fiber will
cause uncertain result, unless your CPU is 386sx with FP emu clib.

This bug exsits on both Win32 and x86 Linux Tango lib. Please dont
use Fiber class unless you are sure there no any float point
calculation in you program and in ALL api/lib you imported.

Thread.d firber context switch bug, there is no FP register
save/restore. EBX ESI EDI EBP ESP IP FS only. this code is unsafe!

==========CUT from tango/core/Thread.d line:2369-2405=======
        version( AsmX86_Win32 )
        {
            asm
            {
                naked;

                // save current stack state
                push EBP;
                mov  EBP, ESP;
                push EAX;
                push dword ptr FS:[0];
                push dword ptr FS:[4];
                push dword ptr FS:[8];
                push EBX;
                push ESI;
                push EDI;

                // store oldp again with more accurate address
                mov EAX, dword ptr 8[EBP];
                mov [EAX], ESP;
                // load newp to begin context switch
                mov ESP, dword ptr 12[EBP];

                // load saved state from new stack
                pop EDI;
                pop ESI;
                pop EBX;
                pop dword ptr FS:[8];
                pop dword ptr FS:[4];
                pop dword ptr FS:[0];
                pop EAX;
                pop EBP;

                // 'return' to complete switch
                ret;
            }
        }
===============CUT END====================


GNU glibc2.7 swapcontext.S code is safe
===============CUT===================
ENTRY(__swapcontext)
 /* Load address of the context data structure we save in.  */
 movl 4(%esp), %eax

 /* Return value of swapcontext.  EAX is the only register whose
    value is not preserved.  */
 movl $0, oEAX(%eax)

 /* Save the 32-bit register values and the return address.  */
 movl %ecx, oECX(%eax)
 movl %edx, oEDX(%eax)
 movl %edi, oEDI(%eax)
 movl %esi, oESI(%eax)
 movl %ebp, oEBP(%eax)
 movl (%esp), %ecx
 movl %ecx, oEIP(%eax)
 leal 4(%esp), %ecx
 movl %ecx, oESP(%eax)
 movl %ebx, oEBX(%eax)

 /* Save the FS segment register.  */
 xorl %edx, %edx
 movw %fs, %dx
 movl %edx, oFS(%eax)

 /* We have separate floating-point register content memory on the
    stack.  We use the __fpregs_mem block in the context.  Set the
    links up correctly.  */
 leal oFPREGSMEM(%eax), %ecx
 movl %ecx, oFPREGS(%eax)
 /* Save the floating-point context.  */
 fnstenv (%ecx)

 /* Load address of the context data structure we have to load.  */
 movl 8(%esp), %ecx

 /* Save the current signal mask and install the new one.  */
 pushl %ebx
 leal oSIGMASK(%eax), %edx
 leal oSIGMASK(%ecx), %ecx
 movl $SIG_SETMASK, %ebx
 movl $__NR_sigprocmask, %eax
 ENTER_KERNEL
 popl %ebx
 cmpl $-4095, %eax  /* Check %eax for error.  */
 jae SYSCALL_ERROR_LABEL /* Jump to error handler if error.  */

 /* EAX was modified, reload it.  */
 movl 8(%esp), %eax

 /* Restore the floating-point context.  Not the registers, only the
    rest.  */
 movl oFPREGS(%eax), %ecx
 fldenv (%ecx)

 /* Restore the FS segment register.  We don't touch the GS register
    since it is used for threads.  */
 movl oFS(%eax), %edx
 movw %dx, %fs

 /* Fetch the address to return to.  */
 movl oEIP(%eax), %ecx

 /* Load the new stack pointer.  */
 movl oESP(%eax), %esp

 /* Push the return address on the new stack so we can return there.  */
 pushl %ecx

 /* Load the values of all the 32-bit registers (except ESP).
    Since we are loading from EAX, it must be last.  */
 movl oEDI(%eax), %edi
 movl oESI(%eax), %esi
 movl oEBP(%eax), %ebp
 movl oEBX(%eax), %ebx
 movl oEDX(%eax), %edx
 movl oECX(%eax), %ecx
 movl oEAX(%eax), %eax

 /* The following 'ret' will pop the address of the code and jump
    to it.  */

L(pseudo_end):
 ret
PSEUDO_END(__swapcontext)
=============CUT END=================


Microsoft Windows Server 2003 SwitchToFiber code also safe.
===========Kernel32.dll SwitchToFiber==============
7C821804 k>/$  64:8B15 18000000  mov edx,dword ptr fs:[18]
7C82180B   |.  8B42 10           mov eax,dword ptr ds:[edx+10]
7C82180E   |.  8998 B8000000     mov dword ptr ds:[eax+B8],ebx
7C821814   |.  89B8 B0000000     mov dword ptr ds:[eax+B0],edi
7C82181A   |.  89B0 B4000000     mov dword ptr ds:[eax+B4],esi
7C821820   |.  89A8 C8000000     mov dword ptr ds:[eax+C8],ebp
7C821826   |.  8178 14 0F000100  cmp dword ptr ds:[eax+14],1000F
7C82182D   |.  75 14             jnz short kernel32.7C821843
7C82182F   |.  9B                wait
7C821830   |.  DD78 34           fstsw word ptr ds:[eax+34]
7C821833   |.  D978 30           fstcw word ptr ds:[eax+30]
7C821836   |.  803D 7A02FE7F 01  cmp byte ptr ds:[7FFE027A],1
7C82183D   |.  75 04             jnz short kernel32.7C821843
7C82183F   |.  0FAE58 28         stmxcsr dword ptr ds:[eax+28]
7C821843   |>  89A0 D8000000     mov dword ptr ds:[eax+D8],esp
7C821849   |.  8B8A B40F0000     mov ecx,dword ptr ds:[edx+FB4]
7C82184F   |.  8988 E8020000     mov dword ptr ds:[eax+2E8],ecx
7C821855   |.  8B8A A8010000     mov ecx,dword ptr ds:[edx+1A8]
7C82185B   |.  8988 E4020000     mov dword ptr ds:[eax+2E4],ecx
7C821861   |.  8B0A              mov ecx,dword ptr ds:[edx]
7C821863   |.  8B5A 08           mov ebx,dword ptr ds:[edx+8]
7C821866   |.  8BB2 780F0000     mov esi,dword ptr ds:[edx+F78]
7C82186C   |.  8948 04           mov dword ptr ds:[eax+4],ecx
7C82186F   |.  8958 0C           mov dword ptr ds:[eax+C],ebx
7C821872   |.  89B0 EC020000     mov dword ptr ds:[eax+2EC],esi
7C821878   |.  8B4C24 04         mov ecx,dword ptr ss:[esp+4]
7C82187C   |.  894A 10           mov dword ptr ds:[edx+10],ecx
7C82187F   |.  8B71 04           mov esi,dword ptr ds:[ecx+4]
7C821882   |.  8B59 08           mov ebx,dword ptr ds:[ecx+8]
7C821885   |.  8932              mov dword ptr ds:[edx],esi
7C821887   |.  895A 04           mov dword ptr ds:[edx+4],ebx
7C82188A   |.  8B71 0C           mov esi,dword ptr ds:[ecx+C]
7C82188D   |.  8B59 10           mov ebx,dword ptr ds:[ecx+10]
7C821890   |.  8BB9 EC020000     mov edi,dword ptr ds:[ecx+2EC]
7C821896   |.  8972 08           mov dword ptr ds:[edx+8],esi
7C821899   |.  899A 0C0E0000     mov dword ptr ds:[edx+E0C],ebx
7C82189F   |.  89BA 780F0000     mov dword ptr ds:[edx+F78],edi
7C8218A5   |.  8BB1 E4020000     mov esi,dword ptr ds:[ecx+2E4]
7C8218AB   |.  89B2 A8010000     mov dword ptr ds:[edx+1A8],esi
7C8218B1   |.  8179 14 0F000100  cmp dword ptr ds:[ecx+14],1000F
7C8218B8   |.  75 28             jnz short kernel32.7C8218E2
7C8218BA   |.  8B58 34           mov ebx,dword ptr ds:[eax+34]
7C8218BD   |.  66:3B59 34        cmp bx,word ptr ds:[ecx+34]
7C8218C1   |.  75 09             jnz short kernel32.7C8218CC
7C8218C3   |.  8B58 30           mov ebx,dword ptr ds:[eax+30]
7C8218C6   |.  66:3B59 30        cmp bx,word ptr ds:[ecx+30]
7C8218CA   |.  74 09             je short kernel32.7C8218D5
7C8218CC   |>  66:C741 38 FFFF   mov word ptr ds:[ecx+38],0FFFF
7C8218D2   |.  D961 30           fldenv (28-byte) ptr ds:[ecx+30]
7C8218D5   |>  803D 7A02FE7F 01  cmp byte ptr ds:[7FFE027A],1
7C8218DC   |.  75 04             jnz short kernel32.7C8218E2
7C8218DE   |.  0FAE51 28         ldmxcsr dword ptr ds:[ecx+28]
7C8218E2   |>  8BB9 B0000000     mov edi,dword ptr ds:[ecx+B0]
7C8218E8   |.  8BB1 B4000000     mov esi,dword ptr ds:[ecx+B4]
7C8218EE   |.  8BA9 C8000000     mov ebp,dword ptr ds:[ecx+C8]
7C8218F4   |.  8B99 B8000000     mov ebx,dword ptr ds:[ecx+B8]
7C8218FA   |.  8B81 E8020000     mov eax,dword ptr ds:[ecx+2E8]
7C821900   |.  8982 B40F0000     mov dword ptr ds:[edx+FB4],eax
7C821906   |.  8BA1 D8000000     mov esp,dword ptr ds:[ecx+D8]
7C82190C   \.  C2 0400           retn 4
===============CUT END=====================

Hope this bug fix fast because tango is my standard lib.
Dec 07 2007
parent reply Mikola Lysenko <mclysenk mtu.edu> writes:
Have you tried testing this with any examples?  I'm fairly certain that the FPU
does actually do what it is supposed to.  If you will notice, the calling
convention on the method is extern(C), not extern(D).  As a result, the C
calling specification requires that the FPU state is saved before any function
call by the caller - not the callee.  As a result, this method should work and
moreover save a great deal of time.  Dumping the FPU state is a rather costly
operation, and best avoided if possible, which is why the C calling convention
works this way.

If you can find code that breaks with the current Tango fiber implementation,
I'd be happy to make the necessary changes.

-Mik


Swer Wrote:

 Any float point calculation in both main Fiber/slave Fiber will
 cause uncertain result, unless your CPU is 386sx with FP emu clib.
 
 This bug exsits on both Win32 and x86 Linux Tango lib. Please dont
 use Fiber class unless you are sure there no any float point
 calculation in you program and in ALL api/lib you imported.
 
 Thread.d firber context switch bug, there is no FP register
 save/restore. EBX ESI EDI EBP ESP IP FS only. this code is unsafe!
 
 ==========CUT from tango/core/Thread.d line:2369-2405=======
         version( AsmX86_Win32 )
         {
             asm
             {
                 naked;
 
                 // save current stack state
                 push EBP;
                 mov  EBP, ESP;
                 push EAX;
                 push dword ptr FS:[0];
                 push dword ptr FS:[4];
                 push dword ptr FS:[8];
                 push EBX;
                 push ESI;
                 push EDI;
 
                 // store oldp again with more accurate address
                 mov EAX, dword ptr 8[EBP];
                 mov [EAX], ESP;
                 // load newp to begin context switch
                 mov ESP, dword ptr 12[EBP];
 
                 // load saved state from new stack
                 pop EDI;
                 pop ESI;
                 pop EBX;
                 pop dword ptr FS:[8];
                 pop dword ptr FS:[4];
                 pop dword ptr FS:[0];
                 pop EAX;
                 pop EBP;
 
                 // 'return' to complete switch
                 ret;
             }
         }
 ===============CUT END====================
 
 
 GNU glibc2.7 swapcontext.S code is safe
 ===============CUT===================
 ENTRY(__swapcontext)
  /* Load address of the context data structure we save in.  */
  movl 4(%esp), %eax
 
  /* Return value of swapcontext.  EAX is the only register whose
     value is not preserved.  */
  movl $0, oEAX(%eax)
 
  /* Save the 32-bit register values and the return address.  */
  movl %ecx, oECX(%eax)
  movl %edx, oEDX(%eax)
  movl %edi, oEDI(%eax)
  movl %esi, oESI(%eax)
  movl %ebp, oEBP(%eax)
  movl (%esp), %ecx
  movl %ecx, oEIP(%eax)
  leal 4(%esp), %ecx
  movl %ecx, oESP(%eax)
  movl %ebx, oEBX(%eax)
 
  /* Save the FS segment register.  */
  xorl %edx, %edx
  movw %fs, %dx
  movl %edx, oFS(%eax)
 
  /* We have separate floating-point register content memory on the
     stack.  We use the __fpregs_mem block in the context.  Set the
     links up correctly.  */
  leal oFPREGSMEM(%eax), %ecx
  movl %ecx, oFPREGS(%eax)
  /* Save the floating-point context.  */
  fnstenv (%ecx)
 
  /* Load address of the context data structure we have to load.  */
  movl 8(%esp), %ecx
 
  /* Save the current signal mask and install the new one.  */
  pushl %ebx
  leal oSIGMASK(%eax), %edx
  leal oSIGMASK(%ecx), %ecx
  movl $SIG_SETMASK, %ebx
  movl $__NR_sigprocmask, %eax
  ENTER_KERNEL
  popl %ebx
  cmpl $-4095, %eax  /* Check %eax for error.  */
  jae SYSCALL_ERROR_LABEL /* Jump to error handler if error.  */
 
  /* EAX was modified, reload it.  */
  movl 8(%esp), %eax
 
  /* Restore the floating-point context.  Not the registers, only the
     rest.  */
  movl oFPREGS(%eax), %ecx
  fldenv (%ecx)
 
  /* Restore the FS segment register.  We don't touch the GS register
     since it is used for threads.  */
  movl oFS(%eax), %edx
  movw %dx, %fs
 
  /* Fetch the address to return to.  */
  movl oEIP(%eax), %ecx
 
  /* Load the new stack pointer.  */
  movl oESP(%eax), %esp
 
  /* Push the return address on the new stack so we can return there.  */
  pushl %ecx
 
  /* Load the values of all the 32-bit registers (except ESP).
     Since we are loading from EAX, it must be last.  */
  movl oEDI(%eax), %edi
  movl oESI(%eax), %esi
  movl oEBP(%eax), %ebp
  movl oEBX(%eax), %ebx
  movl oEDX(%eax), %edx
  movl oECX(%eax), %ecx
  movl oEAX(%eax), %eax
 
  /* The following 'ret' will pop the address of the code and jump
     to it.  */
 
 L(pseudo_end):
  ret
 PSEUDO_END(__swapcontext)
 =============CUT END=================
 
 
 Microsoft Windows Server 2003 SwitchToFiber code also safe.
 ===========Kernel32.dll SwitchToFiber==============
 7C821804 k>/$  64:8B15 18000000  mov edx,dword ptr fs:[18]
 7C82180B   |.  8B42 10           mov eax,dword ptr ds:[edx+10]
 7C82180E   |.  8998 B8000000     mov dword ptr ds:[eax+B8],ebx
 7C821814   |.  89B8 B0000000     mov dword ptr ds:[eax+B0],edi
 7C82181A   |.  89B0 B4000000     mov dword ptr ds:[eax+B4],esi
 7C821820   |.  89A8 C8000000     mov dword ptr ds:[eax+C8],ebp
 7C821826   |.  8178 14 0F000100  cmp dword ptr ds:[eax+14],1000F
 7C82182D   |.  75 14             jnz short kernel32.7C821843
 7C82182F   |.  9B                wait
 7C821830   |.  DD78 34           fstsw word ptr ds:[eax+34]
 7C821833   |.  D978 30           fstcw word ptr ds:[eax+30]
 7C821836   |.  803D 7A02FE7F 01  cmp byte ptr ds:[7FFE027A],1
 7C82183D   |.  75 04             jnz short kernel32.7C821843
 7C82183F   |.  0FAE58 28         stmxcsr dword ptr ds:[eax+28]
 7C821843   |>  89A0 D8000000     mov dword ptr ds:[eax+D8],esp
 7C821849   |.  8B8A B40F0000     mov ecx,dword ptr ds:[edx+FB4]
 7C82184F   |.  8988 E8020000     mov dword ptr ds:[eax+2E8],ecx
 7C821855   |.  8B8A A8010000     mov ecx,dword ptr ds:[edx+1A8]
 7C82185B   |.  8988 E4020000     mov dword ptr ds:[eax+2E4],ecx
 7C821861   |.  8B0A              mov ecx,dword ptr ds:[edx]
 7C821863   |.  8B5A 08           mov ebx,dword ptr ds:[edx+8]
 7C821866   |.  8BB2 780F0000     mov esi,dword ptr ds:[edx+F78]
 7C82186C   |.  8948 04           mov dword ptr ds:[eax+4],ecx
 7C82186F   |.  8958 0C           mov dword ptr ds:[eax+C],ebx
 7C821872   |.  89B0 EC020000     mov dword ptr ds:[eax+2EC],esi
 7C821878   |.  8B4C24 04         mov ecx,dword ptr ss:[esp+4]
 7C82187C   |.  894A 10           mov dword ptr ds:[edx+10],ecx
 7C82187F   |.  8B71 04           mov esi,dword ptr ds:[ecx+4]
 7C821882   |.  8B59 08           mov ebx,dword ptr ds:[ecx+8]
 7C821885   |.  8932              mov dword ptr ds:[edx],esi
 7C821887   |.  895A 04           mov dword ptr ds:[edx+4],ebx
 7C82188A   |.  8B71 0C           mov esi,dword ptr ds:[ecx+C]
 7C82188D   |.  8B59 10           mov ebx,dword ptr ds:[ecx+10]
 7C821890   |.  8BB9 EC020000     mov edi,dword ptr ds:[ecx+2EC]
 7C821896   |.  8972 08           mov dword ptr ds:[edx+8],esi
 7C821899   |.  899A 0C0E0000     mov dword ptr ds:[edx+E0C],ebx
 7C82189F   |.  89BA 780F0000     mov dword ptr ds:[edx+F78],edi
 7C8218A5   |.  8BB1 E4020000     mov esi,dword ptr ds:[ecx+2E4]
 7C8218AB   |.  89B2 A8010000     mov dword ptr ds:[edx+1A8],esi
 7C8218B1   |.  8179 14 0F000100  cmp dword ptr ds:[ecx+14],1000F
 7C8218B8   |.  75 28             jnz short kernel32.7C8218E2
 7C8218BA   |.  8B58 34           mov ebx,dword ptr ds:[eax+34]
 7C8218BD   |.  66:3B59 34        cmp bx,word ptr ds:[ecx+34]
 7C8218C1   |.  75 09             jnz short kernel32.7C8218CC
 7C8218C3   |.  8B58 30           mov ebx,dword ptr ds:[eax+30]
 7C8218C6   |.  66:3B59 30        cmp bx,word ptr ds:[ecx+30]
 7C8218CA   |.  74 09             je short kernel32.7C8218D5
 7C8218CC   |>  66:C741 38 FFFF   mov word ptr ds:[ecx+38],0FFFF
 7C8218D2   |.  D961 30           fldenv (28-byte) ptr ds:[ecx+30]
 7C8218D5   |>  803D 7A02FE7F 01  cmp byte ptr ds:[7FFE027A],1
 7C8218DC   |.  75 04             jnz short kernel32.7C8218E2
 7C8218DE   |.  0FAE51 28         ldmxcsr dword ptr ds:[ecx+28]
 7C8218E2   |>  8BB9 B0000000     mov edi,dword ptr ds:[ecx+B0]
 7C8218E8   |.  8BB1 B4000000     mov esi,dword ptr ds:[ecx+B4]
 7C8218EE   |.  8BA9 C8000000     mov ebp,dword ptr ds:[ecx+C8]
 7C8218F4   |.  8B99 B8000000     mov ebx,dword ptr ds:[ecx+B8]
 7C8218FA   |.  8B81 E8020000     mov eax,dword ptr ds:[ecx+2E8]
 7C821900   |.  8982 B40F0000     mov dword ptr ds:[edx+FB4],eax
 7C821906   |.  8BA1 D8000000     mov esp,dword ptr ds:[ecx+D8]
 7C82190C   \.  C2 0400           retn 4
 ===============CUT END=====================
 
 Hope this bug fix fast because tango is my standard lib.
 
 
Dec 07 2007
parent reply "Swer" <swer yoyocowo.com.nb> writes:
I open 50 threads in my project, each threads have one master fiber and one 
slave fiber. each salve fiber instance a LUA 5.1 lua_State*, A Lua api 
my_yield() calling D Tango Fiber yield in my script. Lua number is double 
type, and my master fiber will handle bothe network and DirectX. So there 
both master/slave firbers touch FP units. My program crash randomly when 
using Tango Fiber, but when using Win32 SwitchToFiber or Posix swapcontext 
theres no crash anymore.

I do trace on you code by OllyDbg, there is no any FP save/restore 
internally by C calling convention. Have u tried use your Fiber on any real 
world project before submit to Tango library?

 Have you tried testing this with any examples?  I'm fairly certain that 
 the FPU does actually do what it is supposed to.  If you will notice, the 
 calling convention on the method is extern(C), not extern(D).  As a 
 result, the C calling specification requires that the FPU state is saved 
 before any function call by the caller - not the callee.  As a result, 
 this method should work and moreover save a great deal of time.  Dumping 
 the FPU state is a rather costly operation, and best avoided if possible, 
 which is why the C calling convention works this way.

 If you can find code that breaks with the current Tango fiber 
 implementation, I'd be happy to make the necessary changes.
Dec 08 2007
parent reply Mikola Lysenko <mclysenk mtu.edu> writes:
I've used Fibers and StackThreads in several independent projects, many which
happened to be heavily floating point intensive (ie 3D demos, videogames, etc).
 I believe that the code used in Tango's Fibers for swapping contexts is both
correct, and also more efficient than either GCC or Win32's SwapContext.  The
justification for this follows from my previous argument about the cdecl
calling convention, which is corroborated by the following evidence:

http://www.agner.org/optimize/calling_conventions.pdf

"Floating point registers :
The floating point registers ST(0)-ST(7) need not be saved. These registers
must be 
emptied before any call or return, except for registers used for return values.
... "


I'm not exactly sure what is causing these crashes, but I can't fix any errors
unless you post an example where the code breaks.  It is possible that a more
serious issue than floating point state is involved, but I can't determine what
is happening given the information. 

-Mik

Swer Wrote:

 I open 50 threads in my project, each threads have one master fiber and one 
 slave fiber. each salve fiber instance a LUA 5.1 lua_State*, A Lua api 
 my_yield() calling D Tango Fiber yield in my script. Lua number is double 
 type, and my master fiber will handle bothe network and DirectX. So there 
 both master/slave firbers touch FP units. My program crash randomly when 
 using Tango Fiber, but when using Win32 SwitchToFiber or Posix swapcontext 
 theres no crash anymore.
 
 I do trace on you code by OllyDbg, there is no any FP save/restore 
 internally by C calling convention. Have u tried use your Fiber on any real 
 world project before submit to Tango library?
 
 Have you tried testing this with any examples?  I'm fairly certain that 
 the FPU does actually do what it is supposed to.  If you will notice, the 
 calling convention on the method is extern(C), not extern(D).  As a 
 result, the C calling specification requires that the FPU state is saved 
 before any function call by the caller - not the callee.  As a result, 
 this method should work and moreover save a great deal of time.  Dumping 
 the FPU state is a rather costly operation, and best avoided if possible, 
 which is why the C calling convention works this way.

 If you can find code that breaks with the current Tango fiber 
 implementation, I'd be happy to make the necessary changes.
Dec 08 2007
parent reply "Swer" <swer yoyocowo.com.nb> writes:
Now im using SwitchToFiber instead Tango Fiber. Right now i dont have so 
much time to split some example from my project. Here I also find an other 
SwitchToFiber implement by ReactOS (open source windows clone). Context 
switch with FP save/restore also, with comment in source code.

 I'm not exactly sure what is causing these crashes, but I can't fix any 
 errors unless you post an example where the code breaks.  It is possible 
 that a more serious issue than floating point state is involved, but I 
 can't determine what is happening given the information.
======= ReactOS-0.3.3/dll/win32/kernel32/thread/i386/fiber.S ====== /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/kernel32/thread/i386/fiber.S * PURPOSE: Fiber context switch code for the x86 architecture * PROGRAMMERS: Alex Ionescu (alex relsoft.net) * KJK::Hyperion <noog libero.it> */ #include <ndk/asm.h> #define CONTEXT_FULL 0x10007 #define CONTEXT_FLOATING_POINT 0xF .globl _SwitchToFiber 4 .intel_syntax noprefix _SwitchToFiber 4: /* Get the TEB */ mov edx, fs:[KGDT_R3_TEB] /* Get the Fiber */ mov eax, [edx+TEB_FIBER_DATA] /* Save the non-volatile registers */ mov [eax+FIBER_CONTEXT_EBX], ebx mov [eax+FIBER_CONTEXT_ESI], esi mov [eax+FIBER_CONTEXT_EDI], edi mov [eax+FIBER_CONTEXT_EBP], ebp /* Check if we're to save FPU State */ cmp dword ptr [eax+FIBER_CONTEXT_FLAGS], CONTEXT_FULL + CONTEXT_FLOATING_POINT jnz NoFpuStateSave /* Save the FPU State (Status and Control)*/ fstsw [eax+FIBER_CONTEXT_FLOAT_SAVE_STATUS_WORD] fstcw [eax+FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD] /* Check if the CPU supports SIMD MXCSR State Save */ cmp byte ptr [PROCESSOR_FEATURE_FXSR], 0 jnz NoFpuStateSave stmxcsr [eax+FIBER_CONTEXT_DR6] NoFpuStateSave: /* Save stack since we're not touching it anymore */ mov [eax+FIBER_CONTEXT_ESP], esp /* Transfer some data from the TEB */ mov ecx, [edx+TEB_FLS_DATA] mov [eax+FIBER_FLS_DATA], ecx mov ecx, [edx+TEB_ACTIVATION_CONTEXT_STACK_POINTER] mov [eax+FIBER_ACTIVATION_CONTEXT_STACK], ecx /* Transfer some data related to the Stack */ mov ecx, [edx+TEB_EXCEPTION_LIST] mov [eax+FIBER_EXCEPTION_LIST], ecx mov ecx, [edx+TEB_STACK_LIMIT] mov [eax+FIBER_STACK_LIMIT], ecx mov ecx, [edx+TEB_GUARANTEED_STACK_BYTES] mov [eax+FIBER_GUARANTEED_STACK_BYTES], ecx /* Switch to the new fiber */ mov ecx, [esp+4] mov [edx+TEB_FIBER_DATA], ecx /* Switch Fiber Data */ mov esi, [ecx+FIBER_EXCEPTION_LIST] mov [edx+TEB_EXCEPTION_LIST], esi mov esi, [ecx+FIBER_STACK_BASE] mov [edx+TEB_STACK_BASE], esi mov esi, [ecx+FIBER_STACK_LIMIT] mov [edx+TEB_STACK_LIMIT], esi mov esi, [ecx+FIBER_DEALLOCATION_STACK] mov [edx+TEB_DEALLOCATION_STACK], esi mov esi, [ecx+FIBER_GUARANTEED_STACK_BYTES] mov [edx+TEB_GUARANTEED_STACK_BYTES], esi mov esi, [ecx+FIBER_ACTIVATION_CONTEXT_STACK] mov [edx+TEB_ACTIVATION_CONTEXT_STACK_POINTER], esi /* Restore FPU State */ cmp dword ptr [eax+FIBER_CONTEXT_FLAGS], CONTEXT_FULL + CONTEXT_FLOATING_POINT jnz NoFpuStateRestore /* Check if the Status Word Changed */ mov esi, [eax+FIBER_CONTEXT_FLOAT_SAVE_STATUS_WORD] cmp si, word ptr [ecx+FIBER_CONTEXT_FLOAT_SAVE_STATUS_WORD] jnz StatusWordChanged /* Check if the Control Word Changed */ mov esi, [eax+FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD] cmp si, word ptr [ecx+FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD] jz ControlWordEqual StatusWordChanged: /* Load the new one */ mov word ptr [ecx+FIBER_CONTEXT_FLOAT_SAVE_TAG_WORD], 0xFFFF fldenv [ecx+FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD] ControlWordEqual: /* Load the new one */ cmp byte ptr [PROCESSOR_FEATURE_FXSR], 0 jnz NoFpuStateRestore ldmxcsr [ecx+FIBER_CONTEXT_DR6] NoFpuStateRestore: /* Restore non-volatile registers */ mov esi, [ecx+FIBER_CONTEXT_ESI] mov edi, [ecx+FIBER_CONTEXT_EDI] mov ebx, [ecx+FIBER_CONTEXT_EBX] mov ebp, [ecx+FIBER_CONTEXT_EBP] mov esp, [ecx+FIBER_CONTEXT_ESP] /* Restore FLS Data */ mov eax, [ecx+FIBER_FLS_DATA] mov [edx+TEB_FLS_DATA], eax /* Return */ ret 4 /* EOF */ ====== ReactOS-0.3.3/dll/win32/kernel32/thread/i386/fiber.S END ===
Dec 08 2007
parent Sean Kelly <sean f4.ca> writes:
Swer wrote:
 Now im using SwitchToFiber instead Tango Fiber. Right now i dont have so 
 much time to split some example from my project.
No offense, but it's kind of difficult to fix an issue that can't be reproduced. Do you really want Tango's Fibers to be fixed or did you post here just to say that they stink? Sean
Dec 08 2007