Preface
>_<"The previous section has implemented simple multitasking and has also written the task suspension function to speed up processing ~ This section adds multiple Windows Based on the above, and then designs a hierarchical priority mode on the priority level ~
I. effect display
>_<"Four windows are generated. Besides task_a, the number in 1 s is displayed in the window.
>_<"The priority mode here is: when there are tasks in the layer with a higher priority, all tasks in the layer with a lower priority will be blocked, only tasks in the layer with a higher priority can be switched ~, This example sets task a as level1 and priority 2, and the other three as level2 with priority 1, 2, and 3. here, the priority is the interruption time. Priority 1 indicates that the interruption time of the task is 0.01 s.
Ii. Code Description
>_<"In bootpack. h, there is a tss32 struct that stores the status information of the task. Then there is a task struct, followed by a level struct, And the last struct is responsible for managing all tasks ~
1/* mtask. c task switchover related */2 # define max_tasks 1000/* Maximum number of tasks */3 # define task_gdt0 3/* defines the number of gdt numbers allocated to TSS */4 # define max_tasks_lv 100 // up to 100 tasks per level 5 # define max_tasklevels 10 // up to 10 levels 6 7 struct tss32 {// task status segment task status Segment 8 int backlink, esp0, ss0, esp1, SS1, esp2, ss2, 3303. // the stored data is not register data, but information related to task settings, during task switching, these Members will not be written (except for backlink, which will be written in some cases) 9 int EIP, eflags, eax, ECx, EDX, EBX, es P, EBP, ESI, EDI; // 32-bit registers 10 int es, Cs, SS, DS, FS, GS; // 16-bit Registers 11 int ldtr, iomap; // related task Settings section 12}; 13 struct task {14 int Sel, flags;/* SEL is used to store gdt numbers */15 int level, priority; 16 struct tss32 TSS; 17}; 18 struct tasklevel {19 int running;/* Number of running tasks */20 int now; /* this variable is used to record which task is currently running */21 struct task * tasks [max_tasks_lv]; 22}; 23 struct taskctl {24 int now_lv; /* running level */25 char lv_change; /* Whether to change the level */26 struct tasklevel [max_tasklevels] during the next task switchover; // a maximum of 10 level27 struct task tasks0 [max_tasks]; 28 }; 29 extern struct timer * task_timer; 30 struct task * task_init (struct memman * memman); // initialization Task Control 31 struct task * task_alloc (void ); // assign a task 32 void task_run (struct task * task, int level, int priority); // set the level and priority of a task 33 void task_switch (void ); // if the level changes, you need to change the current level and find the current task from the current level to switch. Change 34 void task_sleep (struct task * task); // When deleting a task, consider level changes ~
>_<"In initialization, the running of all levels (that is, the number of running tasks) is set to 0, And Now (that is, the label of the currently running task) is set to 0, then assign a task to set the level and priority, and add the level. The second row is used to set the level to be switched when the task is switched. Next, allocate a time and set it ~
1 For (I = 0; I <max_tasklevels; I ++) {// set the level of each layer to 0 2 taskctl-> level [I]. running = 0; 3 taskctl-> level [I]. now = 0; 4} 5 task = task_alloc (); 6 task-> flags = 2;/* Indicates */7 task-> priority = 2; // task priority // 0.02s timer 8 Task-> level = 0;/* Layer 2 */9 task_add (task); // Add 10 task_switchsub () in level (); /* determines the level to switch to when the task is switched */11 load_tr (Task-> SEL); 12 // writes this value to the tr register, because the gdt of the current running task is defined as number 3, the tr Register enables the CPU to remember which task is currently running, the value of the tr register is automatically changed. Task register14 // when assigning values to tr, you must multiply the gdt number by 815 task_timer = timer_alloc (); 16 timer_settime (task_timer, task-> priority );
>_<"Before changing, the next task to be switched in task_run is fixed, but now it is different. If this task starts a task with a higher level than the task in the current activity, in this case, you need to switch to a higher priority level unconditionally during the next task switchover. In addition, if the level in the current task is lowered, you have to put the level of other level first tasks in front. To sum up, we need to check the level before the next switchover, so we set lv_change to 1.
1 void task_run (struct task * task, int level, int priority) 2 {3 if (level <0) {4 level = task-> level; /* do not change level */5} 6 if (Priority> 0) {7 task-> priority = priority; 8} 9 10 if (Task-> flags = 2 & task-> level! = Level) {/* change the level in the activity */11 task_remove (task);/* the flag value will change to 1 after execution, the following statement will also be executed */12} 13 if (Task-> flags! = 2) {14/* wake up from sleep */15 task-> level = level; 16 task_add (task); 17} 18 19 taskctl-> lv_change = 1; /* Check the level */20 return; 21} For the next task switch}
>_<"Therefore, in the task switchover, if the above level changes, we need to change the 10th ~ Set the current level in row 11. The following figure shows the normal switchover ~
1 void task_switch (void) 2 {3 struct tasklevel * TL = & taskctl-> level [taskctl-> now_lv]; // Level 4 struct task * new_task of the current task, * now_task = TL-> tasks [TL-> now]; 5 TL-> now ++; 6 if (TL-> now = TL-> running) {7 TL-> now = 0; 8} 9 If (taskctl-> lv_change! = 0) {// 10 task_switchsub () is changed between levels. // this parameter is used to determine the level to switch to during the task and locate the level from the beginning, find the task in the first level and return 11 TL = & taskctl-> level [taskctl-> now_lv]; 12} 13 new_task = TL-> tasks [TL-> now]; 14 timer_settime (task_timer, new_task-> priority); 15 if (new_task! = Now_task) {16 farjmp (0, new_task-> SEL); 17} 18 return; 19}
>_<"The following task suspension is also relatively simple ~
1 void task_sleep (struct task * task) 2 {3 struct task * now_task; 4 If (Task-> flags = 2) {5/* If the statement is active */6 now_task = task_now (); 7 task_remove (task);/* If the statement is executed, flags will be set to 1. Remove is to delete a */8 If (task = now_task) from the array) {9/* if you want to sleep yourself, you need to switch the task */10 task_switchsub (); 11 now_task = task_now (); /* obtain the value of the current task after setting */12 farjmp (0, now_task-> SEL); 13} 14} 15 return; 16}
>_<"In the main function, perform the following settings for the tasks in the four windows:
1 task_a = task_init (memman); // initialize task a // initialize Task Manager. task_init returns its own constructor address, which is saved to the FIFO. task2 FIFO. task = task_a; // can be automatically managed. The task to be awakened (// records the sleep Task Name) 3 task_run (task_a, 1, 2 ); // set level of task a to 1, priority 2, and level of Task B to 2, so the priority is low
1 task_run (task_ B [I], 2, I + 1); // start the task, level2, priority 1, 2, 3
3. Related Links
The priority is not added, but the Multi-Window link 13C: http://pan.baidu.com/s/1nt4w6RB with the average allocation mode
Multi-Window link 13E: http://pan.baidu.com/s/1eQw3sQY when adding level mode priority
[Self-made simple operating system] 8. Multi-task (3) -- Multi-Window and priority