Commit c18258c6f0848f97e85287f6271c511a092bb784
Committed by
Linus Torvalds
1 parent
35fa2048ab
Exists in
master
and in
20 other branches
[PATCH] pid: Implement transfer_pid and use it to simplify de_thread
In de_thread we move pids from one process to another, a rather ugly case. The function transfer_pid makes it clear what we are doing, and makes the action atomic. This is useful we ever want to atomically traverse the process group and session lists, in a rcu safe manner. Even if the atomic properties this change should be a win as transfer_pid should be less code to execute than executing both attach_pid and detach_pid, and this should make de_thread slightly smaller as only a single function call needs to be emitted. The only downside is that the code might be slower to execute as the odds are against transfer_pid being in cache. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 15 additions and 7 deletions Side-by-side Diff
fs/exec.c
... | ... | @@ -696,22 +696,19 @@ |
696 | 696 | */ |
697 | 697 | |
698 | 698 | /* Become a process group leader with the old leader's pid. |
699 | - * Note: The old leader also uses thispid until release_task | |
699 | + * The old leader becomes a thread of the this thread group. | |
700 | + * Note: The old leader also uses this pid until release_task | |
700 | 701 | * is called. Odd but simple and correct. |
701 | 702 | */ |
702 | 703 | detach_pid(current, PIDTYPE_PID); |
703 | 704 | current->pid = leader->pid; |
704 | 705 | attach_pid(current, PIDTYPE_PID, current->pid); |
705 | - attach_pid(current, PIDTYPE_PGID, current->signal->pgrp); | |
706 | - attach_pid(current, PIDTYPE_SID, current->signal->session); | |
706 | + transfer_pid(leader, current, PIDTYPE_PGID); | |
707 | + transfer_pid(leader, current, PIDTYPE_SID); | |
707 | 708 | list_replace_rcu(&leader->tasks, ¤t->tasks); |
708 | 709 | |
709 | 710 | current->group_leader = current; |
710 | 711 | leader->group_leader = current; |
711 | - | |
712 | - /* Reduce leader to a thread */ | |
713 | - detach_pid(leader, PIDTYPE_PGID); | |
714 | - detach_pid(leader, PIDTYPE_SID); | |
715 | 712 | |
716 | 713 | current->exit_signal = SIGCHLD; |
717 | 714 |
include/linux/pid.h
... | ... | @@ -76,6 +76,8 @@ |
76 | 76 | enum pid_type type, int nr)); |
77 | 77 | |
78 | 78 | extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); |
79 | +extern void FASTCALL(transfer_pid(struct task_struct *old, | |
80 | + struct task_struct *new, enum pid_type)); | |
79 | 81 | |
80 | 82 | /* |
81 | 83 | * look up a PID in the hash table. Must be called with the tasklist_lock |
kernel/pid.c
... | ... | @@ -252,6 +252,15 @@ |
252 | 252 | free_pid(pid); |
253 | 253 | } |
254 | 254 | |
255 | +/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ | |
256 | +void fastcall transfer_pid(struct task_struct *old, struct task_struct *new, | |
257 | + enum pid_type type) | |
258 | +{ | |
259 | + new->pids[type].pid = old->pids[type].pid; | |
260 | + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); | |
261 | + old->pids[type].pid = NULL; | |
262 | +} | |
263 | + | |
255 | 264 | struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type) |
256 | 265 | { |
257 | 266 | struct task_struct *result = NULL; |