C 线程调度(和 asm)
C Thread scheduling (and asm)
我目前正在编写自己的线程库。而且我无法调试未处理的异常 "Stack cookie instrumentation code detected a stack-based buffer overrun"。以下是导致未处理异常的相关代码
void Scheduler()
{
void *curr_esp;
TCB* next_thread = ready_queue->data;
popFront(&ready_queue);
__asm
{
pushad
mov curr_esp, esp
}
curr_thread->esp = curr_esp;
if (curr_thread->status == RUNNING)
{
curr_thread->status = READY;
Enqueue(curr_thread, &ready_queue);
}
curr_thread = next_thread;
if (curr_thread->status == READY)
{
curr_thread->status = RUNNING;
curr_esp = next_thread->esp;
__asm
{
mov esp, curr_esp
popad
}
}
else if (curr_thread->status == NEW)
{
curr_thread->status = RUNNING;
curr_thread->params = (curr_thread->fn)(curr_thread->params);
__asm
{
mov esp,curr_esp
}
if (curr_thread->status == RUNNING)
{
thread_exit(curr_thread->params);
}
}
}
这是执行自旋函数的主要部分,应该 运行 线程库和 thd_yield 基本上只是调用我的调度程序
void *spin1(void *a)
{
int i;
for(i=0;i< 20; i++)
{
printf("SPIN1\n");
if((i+1)%4==0)
thd_yield();
}
return NULL;
}
void* spin2(void *a)
{
int i;
for(i=0;i< 20; i++)
{
printf("SPIN2\n");
if((i+1)%4==0)
thd_yield();
}
return NULL;
}
int main()
{
thread_id_ id;
thd_init();
id = new_thd(spin2, NULL);
spin1(NULL);
}
输出应该是 5 组 4 "spin1"s 和 "spin2"s 交替。
旋转1
自旋1
自旋1
自旋1
自旋2
自旋2
自旋2
自旋2
自旋1
..
该代码对于前 2 组 "spin1"s 和 1 工作得很好,但在第二组 "spin2"s 上给了我一个未处理的异常。我检查了正在存储和检索的堆栈指针,它们已正确存储和检索,链表存储和内存分配。更糟糕的是,我没有看到是哪一行导致了错误。
注意:我不允许使用任何线程系统调用,它必须在 C 中。
这是我的 TCB 结构,如果有帮助的话
typedef struct _TCB_
{
/* Unique ID*/
thread_id_ id;
/* Thread status*/
enum ThreadState status;
/* ID of next thread*/
thread_id_ wait_id;
void *esp;
void *(*fn)(void*);
void *params;
void *stack;
}TCB;
如果可以帮助您解决此问题,我很乐意分享我的源文件。
简而言之,堆栈 cookie 受到干扰。
堆栈cookie在执行函数代码之前被计算并存储在当前堆栈帧的末尾。当函数代码执行结束时,它正在被验证。在缓冲区溢出的情况下,它会被覆盖并且验证失败。这就是为什么它不能向您报告导致问题的行。
您的情况可能有多种原因导致此异常。由于没有完整的代码很难判断,我会做一些假设:
- 您实际上可能有 缓冲区溢出。最简单的测试方法是禁用 stack cookie 安全检查,然后查看是否有 "Access violation" 异常。即使你不这样做,它仍然可能是 缓冲区溢出。
- 不同线程的堆栈指针指向重叠的内存区域。如果您没有为堆栈分配足够的内存,则可能会发生这种情况 - 这是 缓冲区溢出 无论如何。
- 不太可能,但您的代码可能是正确的,但它与堆栈 cookie 安全检查不兼容,因此您必须使其兼容或禁用检查。这里唯一的建议是启用 Assembler Output 并检查它。
我目前正在编写自己的线程库。而且我无法调试未处理的异常 "Stack cookie instrumentation code detected a stack-based buffer overrun"。以下是导致未处理异常的相关代码
void Scheduler()
{
void *curr_esp;
TCB* next_thread = ready_queue->data;
popFront(&ready_queue);
__asm
{
pushad
mov curr_esp, esp
}
curr_thread->esp = curr_esp;
if (curr_thread->status == RUNNING)
{
curr_thread->status = READY;
Enqueue(curr_thread, &ready_queue);
}
curr_thread = next_thread;
if (curr_thread->status == READY)
{
curr_thread->status = RUNNING;
curr_esp = next_thread->esp;
__asm
{
mov esp, curr_esp
popad
}
}
else if (curr_thread->status == NEW)
{
curr_thread->status = RUNNING;
curr_thread->params = (curr_thread->fn)(curr_thread->params);
__asm
{
mov esp,curr_esp
}
if (curr_thread->status == RUNNING)
{
thread_exit(curr_thread->params);
}
}
}
这是执行自旋函数的主要部分,应该 运行 线程库和 thd_yield 基本上只是调用我的调度程序
void *spin1(void *a)
{
int i;
for(i=0;i< 20; i++)
{
printf("SPIN1\n");
if((i+1)%4==0)
thd_yield();
}
return NULL;
}
void* spin2(void *a)
{
int i;
for(i=0;i< 20; i++)
{
printf("SPIN2\n");
if((i+1)%4==0)
thd_yield();
}
return NULL;
}
int main()
{
thread_id_ id;
thd_init();
id = new_thd(spin2, NULL);
spin1(NULL);
}
输出应该是 5 组 4 "spin1"s 和 "spin2"s 交替。
旋转1 自旋1 自旋1 自旋1 自旋2 自旋2 自旋2 自旋2 自旋1 ..
该代码对于前 2 组 "spin1"s 和 1 工作得很好,但在第二组 "spin2"s 上给了我一个未处理的异常。我检查了正在存储和检索的堆栈指针,它们已正确存储和检索,链表存储和内存分配。更糟糕的是,我没有看到是哪一行导致了错误。
注意:我不允许使用任何线程系统调用,它必须在 C 中。
这是我的 TCB 结构,如果有帮助的话
typedef struct _TCB_
{
/* Unique ID*/
thread_id_ id;
/* Thread status*/
enum ThreadState status;
/* ID of next thread*/
thread_id_ wait_id;
void *esp;
void *(*fn)(void*);
void *params;
void *stack;
}TCB;
如果可以帮助您解决此问题,我很乐意分享我的源文件。
简而言之,堆栈 cookie 受到干扰。
堆栈cookie在执行函数代码之前被计算并存储在当前堆栈帧的末尾。当函数代码执行结束时,它正在被验证。在缓冲区溢出的情况下,它会被覆盖并且验证失败。这就是为什么它不能向您报告导致问题的行。
您的情况可能有多种原因导致此异常。由于没有完整的代码很难判断,我会做一些假设:
- 您实际上可能有 缓冲区溢出。最简单的测试方法是禁用 stack cookie 安全检查,然后查看是否有 "Access violation" 异常。即使你不这样做,它仍然可能是 缓冲区溢出。
- 不同线程的堆栈指针指向重叠的内存区域。如果您没有为堆栈分配足够的内存,则可能会发生这种情况 - 这是 缓冲区溢出 无论如何。
- 不太可能,但您的代码可能是正确的,但它与堆栈 cookie 安全检查不兼容,因此您必须使其兼容或禁用检查。这里唯一的建议是启用 Assembler Output 并检查它。