Skip to content

[Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] introduce __next_thread(), change next_thread() & kill task_struct->thread_group#1868

Merged
opsiff merged 5 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-06-16-task-struct
Jun 16, 2026
Merged

[Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] introduce __next_thread(), change next_thread() & kill task_struct->thread_group#1868
opsiff merged 5 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-06-16-task-struct

Conversation

@opsiff

@opsiff opsiff commented Jun 16, 2026

Copy link
Copy Markdown
Member

Link: https://lore.kernel.org/all/20230824143142.GA31222@redhat.com/T/#u

Hello,

After document-while_each_thread-change-first_tid-to-use-for_each_thread.patch
in mm tree + this series

  1. We have only one lockless user of next_thread(), task_group_seq_get_next().
    I think it should be changed too.

  2. We have only one user of task_struct->thread_group, thread_group_empty().
    The next patches will change thread_group_empty() and kill ->thread_group.

Oleg.

Link: https://lore.kernel.org/all/20230826111406.GA23238@redhat.com/T/#u

On top of

[PATCH 0/2] introduce __next_thread(), change next_thread()
https://lore.kernel.org/all/20230824143112.GA31208@redhat.com/

Next: audit the while_each_thread() users.

Oleg.

Summary by Sourcery

Refactor kernel thread group iteration to use the shared thread_head/thread_node list and remove the deprecated thread_group list linkage.

Enhancements:

  • Introduce __next_thread() as an internal helper that returns the next thread in a thread group or NULL at the end of the list.
  • Redefine next_thread() and thread_group_empty() to operate on the signal->thread_head/thread_node list instead of a separate thread_group list.
  • Remove the thread_group list_head from task_struct and all associated initialization and unlinking paths.
  • Update the GDB tasks.py helper to iterate threads using the thread_head/thread_node list instead of the removed thread_group linkage.
  • Simplify next_tid() to rely directly on __next_thread() for thread group traversal.

oleg-nesterov and others added 5 commits June 16, 2026 18:00
mainline inclusion
from mainline-v6.7-rc1
category: performance

Patch series "introduce __next_thread(), change next_thread()".

After commit dce8f8e ("document while_each_thread(), change
first_tid() to use for_each_thread()") + this series

1. We have only one lockless user of next_thread(), task_group_seq_get_next().
   I think it should be changed too.

2. We have only one user of task_struct->thread_group, thread_group_empty().
   The next patches will change thread_group_empty() and kill ->thread_group.

This patch (of 2):

next_tid(start) does:

	rcu_read_lock();
	if (pid_alive(start)) {
		pos = next_thread(start);
		if (thread_group_leader(pos))
			pos = NULL;
		else
			get_task_struct(pos);

it should return pos = NULL when next_thread() wraps to the 1st thread
in the thread group, group leader, and the thread_group_leader() check
tries to detect this case.

But this can race with exec. To simplify, suppose we have a main thread
M and a single sub-thread T, next_tid(T) should return NULL.

Now suppose that T execs. If next_tid(T) is called after T changes the
leadership and before it does release_task() which removes the old leader
from list, then next_thread() returns M and thread_group_leader(M) = F.

Lockless use of next_thread() should be avoided. After this change only
task_group_seq_get_next() does this, and I believe it should be changed
as well.

Link: https://lkml.kernel.org/r/20230824143112.GA31208@redhat.com
Link: https://lkml.kernel.org/r/20230824143142.GA31222@redhat.com
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit 33a9813)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.7-rc1
category: performance

This relies on fact that group leader is always the 1st entry in the
signal->thread_head list.

With or without this change, if the lockless next_thread(last_thread)
races with exec it can return the old or the new leader.

We are almost ready to kill task->thread_group, after this change its
only user is thread_group_empty().

Link: https://lkml.kernel.org/r/20230824143201.GB31222@redhat.com
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit d639cf4)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.7-rc1
category: performance

Patch series "kill task_struct->thread_group".

This patch (of 2):

It could use list_is_singular() but this way it is cheaper.  Plus the
thread_group_leader() check makes it clear that thread_group_empty() can
only return true if p is a group leader.  This was not immediately obvious
before this patch.

task_struct->thread_group no longer has users, it can die.

Link: https://lkml.kernel.org/r/20230826111200.GA22982@redhat.com
Link: https://lkml.kernel.org/r/20230826111406.GA23238@redhat.com
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit e34a35e)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.7-rc1
category: performance

The last user was removed by the previous patch.

Link: https://lkml.kernel.org/r/20230826111409.GA23243@redhat.com
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit 8e1f385)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.7-rc5
category: bugfix

Since commit 8e1f385 ("kill task_struct->thread_group") remove
the thread_group, we will encounter below issue.

(gdb) lx-ps
      TASK          PID    COMM
0xffff800086503340   0   swapper/0
Python Exception <class 'gdb.error'>: There is no member named thread_group.
Error occurred in Python: There is no member named thread_group.

We use signal->thread_head to iterate all threads instead.

[Kuan-Ying.Lee@mediatek.com: v2]
  Link: https://lkml.kernel.org/r/20231129065142.13375-2-Kuan-Ying.Lee@mediatek.com
