# by Stanley
## task_struct 是什麼, 在哪?
在linux/sched.h裡面定義了task_struct,裡面定義了一個task/process所有的內容
## sched.h 我只放與作業有關的內容
```c
#include <uapi/linux/sched.h>
#include <asm/current.h>
#include <linux/thread_info.h>
...
struct task_struct {
struct thread_info thread_info;
unsigned int __state;
...
randomized_struct_fields_start
void *stack;
...
unsigned int flags;
unsigned int ptrace;
pid_t pid;
pid_t tgid;
...
int prio;
int static_prio; // 靜態優先度
int normal_prio;
unsigned int rt_priority;
struct task_struct __rcu *parent; // 有可能重新配給新的parent
struct task_struct __rcu *real_parent; // 真正被fork出來的parent
struct list_head children;
struct list_head sibling;
start_time; // start time
bootstart_time
utime; // user time
stime; // system time
...
};
...
static inline int task_nice(const struct task_struct *p) {
return PRIO_TO_NICE((p)->static_prio);
}
#ifdef CONFIG_THREAD_INFO_IN_TASK
# define task_thread_info(task) (&(task)->thread_info)
#elif !defined(__HAVE_THREAD_FUNTIONS)
# define task_thread_info(task) ((struct thread_info *)(task)->stack)
```

## deep into <thread_info.h>
<linux/thread_info.h> 路徑在linux-x.x.x/include/linux
```c
#include <asm/thread_info.h>
struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
unsigned long syscall_work; /* SYSCALL_WORK_ flags */
u32 status; /* thread synchronous flags */
#ifdef CONFIG_SMP
u32 cpu; /* current CPU */
#endif
};
#define current_thread_info() ((struct thread_info *)current)
```
這邊的current指向一個stack當中的task_struct的結構
## 此current是什麼?
在<include/asm-generic/current.h>當中有這麼一段code
```c
#include <linux/thread_info.h>
#define get_current() (current_thread_info()->task)
#define current get_current()
```
我們呼叫的current其實就是一個
```c
struct task_struct *task
```
## uaccess.h
需要從kernel把struct傳入user space,就需要用到copy_to_user的system call,實際是用_copy_to_user去實作的,內容細節會用到
```c
unsigned long copy_to_user(void *to, const void *from, unsigned long n);
```
可以看到這部分是直接傳bit當作parameter(帶void型別)
>**_NOTE:_** copy_to_user 為x86的函數,跟arch版本的會不同,別用錯了
## linux list
```c
struct list_head {
struct list_head *next, *prev;
};
#define list_first_entry(head, type, member) \
list_entry((head)->next, type, member)
#define list_last_entry(head, type, member) \
list_entry((head)->prev, type, member)
```
例如取得task這個process/thread所生的children也就是`task_struct`當中`list_head children`中最新的child,會是children中最後一個,可以使用`list_last_entry(¤t->children, struct task_struct, children)`
記得這邊的為task_struct current
# 開始實作吧~
## step1 我的entry 464改成你們自己的~
cd /usr/src/linux-6.10.9/arch/x86/entry/syscall
sudo gedit syscall_64.tbl
加入一個system call entry


## step2
cd /usr/src/linux-6.10.9/include/linux
新增header
sudo gedit printfo.h

cd /usr/src/linux-6.10.9/kernel
gedit sys.c
### 加入system call define
確認uaccess.h,不然copy_to_user權限檢查的時候可能編譯錯誤
string.h : strncpy 不要用strcpy很容易overflow
printfo.h : 作業要用到的struct


## step3
cd /usr/src/linux-6.10.9/include/linux
sudo gedit syscalls.h
加入header "linux/prinfo.h"

往下加入syscall linkage

## step4 make
回到linux-x.x.x路徑
sudo make -j8
如果這時候編譯的時候有bug
再po群組問也可以!
若沒問題安裝編譯好的image
sudo make install
reboot
## step5 已經重啟選好編譯完的kernel版本
隨便找個路徑測試system call
我是在/home底下測試

# Output
* nice值應該要藉於-19~20
* 如果是用static_prio輸出結果會是120,但這個並不是我們要的,我們要把static priority轉換成nice value,這個API在sched.h裡面可以找到,傳入task_struct型別的pointer,會從task當中把static_prio轉換成nice value then return。
* 若轉換成nice則這次的作業的值應該是 nice = 0
* 再來我們原本的shell視窗
* 可以嘗試用sudo ./test2 或是 ./test2 可以查看到uid不一樣 uid = 0為supervisor
* 再多開一個shell測試一次,比對看看


# 總結
還是希望去github找相對應的kernel版本來看source code比較快,可以查到想要的結構、函數內部結構是怎麼寫的,Linux某些函數被包裝得很隱密,必須先了解linux怎麼實作的再來做會比較容易。
# Reference
[task_struct講解](https://www.cnblogs.com/yungyu16/p/13023982.html)
[task struct mapping 技術](https://hackmd.io/@PIFOPlfSS3W_CehLxS3hBQ/S14tx4MqP)
https://hackmd.io/@sakuraiiii/r1gFubKkF)
[關於linux list_head, list這邊說明得很清楚 : Linux list wrapper](https://hackmd.io/@RinHizakura/HkEuhNwGO)
[nice val](https://deepinout.com/linux-kernel-api/linux-kernel-api-process-scheduling/linux-kernel-api-task_nice.html)