Linux 0.11 learning notes

Posted by JMJimmy on Tue, 08 Mar 2022 01:01:56 +0100

About sleep_ A little doubt about the on () function

void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;

// If the pointer is invalid, exit. (the object pointed to by the pointer can be NULL, but the pointer itself should not be 0) In addition, if
// If the current task is task 0, the machine will crash. Because the operation of task 0 does not depend on its own state, the kernel code sets task 0 as
// Sleep is meaningless.
if (!p)
	return;
if (current == &(init_task.task))
	panic("task[0] trying to sleep");
// Let tmp point to the task (if any) already on the waiting queue, such as inode - > I_ wait. And put the head of the sleep queue
// Wait, the pointer points to the current task. In this way, the current task is inserted into the waiting queue of * p. Then set the current task as
// Non interruptible wait state and perform rescheduling.
tmp = *p;
*p = current;
current->state = TASK_UNINTERRUPTIBLE;
schedule();
// Only when the waiting task is awakened, the scheduler returns here again, indicating that the process has been explicitly awakened (on
// Continued). Since everyone is waiting for the same resource, it is necessary to wake up all waiting for the resource when the resource is available
// Process. The nested call of this function will also wake up all processes waiting for the resource. Here, nested calls refer to a
// The process called sleep_ After on (), it will be switched off in this function and the control will be transferred to other processes. If any
// If the process also needs to use the same resource, it will also use the same waiting queue header pointer as a parameter to call sleep_on() function,
// And will also fall into the function without returning. Only when the code somewhere in the kernel takes the queue header pointer as the parameter wake_up the queue,
// Then, when the system switches to execute the process A indicated by the header pointer, the process will continue to execute the following code and queue the next one
// Process B sets the ready state (wake-up). When it's the B process's turn to execute, it can also continue to execute the following code. If it
// There is also a waiting process C, which will wake up C, etc. You should also add a line before this: * p = tmp
if (tmp)                    // If there is a waiting task before it, it will also be set to the ready state (wake up)
	tmp->state=0;

}

Suppose there are four tasks A, B, C and D waiting for A resource. They call sleep_ The on() function successively enters the wait queue of resources. At this time, the queue condition is D-C-B-A, wait=D.
At some point, resources are released and task D is awakened. After task D is scheduled and executed by schedule(), it will start from sleep_ Start execution after schedule() in the on() function (execution will resume when any task in the waiting queue is resumed), that is:
*

p=tmp;//tmp=C
if (tmp)                    // If there is a waiting task before it, it will also be set to the ready state (wake up)
		tmp->state=0;

At this time, wait=C, C-B-A in the waiting queue, and task C is set to schedulable state. But it's still in task D.
Task D continues to be executed. Generally, resources are locked and relevant operations are started. Suppose D will occupy resources for a long time. When task C begins to be called:

*p=tmp;//At this point tmp=B
if (tmp)                    // If there is a waiting task before it, it will also be set to the ready state (wake up)
		tmp->state=0;

At this time, wait=B, B-A in the waiting queue, and Task B is set to schedulable state. It is still in task C.
Task C continues to execute and starts to apply for resources. However, since the resources are occupied by task D, task C calls sleep again_ Go to sleep. For example, buffer C, if the task is in sleep_ Wake up in on() and find that the resource is locked again after execution. Sleep will be called again_ I'll sleep myself.

static inline void wait_on_buffer(struct buffer_head * bh)
{
	cli();                          // Off interrupt
	while (bh->b_lock)              // If it is locked, the process goes to sleep and waits for it to unlock
		sleep_on(&bh->b_wait);
	sti();                          // Open interrupt
}

After C sleep, wait=C, and the sleep queue is C-B-A. At this time, C and A will not be schedule d, but B has been set as schedulable by C before. When B starts running, B sets A to be schedulable, wait=A, there is only A waiting queue, and C is lost. B continues to apply for resources, finds that it is still locked, and sleeps himself again. At this time, wait=B, waiting for queue B-A. When A runs, wait=NULL. After applying for resources, it is found that the resources are locked and sleep. At this time, wait=A, there is only A in the sleep queue, and B is lost.

I think I can enter sleep_ After on, first check whether the state of the current queue header is 0. If it is 0, it will be changed to task_ The resource is currently locked and cannot be run. The details are as follows:

If(*p && *p->stat==0)
	*p->state= TASK_UNINTERRUPTIBLE;
tmp = *p;
	*p = current;
	current->state = TASK_UNINTERRUPTIBLE;
	schedule();