Link: https://lkml.kernel.org/r/20231127070404.4192-2-Kuan-Ying.Lee@mediatek.com
Fixes: 8e1f385 ("kill task_struct->thread_group")
Signed-off-by: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Cc: Chinwen Chang <chinwen.chang@mediatek.com>
Cc: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Qun-Wei Lin <qun-wei.lin@mediatek.com>
Cc: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit 854f276)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from opsiff. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors thread-group iteration to use the existing signal->thread_head/thread_node list, introduces __next_thread() for raw iteration, changes next_thread() semantics to wrap to the group leader, and removes the task_struct->thread_group list and its users in core kernel, proc, fork, exit, and GDB scripts.

File-Level Changes

Change Details Files
Introduce __next_thread() helper and change next_thread() semantics to wrap to the thread-group leader using signal->thread_head/thread_node.
  • Add __next_thread() that walks the thread list using list_next_or_null_rcu() on signal->thread_head/thread_node.
  • Redefine next_thread() to call __next_thread() and fall back to p->group_leader when reaching the end of the list.
  • Clarify that __next_thread() returns NULL when the input task is the last thread in the group.
include/linux/sched/signal.h
Redefine thread_group_empty() to use thread_node/thread_head and thread_group_leader() instead of task_struct->thread_group list.
  • Update thread_group_empty() to check thread_group_leader(p) and list_is_last(&p->thread_node, &p->signal->thread_head).
include/linux/sched/signal.h
Remove task_struct->thread_group list_head field and all associated initialization and list manipulation, relying solely on thread_node/signal->thread_head for thread-group membership.
  • Delete thread_group list_head from struct task_struct.
  • Remove INIT_LIST_HEAD(&p->thread_group) from process initialization.
  • Drop list_add_tail_rcu() and list_del_rcu() calls that maintained the thread_group list in fork and exit paths.
  • Stop initializing init_task.thread_group in init_task.c.
include/linux/sched.h
kernel/fork.c
kernel/exit.c
init/init_task.c
Adapt /proc TID iteration to the new __next_thread() helper and non-wrapping semantics.
  • Change next_tid() to use __next_thread(start) instead of next_thread(), and only take a reference if a next thread exists.
  • Rely on __next_thread() returning NULL at the end of the group instead of checking thread_group_leader().
fs/proc/base.c
Update GDB Python task iteration helper to iterate threads via signal->thread_head/thread_node using the generic list helpers instead of task_struct->thread_group.
  • Import linux.lists module in tasks.py.
  • Replace nested loops that walked thread_group and tasks lists with iteration over signal->thread_head via list_for_each_entry(thread_head, task_ptr_type, 'thread_node').
  • Simplify outer task list advancement to use only the tasks list while yielding each thread via thread_node.
scripts/gdb/linux/tasks.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In scripts/gdb/linux/tasks.py, the new task_lists() implementation will traverse thread_head for every task in the tasks list, which will cause threads to be yielded multiple times for multi-threaded groups; consider restricting the inner traversal to group leaders only (e.g., guard with a group_leader check) or otherwise ensuring each thread group is walked exactly once as before.
  • The change of next_thread() (and __next_thread()) to take a non-const struct task_struct * parameter weakens the previous const-correctness; consider keeping the parameter const and using an internal cast around list_next_or_null_rcu() to avoid unnecessarily widening the API surface for mutation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In scripts/gdb/linux/tasks.py, the new task_lists() implementation will traverse thread_head for every task in the tasks list, which will cause threads to be yielded multiple times for multi-threaded groups; consider restricting the inner traversal to group leaders only (e.g., guard with a group_leader check) or otherwise ensuring each thread group is walked exactly once as before.
- The change of next_thread() (and __next_thread()) to take a non-const struct task_struct * parameter weakens the previous const-correctness; consider keeping the parameter const and using an internal cast around list_next_or_null_rcu() to avoid unnecessarily widening the API surface for mutation.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread include/linux/sched.h
/* PID/PID hash table linkage. */
struct pid *thread_pid;
struct hlist_node pid_links[PIDTYPE_MAX];
struct list_head thread_group;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about kabi

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about kabi

don`t worry it, these patches sync from internal repo.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors thread-group iteration to rely solely on signal->thread_head / task_struct->thread_node, introducing __next_thread() and removing the deprecated task_struct->thread_group linkage.

Changes:

  • Add __next_thread() and rework next_thread() / thread_group_empty() to use signal->thread_head + thread_node.
  • Remove all initialization and unlinking of task_struct->thread_group (and drop the field from task_struct).
  • Update /proc TID traversal and the GDB tasks.py helper to iterate via thread_head / thread_node.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
scripts/gdb/linux/tasks.py Switches GDB task/thread enumeration to signal->thread_head / thread_node.
kernel/fork.c Removes thread_group initialization/linking; relies on thread_node insertion into signal->thread_head.
kernel/exit.c Removes thread_group unlinking; keeps unlinking via thread_node.
init/init_task.c Drops init_task.thread_group static initialization.
include/linux/sched/signal.h Introduces __next_thread(), updates next_thread() and thread_group_empty() to use thread_head / thread_node.
include/linux/sched.h Removes task_struct::thread_group.
fs/proc/base.c Updates next_tid() to use __next_thread() to avoid wraparound semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 27 to +30
while True:
while True:
yield t
thread_head = t['signal']['thread_head']
for thread in lists.list_for_each_entry(thread_head, task_ptr_type, 'thread_node'):
yield thread
@opsiff opsiff merged commit 000b44f into deepin-community:linux-6.6.y Jun 16, 2026
14 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants