<!-- {%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

### Observation
:::info
1. process的執行時間跟Priority依照我們的觀察是沒有相關性的
2. 第一行的priority is not adjusted依照程式邏輯是因為還沒賦值給current->my_fixed_prioity(我們也利用printk來驗證我們的想法)
:::spoiler


:::
## 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變數,避免程式發生錯誤。
:::

### core-y新增我們新的system call名稱 set_process_priority

### syscall_64.tbl新增system call編號為451

### syscalls.h新增syscall的prototype
