模拟线程切换ThreadSwitch源代码(X86)
2023-11-13
32
0
ThreadSwitch.cpp
// ThreadSwitch.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "ThreadCore.h"
int main(int argc, char* argv[])
{
//初始化线程环境
RegisterGMThread("Thread1",Thread1,NULL);
RegisterGMThread("Thread2",Thread2,NULL);
RegisterGMThread("Thread3",Thread3,NULL);
RegisterGMThread("Thread4",Thread4,NULL);
//仿Windows线程切换
for (;;)
{
Sleep(20);
//实际执行的是丝程切换函数Scheduling
ThreadPolling();
}
return 0;
}
ThreadCore.h
// ThreadCore.h: interface for the ThreadCore class.
//
//
#if !defined(AFX_THREADCORE_H__3C5DBE32_012F_4176_884F_8D9EA510122D__INCLUDED_)
#define AFX_THREADCORE_H__3C5DBE32_012F_4176_884F_8D9EA510122D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define MAXGMTHREAD 0x100
#define GMTHREAD_CREATE 0x01
#define GMTHREAD_READAY 0x02
#define GMTHREAD_RUNING 0x04
#define GMTHREAD_SLEEP 0x08
#define GMTHREAD_SUSPEND 0x10
#define GMTHREAD_EXIT 0x100
typedef struct
{
char *name; // 线程名 相当于线程TID
int Flags; // 线程状态
int SleepMillisecondDot; // 休眠截止时间戳
void *InitialStack; // 线程堆栈起始位置,也就是EBP
void *StackLimit; // 线程堆栈界限
void *KernelStack; // 线程堆栈当前位置,也就是ESP
void *lpParameter; // 线程函数的参数
void (*func)(void *lpParameter); // 线程函数
} GMThread_t;
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
/* 线程结构体数组
* 线程在不同状态的存储位置不同
* 正在运行的线程位于KPCR
* 等待中的线程位于等待链表
* 就绪的线程位于调度链表中
* 这里对于以上三种情况使用一个数组进行包含
* main函数也是一个线程,信息存在第一个数组成员里,也就是下标为0的位置
* 创建线程时,是从下标为1的位置开始分配的
*/
extern GMThread_t GMThreadList[MAXGMTHREAD]; //最大100个
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void IdleGMThread(void *lpParameter);
void GMThreadStartup(GMThread_t *GMThreadp);
void initGMThread(GMThread_t *GMThreadp,char *name,void (*func)(void *lpParameter),void *lpParameter);
int RegisterGMThread(char *name,void (*func)(void *lpParameter),void *lpParameter);
void Scheduling(void);
void GMSleep(int Milliseconds);
void ThreadPolling();
void Thread1(void *lpParameter);
void Thread2(void *lpParameter);
void Thread3(void *lpParameter);
void Thread4(void *lpParameter);
#endif // !defined(AFX_THREADCORE_H__3C5DBE32_012F_4176_884F_8D9EA510122D__INCLUDED_)
ThreadCore.cpp
#include "stdafx.h"
#include "stdio.h"
#include "windows.h"
#include "ThreadCore.h"
#define _SELF "滴水_仿Windows线程切换"
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
int CurrentThreadindex = 0;
GMThread_t GMThreadList[MAXGMTHREAD] = { NULL,0 };
#define GMTHREADSTACKSIZE 0x80000
void *WindowsStackLimit = NULL;
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
__declspec(naked) void SwitchContext(GMThread_t *SrcGMThreadp,GMThread_t *DstGMThreadp)
{
__asm
{
//保存现场
push ebp
mov ebp,esp
//sub esp,__LOCAL_SIZE
push edi
push esi
push ebx
push ecx
push edx
push eax
mov esi,SrcGMThreadp //当前线程结构体指针
mov edi,DstGMThreadp //目标线程结构体指针
// esi + GMThread_t.KernelStack == SrcGMThreadp.KernelStack
mov [esi+GMThread_t.KernelStack], esp
//---------------经典堆栈切换 另一个线程复活----------------------------------
// edi + GMThread_t.KernelStack == DstGMThreadp.KernelStack
mov esp, [edi+GMThread_t.KernelStack]
//此时,ESP为目标线程堆栈栈顶
pop eax
pop edx
pop ecx
pop ebx
pop esi
pop edi
//add esp,__LOCAL_SIZE
pop ebp
ret //ebp之后是GMThreadStartup函数地址
}
}
//用来执行线程函数
void GMThreadStartup(GMThread_t *GMThreadp)
{
//执行线程函数
GMThreadp->func(GMThreadp->lpParameter);
//线程函数执行结束,设置线程状态为EXIT
GMThreadp->Flags = GMTHREAD_EXIT;
//线程切换
Scheduling();
return ;
}
void IdleGMThread(void *lpParameter)
{
Scheduling();
return ;
}
void PushStack(unsigned int **Stackpp,unsigned int v)
{
// ESP 减去一个单位(4个字节)
*Stackpp -= 1;
//[ESP] = 参数v
**Stackpp = v;
return ;
}
void initGMThread(GMThread_t *GMThreadp,char *name,void (*func)(void *lpParameter),void *lpParameter)
{
unsigned char *StackPages;
unsigned int *StackDWORDParam;
//结构初始化赋值
GMThreadp->Flags = GMTHREAD_CREATE; //初始化线程为创建状态
GMThreadp->name = name; //线程名
GMThreadp->func = func; //线程函数,已经定义好
GMThreadp->lpParameter = lpParameter; //参数
//申请堆栈空间
StackPages = (unsigned char*)VirtualAlloc(NULL,GMTHREADSTACKSIZE,MEM_COMMIT,PAGE_READWRITE);
//堆栈清零
memset(StackPages,0,GMTHREADSTACKSIZE);
//堆栈栈底(EBP)
GMThreadp->InitialStack = (StackPages+GMTHREADSTACKSIZE-0x10);
//堆栈边界地址
GMThreadp->StackLimit = StackPages;
StackDWORDParam = (unsigned int*)GMThreadp->InitialStack;
//入栈
PushStack(&StackDWORDParam,(unsigned int)GMThreadp); //线程结构体自身指针,用来寻找 线程函数|函数参数
PushStack(&StackDWORDParam,(unsigned int)9); //平衡堆栈
PushStack(&StackDWORDParam,(unsigned int)GMThreadStartup); //函数地址,执行线程函数的入口函数
//下面的值可以随便写
PushStack(&StackDWORDParam,5); //push ebp
PushStack(&StackDWORDParam,7); //push edi
PushStack(&StackDWORDParam,6); //push esi
PushStack(&StackDWORDParam,3); //push ebx
PushStack(&StackDWORDParam,2); //push ecx
PushStack(&StackDWORDParam,1); //push edx
PushStack(&StackDWORDParam,0); //push eax
//执行后,堆栈变化如下
GMThreadp->KernelStack = StackDWORDParam; //指向当前线程的栈顶(ESP)
GMThreadp->Flags = GMTHREAD_READAY; //线程状态设置为就绪
return ;
}
int RegisterGMThread(char *name,void (*func)(void *lpParameter),void *lpParameter)
{
int i;
//为数组下标为0的成员赋值,GM Thread,相当于main函数线程
if (GMThreadList[0].name==NULL)
{
//申请堆栈初始化操作 线程数组 ,线程名字 ,函数地址 ,参数
initGMThread(&GMThreadList[0], "IDLE GM Thread", IdleGMThread, NULL);
}
//新增的线程从下标为1开始写入
for (i=1;GMThreadList[i].name;i++)
{
//判断数组中尚未初始化的成员
if (0==stricmp(GMThreadList[i].name,name))
{
break;
}
}
//初始化线程结构体
initGMThread(&GMThreadList[i],name,func,lpParameter);
return (i|0x55AA0000);
}
void Scheduling(void)
{
int i;
int TickCount;
GMThread_t *SrcGMThreadp;
GMThread_t *DstGMThreadp;
TickCount = GetTickCount();
SrcGMThreadp = &GMThreadList[CurrentThreadindex]; //当前线程结构体指针
DstGMThreadp = &GMThreadList[0]; //目标线程结构体指针
//遍历线程数组,找到状态为就绪的线程
for (i=1;GMThreadList[i].name;i++)
{
if (GMThreadList[i].Flags&GMTHREAD_SLEEP)
{
if (TickCount>GMThreadList[i].SleepMillisecondDot)
{
GMThreadList[i].Flags = GMTHREAD_READAY;
}
}
if ((GMThreadList[i].Flags&GMTHREAD_READAY))
{
//检测到有线程的状态为就绪,将其作为目标线程
DstGMThreadp = &GMThreadList[i];
break;
}
}
CurrentThreadindex = DstGMThreadp-GMThreadList; //得到即将执行的线程下标
SwitchContext(SrcGMThreadp,DstGMThreadp); //线程切换
return ;
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void GMSleep(int Milliseconds)
{
GMThread_t *GMThreadp;
GMThreadp = &GMThreadList[CurrentThreadindex];
//非挂起态时,计算休眠截止时间,并设置状态为休眠
if ((GMThreadp->Flags&GMTHREAD_SUSPEND)==0)
{
GMThreadp->SleepMillisecondDot = GetTickCount()+Milliseconds;
GMThreadp->Flags = GMTHREAD_SLEEP;
}
//线程切换
Scheduling();
return ;
}
void ThreadPolling()
{
unsigned char StackPage[GMTHREADSTACKSIZE];
memset(StackPage,0,GMTHREADSTACKSIZE);
//模拟线程切换
IdleGMThread(StackPage);
return ;
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
void vmmprint(char *f,int l,char *fmt, ...)
{
int ret;
char buffer[0x100];
va_list args;
//----------------------------------
va_start(args, fmt);
_snprintf(buffer,0x80,"[%s]:",f,l);
ret = _vsnprintf(buffer+strlen(buffer), 0x100-strlen(buffer), fmt, args);
if (ret == -1)
{
strcpy(buffer, "vmmprint: error.");
}
//----------------------------------
printf("%s",buffer);
//OutputDebugString(buffer);
return ;
}
void Thread1(void *lpParameter)
{
int i;
for (i=0;i<3;i++)
{
vmmprint(_SELF,__LINE__,"Thread1 \n");
GMSleep(1000);
}
return ;
}
void Thread2(void *lpParameter)
{
for (;;)
{
vmmprint(_SELF,__LINE__,"Thread2 \n");
GMSleep(500);
}
return ;
}
void Thread3(void *lpParameter)
{
for (;;)
{
vmmprint(_SELF,__LINE__,"Thread3 \n");
GMSleep(800);
}
return ;
}
void Thread4(void *lpParameter)
{
for (;;)
{
vmmprint(_SELF,__LINE__,"Thread4 \n");
GMSleep(200);
}
return ;
}
总结
线程不是被动切换的,而是主动让出CPU
线程切换并没有使用TSS来保存寄存器,而是使用堆栈
线程切换的过程就是堆栈切换的过程