Linux System Calls' Forum, #6:(第97號系統服務) sys_setpriority

jollen 發表於 October 20, 2006 7:38 PM

了解 sys_getpriority() 後,要看懂 sys_setpriority() 就不是問題了。

97 sys_setpriority linux/kernel/sys.c
類別:Systems
原型宣告:long sys_setpriority(int which, int who, int niceval);
用途說明:變更 process 的排程優先序(Priority)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_setpriority(int which, int who, int niceval)
{
	struct task_struct *g, *p;
	struct user_struct *user;
	int error = -EINVAL;

	if (which > 2 || which < 0)
		goto out;

	/* normalize: avoid signed division (rounding problems) */
	error = -ESRCH;
	if (niceval < -20)
		niceval = -20;
	if (niceval > 19)
		niceval = 19;

	read_lock(&tasklist_lock);
	switch (which) {
		case PRIO_PROCESS:
			if (!who)
				who = current->pid;
			p = find_task_by_pid(who);
			if (p)
				error = set_one_prio(p, niceval, error);
			break;
		case PRIO_PGRP:
			if (!who)
				who = process_group(current);
			do_each_task_pid(who, PIDTYPE_PGID, p) {
				error = set_one_prio(p, niceval, error);
			} while_each_task_pid(who, PIDTYPE_PGID, p);
			break;
		case PRIO_USER:
			user = current->user;
			if (!who)
				who = current->uid;
			else
				if ((who != current->uid) && !(user = find_user(who)))
					goto out_unlock;	/* No processes for this user */

			do_each_thread(g, p)
				if (p->uid == who)
					error = set_one_prio(p, niceval, error);
			while_each_thread(g, p);
			if (who != current->uid)
				free_uid(user);		/* For find_user() */
			break;
	}
out_unlock:
	read_unlock(&tasklist_lock);
out:
	return error;
}

Jollen 的說明

程式一開始先判斷 which 參數的正確性,並且將 user process 所指定的 nice 值限定在 [-20..19] 的範圍內:

	if (which > 2 || which < 0)
		goto out;

	/* normalize: avoid signed division (rounding problems) */
	error = -ESRCH;
	if (niceval < -20)
		niceval = -20;
	if (niceval > 19)
		niceval = 19;

底下我們來討論 PRIO_PROCESSPRIO_PGRP 參數的實作,強烈建議您先行閱讀本文最後所整理的文章,再回頭來看以下的說明,才能得到最佳學習效果。

變更 priority:PRIO_PROCESS

主要的程式片斷如下:

	case PRIO_PROCESS:   /* 請看 1. */
		if (!who)
			who = current->pid;   /* 請看 1. */
		p = find_task_by_pid(who);   /* 請看 2. */
		if (p)   /* 請看 3. */
			error = set_one_prio(p, niceval, error);   /* 請看 3. */
		break;

說明:

  1. which = PRIO_PROCESS,則 who 的值就是 process ID。因為 who 不能為 0,所以如果 who 是 0 的話,就指定為 current 的 PID。
  2. find_task_by_pid() 是 kernel API,用來取得 PID 的 process descriptor。我們已經學過了!
  3. 如果 p 不是 NULL,就呼叫 set_one_prio(),修改 p 的「nice 值」為 niceval

變更 priority:PRIO_PGRP

主要的程式片斷如下:

	case PRIO_PGRP:
		if (!who)
			who = process_group(current);
		do_each_task_pid(who, PIDTYPE_PGID, p) {   /* 請看 1. */
			error = set_one_prio(p, niceval, error);   /* 請看 1. */
		} while_each_task_pid(who, PIDTYPE_PGID, p);   /* 請看 1. */
		break;

說明:

  1. 在迴圈裡,逐一修改 process group 裡的 process,將其優先序變更為 niceval。這樣的迴圈,在 sys_getpriority() 也看過一次!

二段 kernel code 都呼叫到此 kernel API:

  • kernel API - set_one_prio():傳入 process descriptor 與新的 nice 值,將 process 的 priorioty 做變更。
TIP
  • "*_PGRP"(process group)是 kernel 2.4 的 sematics,「current->pgrp」是 kernel 2.4 的寫法。我們未來有機會的話再做說明。

 

跟上我們的腳步:請讀以下的文章,再看這篇日記!

Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue

您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw