Exemplo n.º 1
0
        /// <summary>
        ///     CLR controlled fiber-enabled execution. To be called from unmanaged environment.
        /// </summary>
        /// <param name="fiberGcHandleIntPtr">The handle to the special fibers that are part of schedulers.</param>
        public void Proc(IntPtr fiberGcHandleIntPtr)
        {
            var fiberGcHandle = GCHandle.FromIntPtr(fiberGcHandleIntPtr);

            if (IsRegularManagedThread())
            {
                throw new NotSupportedException(
                          "Thread that at least once called regular C# thread cannot be used as Fiber-Enabled thread.");
            }

            // Initializing System.Threading.Thread in a special way, so CLR VM will handle different fiber-oriented behavior.
            InitAsFiberEnabledThread();

            // Moving to hard-hack of the stack.
            if (!Cpp.setjmp(ref _beforeFiberStack))
            {
                // Stop using C++
                // Working on assembly level

                // switching C++ OS stack to ClrFiber managed stack:
                var fiber = (ClrFiber)fiberGcHandle.Target;

                // Very special stack condition
                var returnAddress = NativeCodeConstants.InstructionOffset("exitThread");
                Cpu.StackBasePointer =
                    Cpu.StackBasePointer +
                    0x10; // Hacking stack base pointer, now it's tuned to the address of the "returnAddress" variable.

                // After this hack the "ret" assembly command will jump to "exitThread".
                ;

                // What happens if we call Native method inside the "Managed Stack"
                // Making thread exit fiber as current.
                ThreadExitFiber._suspendState.StackPointer     = Cpu.StackPointer;
                ThreadExitFiber._suspendState.StackBasePointer = Cpu.StackBasePointer; // This is native stack pointer
                ThreadExitFiber._suspendState.ContinuationInstructionAddress =
                    NativeCodeConstants.InstructionOffset("exitThread");
                ClrFiber._current = ThreadExitFiber;

                // Do the same code as this IL instruction produces.
                // Whenever ClrFiber executes "ret" assembly instruction will return to "exitThread".
                ThreadExitFiber.TransferFlowOpcode(
                    fiber); // After this call, current thread is fully controlled by the preemptive multitasking.

                // When preemptive multitasking switch control to the "ThreadExitFiber", thread flow will jump to this location:
                exitThread :;
            }

            // Cpp now works again.
            ReleaseFiberEnabledThread();
        }
Exemplo n.º 2
0
        [CpuRegistryBarrier] // JIT should not rely on Cpu registers after this IL instruction.
        public void TransferFlowOpcode(ClrFiber nextFiber)
        {
            // Generated assembly instructions pseudo code:

            // Transferring flow to our self.

            // What should be guarantied before this instruction:
            if (!ReferenceEquals(_current, nextFiber) || !nextFiber.IsSuspended)
            {
                throw new UnpredictableBehavior();
            }

            // Saving resume point in the current fiber.
            _suspendState.StackPointer     = Cpu.StackPointer;     // On x64 machine it's an RSP register.
            _suspendState.StackBasePointer = Cpu.StackBasePointer; // On x64 machine it's an RBP register.

            _suspendState.ContinuationInstructionAddress =
                NativeCodeConstants.InstructionOffset("resume"); // JIT generated code constant

            // Currently we are in the critical state, setting-up stack state for the new fiber.
            _current = nextFiber;
            nextFiber._suspendState.RestoreBaseCpuRegisters();
            Cpu.StackPointer     = nextFiber._suspendState.StackPointer;
            Cpu.StackBasePointer = nextFiber._suspendState.StackBasePointer;
            Cpu.Jump(nextFiber._suspendState.ContinuationInstructionAddress);

            // Critical state ended.
            // After this call we appear on the "resume:" label of the !!!nextFiber!!!, not this.
            // ------------------------------------------------------------------------------- Preemptive switch

            // RESUME from other ClrFiber
            // This instruction already performed it's work
            // The "Resume" label it's a next instruction location
            resume :;

            // Here there is no any assumption about a state of CPU registers
        }