162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Function to determine if a thread group is single threaded or not 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci * - Derived from security/selinux/hooks.c 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/sched/signal.h> 962306a36Sopenharmony_ci#include <linux/sched/task.h> 1062306a36Sopenharmony_ci#include <linux/sched/mm.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * Returns true if the task does not share ->mm with another thread/process. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_cibool current_is_single_threaded(void) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct task_struct *task = current; 1862306a36Sopenharmony_ci struct mm_struct *mm = task->mm; 1962306a36Sopenharmony_ci struct task_struct *p, *t; 2062306a36Sopenharmony_ci bool ret; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (atomic_read(&task->signal->live) != 1) 2362306a36Sopenharmony_ci return false; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (atomic_read(&mm->mm_users) == 1) 2662306a36Sopenharmony_ci return true; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci ret = false; 2962306a36Sopenharmony_ci rcu_read_lock(); 3062306a36Sopenharmony_ci for_each_process(p) { 3162306a36Sopenharmony_ci if (unlikely(p->flags & PF_KTHREAD)) 3262306a36Sopenharmony_ci continue; 3362306a36Sopenharmony_ci if (unlikely(p == task->group_leader)) 3462306a36Sopenharmony_ci continue; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci for_each_thread(p, t) { 3762306a36Sopenharmony_ci if (unlikely(t->mm == mm)) 3862306a36Sopenharmony_ci goto found; 3962306a36Sopenharmony_ci if (likely(t->mm)) 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * t->mm == NULL. Make sure next_thread/next_task 4362306a36Sopenharmony_ci * will see other CLONE_VM tasks which might be 4462306a36Sopenharmony_ci * forked before exiting. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci smp_rmb(); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci ret = true; 5062306a36Sopenharmony_cifound: 5162306a36Sopenharmony_ci rcu_read_unlock(); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return ret; 5462306a36Sopenharmony_ci} 55