I am writing codes on a thrd_stop function. It has similar functionality as the practice lab of chapter 4 in xv6, the alarm. When thrd_stop is called, start a timer and call handler when the timer reaches the inverval. The difference between mine and xv6 practice is that I need to provide arguments to the handler. I've add the below things to attributes of proc.
int thrdstop_ticks;
int thrdstop_interval;
uint64 threstop_handler;
uint64 thrdstop_handler_args;
struct trapframe thrdstop_context[MAX_THRD_NUM];
int thrdstop_context_used[MAX_THRD_NUM];
int thrdstop_context_id;
int timeFlag;
And here is my thrdstop:
uint64
sys_thrdstop(void)
{
int delay;
uint64 context_id_ptr;
uint64 handler, handler_arg;
if (argint(0, &delay) < 0)
return -1;
if (argaddr(1, &context_id_ptr) < 0)
return -1;
if (argaddr(2, &handler) < 0)
return -1;
if (argaddr(3, &handler_arg) < 0)
return -1;
struct proc *proc = myproc();
proc->thrdstop_interval = delay;
proc->threstop_handler = handler;
proc->thrdstop_handler_args = handler_arg;
int kernelPtr;
copyin(proc->pagetable, (char *)&kernelPtr, context_id_ptr, sizeof(kernelPtr));
if (kernelPtr == -1)
{
for (int i = 0; i < MAX_THRD_NUM; i++)
{
if (!proc->thrdstop_context_used[i])
{
kernelPtr = i;
copyout(proc->pagetable, context_id_ptr, (char *)&kernelPtr, sizeof(kernelPtr));
proc->thrdstop_context_used[i] = 1;
proc->thrdstop_context_id = i;
break;
}
}
if (kernelPtr == -1)
return -1;
}
proc->thrdstop_context_id = kernelPtr;
return 0;
}
uint64
sys_thrdresume(void)
{
int context_id;
if (argint(0, &context_id) < 0)
return -1;
struct proc *proc = myproc();
if (proc->thrdstop_context_used[context_id] == 0)
return -1;
proc->thrdstop_context_used[context_id] = 0;
proc->thrdstop_interval = 0;
proc->thrdstop_context_id = -1;
// printf("resume\n");
memmove(proc->trapframe, &proc->thrdstop_context[context_id], sizeof(proc->thrdstop_context[context_id]));
proc->timeFlag = 0;
return 0;
}
And in usertrap and kerneltrap, I do the below things.
if (which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
{
if (p->thrdstop_interval == 0 && p->threstop_handler == 0)
goto yield;
if (p->thrdstop_ticks == p->thrdstop_interval)
{
if(!p->timeFlag)
{
// intr_off();
memmove(&p->thrdstop_context[p->thrdstop_context_id],p->trapframe,sizeof(p->thrdstop_context[p->thrdstop_context_id]));
// printf("%d",p->trapframe->a0);
// printf("kernel %d\n",p->thrdstop_context_id);
p->trapframe->a0=p->thrdstop_handler_args;
p->trapframe->epc = p->threstop_handler;
p->thrdstop_ticks = 0;
p->timeFlag=1;
}
}
else
{
p->thrdstop_ticks += 1;
}
yield:
yield();
}
The problem now is that after changing a0 to the handler_args, sometimes it will be overwritten by other system call such as other timer interrupt. In this case, when the handler is executed, it cannot use the correct argument. Is there any way to pass the argument correctly before jumping back to user space without overwritten by other system call?