---
# System prepended metadata

title: Linux Priority Setting

---

<!-- {%hackmd theme-dark %} -->
# Linux Project 2
111522125 童柏堯
111522140 陳政瑋
111525026 鄧皓

## Kernel & OS version
* 作業系統： ubuntu 22.04
* Kernel 版本： 5.15.137

## 新增system call

### system call
:::info
此system call的用意在於變更目前的process的priority，而此system call目的是想去觀察process的priority在101~139(completely fair scheduling class)的變化中，是否會對process的execution time 照成影響，也就是normal tasks之間priority對於process exection time的關係。
:::
```Linux
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/sched.h>

SYSCALL_DEFINE1(set_process_priority, int, x) {
    // Check if x is within the valid range (101 to 139)
        printk("my_fixed_priority: %d\n", current->my_fixed_priority);
        printk("my_fixed_priority x: %d\n", x);
        if (x < 101 || x > 139){
                return 0;
        }

        else {
            current->my_fixed_priority = x;
            return 1; // System call completed successfully
        }
}
```

### execution c file
:::info
整個code的目的是計算process各別在priority 101~139時，所花費的執行時間。set_process_priority(priority)函式使用到了我們所新增的syscall，在更改完priority後，就會開始計算process的execution time。
:::
```C=
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>


#define TOTAL_ITERATION_NUM  100000000
#define NUM_OF_PRIORITIES_TESTED  40

void * set_process_priority(int priority){
        long int sys = syscall(451, priority);
}


int main()
{
        int index=0;
        int priority,i;
        struct timeval start[NUM_OF_PRIORITIES_TESTED], end[NUM_OF_PRIORITIES_TESTED];

        gettimeofday(&start[index], NULL);           //begin
        for(i=1;i<=TOTAL_ITERATION_NUM;i++)
                rand();
        gettimeofday(&end[index], NULL);             //end

         /*================================================================================*/

         for(index=1, priority=101;priority<=139;++priority,++index)
         {

                if(!set_process_priority(priority))
                        printf("Cannot set priority %d.\n", priority);

                gettimeofday(&start[index], NULL);           //begin
                for(i=1;i<=TOTAL_ITERATION_NUM;i++)
                        rand();
                gettimeofday(&end[index], NULL);             //end
          }

          /*================================================================================*/

          printf("The process spent %ld uses to execute when priority is not adjusted.\n", ((end[0].tv_sec * 1000000 + end[0].tv_usec) - (start[0].tv_sec * 1000000 + start[0].tv_usec)));

          for(i=1;i<=NUM_OF_PRIORITIES_TESTED-1;i++)
                printf("The process spent %ld uses to execute when priority is %d.\n", ((end[i].tv_sec * 1000000 + end[i].tv_usec) - (start[i].tv_sec * 1000000 + start[i].tv_usec)), i+100);
}
```
### outupt
![image](https://hackmd.io/_uploads/SkJDwj5_6.png)


### Observation
:::info
1. process的執行時間跟Priority依照我們的觀察是沒有相關性的
2. 第一行的priority is not adjusted依照程式邏輯是因為還沒賦值給current->my_fixed_prioity(我們也利用printk來驗證我們的想法)
:::spoiler
![螢幕擷取畫面 2024-01-05 160517](https://hackmd.io/_uploads/rkl7arSu6.png)
![螢幕擷取畫面 2024-01-05 160531](https://hackmd.io/_uploads/HJ776HH_T.png)
:::


## kernel需要更改的地方

:::info
在kernel/sched/core.c 賦值，利用system call傳入的value 給新增的task_struct欄位: ==my_fixed_priority== ，再將my_fixed_priority賦值給static_prio。
**line 50為新增指令**
***
:::success 
**code相關資料**
1. prepare_task_switch(rq, prev, next) & finish_task_switch(prev):為下一次任務切換做好準備工作，以確保系統可以順利地進行context switch，並確保各個任務能夠正確地執行。
2. process address space切換(中間if_else部分):context switch時，處理當前process和即將要執行的process之間的page切換和memory management。
3. rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP):清除rq的時鐘更新標誌。
4. prepare_lock_switch(rq, next, rf):確保在context switch期間不會出現race condition。
5. switch_to(prev, next, prev):切換是在 switch_to 函數中完成的。 保存原process所有的register，恢復新process所有register，執行新process。
:::
```Linux=
static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
               struct task_struct *next, struct rq_flags *rf)
{
        prepare_task_switch(rq, prev, next);

        /*
         * For paravirt, this is coupled with an exit in switch_to to
         * combine the page table reload and the switch backend into
         * one hypercall.
         */
         
        
        arch_start_context_switch(prev);

        /*
         * kernel -> kernel   lazy + transfer active
         *   user -> kernel   lazy + mmgrab() active
         *
         * kernel ->   user   switch + mmdrop() active
         *   user ->   user   switch
         */
        if (!next->mm) {                                // to kernel
                enter_lazy_tlb(prev->active_mm, next);

                next->active_mm = prev->active_mm;
                if (prev->mm)                           // from user
                        mmgrab(prev->active_mm);
                else
                        prev->active_mm = NULL;
        } else {                                        // to user
                membarrier_switch_mm(rq, prev->active_mm, next->mm);
                /*
                 * sys_membarrier() requires an smp_mb() between setting
                 * rq->curr / membarrier_switch_mm() and returning to userspace.
                 *
                 * The below provides this either through switch_mm(), or in
                 * case 'prev->active_mm == next->mm' through
                 * finish_task_switch()'s mmdrop().
                 */
                switch_mm_irqs_off(prev->active_mm, next->mm, next);

                if (!prev->mm) {                        // from kernel
                        /* will mmdrop() in finish_task_switch(). */
                        rq->prev_mm = prev->active_mm;
                        prev->active_mm = NULL;
                }
        }

        prev->static_prio=prev->my_fixed_priority;
        
        rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);

        prepare_lock_switch(rq, next, rf);

        /* Here we just switch the register state and the stack. */
        switch_to(prev, next, prev);
        barrier();

        return finish_task_switch(prev);
}
```

### 在 struct task_struct新增的feild
:::warning
我們想在process descriptior中新增欄位(變數)，因此在```include/linux/sched.h```找到了struct task_struct，由於linux在這部分程式碼的撰寫上是直接使用offset去編譯，因此為了不影響整體程式的運行，我們找到此task_struct最後的欄位位置，新增my_fixed_priority變數，避免程式發生錯誤。
:::
![螢幕擷取畫面 2024-01-05 160657](https://hackmd.io/_uploads/B13LTrB_a.png)

### core-y新增我們新的system call名稱 set_process_priority
![螢幕擷取畫面 2024-01-05 160745](https://hackmd.io/_uploads/S1xuaBH_6.png)

### syscall_64.tbl新增system call編號為451
![螢幕擷取畫面 2024-01-05 160835](https://hackmd.io/_uploads/ByFdaHH_6.png)

### syscalls.h新增syscall的prototype
![螢幕擷取畫面 2024-01-05 160909](https://hackmd.io/_uploads/BkGKaHrda.png)
