From patchwork Thu Apr 25 19:00:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Fernandes X-Patchwork-Id: 10917631 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 30FCC1390 for ; Thu, 25 Apr 2019 19:00:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 204AD28CE3 for ; Thu, 25 Apr 2019 19:00:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 13DEF28CF3; Thu, 25 Apr 2019 19:00:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4D86028CE3 for ; Thu, 25 Apr 2019 19:00:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726206AbfDYTA2 (ORCPT ); Thu, 25 Apr 2019 15:00:28 -0400 Received: from mail-pg1-f195.google.com ([209.85.215.195]:36435 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725900AbfDYTA2 (ORCPT ); Thu, 25 Apr 2019 15:00:28 -0400 Received: by mail-pg1-f195.google.com with SMTP id 85so307748pgc.3 for ; Thu, 25 Apr 2019 12:00:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=joelfernandes.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=FiYXLK7Tf5Qbjvl0oGyu8yhpajL4qMdWQdIN0gBiHWs=; b=D9amvk7URcyGLGrVBPmMAbroP7VJp4xohyxcmkx8tXZAdg0kKAeqx3rRDe/s5u6/jG YgDz7fpcibNSCh8AwefMwo+hMIAZJ2GadMgwqz8uzbMyQX1Xsrjp/0rFopnAwx3FJ0HR eHMHm/B/eS/f3QAM3+30ukJYQmU5CV5Eg0gB8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=FiYXLK7Tf5Qbjvl0oGyu8yhpajL4qMdWQdIN0gBiHWs=; b=jym736UpXWjzUeLwAWDtAfdpMw0VtMFFm8mHHhgyMOhbc7ddCkC8FwZy+fqgX+fUY3 eUfLd0M6RFVNCl8/7+ecoErb6AR1V2AteRjH6fE58SfBryxCT0oxbn9m8l32VGGZwSCB HDowKOa813Gvh+/8rhAdW9Wn+/3Cq0fhkrefqdvE1IIz1pTruZvsAQpkrEImlyAqq+mS 9hc4iM7AvfpOofqwlZwcfmh2CMo5T0oC1OqC4mc5nRqVKazMtV9/etAnShIHepcWe1Dn WY0m9dMkWN2hh3p4nA/BrycfOE3SyV89iWcZbWwBBirJF7K+NO0xLvIn47dXa/eNjbCU V7qA== X-Gm-Message-State: APjAAAWC33kGMcvMUsFPcFV+MILJmL9FuJqxGNjHpKkRDkj3TfYrkM3h 9FP4LUE4N0w2FURWzGSHc4B7Sg== X-Google-Smtp-Source: APXvYqzkgYCDs6Gu24z3xReV3enQ2TUz2QLK6qjWhAZEZ6M4A5n0wqIx7MK7+z61SMaFkN5aOm8DBw== X-Received: by 2002:aa7:8052:: with SMTP id y18mr954369pfm.36.1556218827264; Thu, 25 Apr 2019 12:00:27 -0700 (PDT) Received: from joelaf.cam.corp.google.com ([2620:15c:6:12:9c46:e0da:efbf:69cc]) by smtp.gmail.com with ESMTPSA id o14sm25480683pgn.4.2019.04.25.12.00.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Apr 2019 12:00:26 -0700 (PDT) From: "Joel Fernandes (Google)" To: linux-kernel@vger.kernel.org Cc: "Joel Fernandes (Google)" , luto@amacapital.net, rostedt@goodmis.org, dancol@google.com, sspatil@google.com, christian@brauner.io, jannh@google.com, surenb@google.com, timmurray@google.com, Jonathan Kowalski , torvalds@linux-foundation.org, kernel-team@android.com, Andrew Morton , Arnd Bergmann , "Eric W. Biederman" , Greg Kroah-Hartman , Ingo Molnar , Jann Horn , linux-kselftest@vger.kernel.org, Michal Hocko , "Peter Zijlstra (Intel)" , Serge Hallyn , Shuah Khan , Stephen Rothwell , Thomas Gleixner , Tycho Andersen Subject: [PATCH v1 1/2] Add polling support to pidfd Date: Thu, 25 Apr 2019 15:00:09 -0400 Message-Id: <20190425190010.46489-1-joel@joelfernandes.org> X-Mailer: git-send-email 2.21.0.593.g511ec345e18-goog MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP pidfd are file descriptors referring to a process created with the CLONE_PIDFD clone(2) flag. Android low memory killer (LMK) needs pidfd polling support to replace code that currently checks for existence of /proc/pid for knowing that a process that is signalled to be killed has died, which is both racy and slow. The pidfd poll approach is race-free, and also allows the LMK to do other things (such as by polling on other fds) while awaiting the process being killed to die. It prevents a situation where a PID is reused between when LMK sends a kill signal and checks for existence of the PID, since the wrong PID is now possibly checked for existence. In this patch, we follow the same existing mechanism in the kernel used when the parent of the task group is to be notified (do_notify_parent). This is when the tasks waiting on a poll of pidfd are also awakened. We have decided to include the waitqueue in struct pid for the following reasons: 1. The wait queue has to survive for the lifetime of the poll. Including it in task_struct would not be option in this case because the task can be reaped and destroyed before the poll returns. 2. By including the struct pid for the waitqueue means that during de_thread(), the new thread group leader automatically gets the new waitqueue/pid even though its task_struct is different. Appropriate test cases are added in the second patch to provide coverage of all the cases the patch is handling. Andy had a similar patch [1] in the past which was a good reference however this patch tries to handle different situations properly related to thread group existence, and how/where it notifies. And also solves other bugs (waitqueue lifetime). Daniel had a similar patch [2] recently which this patch supercedes. [1] https://lore.kernel.org/patchwork/patch/345098/ [2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol@google.com/ Cc: luto@amacapital.net Cc: rostedt@goodmis.org Cc: dancol@google.com Cc: sspatil@google.com Cc: christian@brauner.io Cc: jannh@google.com Cc: surenb@google.com Cc: timmurray@google.com Cc: Jonathan Kowalski Cc: torvalds@linux-foundation.org Cc: kernel-team@android.com Co-developed-by: Daniel Colascione Signed-off-by: Joel Fernandes (Google) --- RFC -> v1: * Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/ * Updated selftests. * Renamed poll wake function to do_notify_pidfd. * Removed depending on EXIT flags * Removed POLLERR flag since semantics are controversial and we don't have usecases for it right now (later we can add if there's a need for it). include/linux/pid.h | 3 +++ kernel/fork.c | 33 +++++++++++++++++++++++++++++++++ kernel/pid.c | 2 ++ kernel/signal.c | 14 ++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/include/linux/pid.h b/include/linux/pid.h index 3c8ef5a199ca..1484db6ca8d1 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -3,6 +3,7 @@ #define _LINUX_PID_H #include +#include enum pid_type { @@ -60,6 +61,8 @@ struct pid unsigned int level; /* lists of tasks that use this pid */ struct hlist_head tasks[PIDTYPE_MAX]; + /* wait queue for pidfd notifications */ + wait_queue_head_t wait_pidfd; struct rcu_head rcu; struct upid numbers[1]; }; diff --git a/kernel/fork.c b/kernel/fork.c index 5525837ed80e..fb3b614f6456 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1685,8 +1685,41 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f) } #endif +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts) +{ + struct task_struct *task; + struct pid *pid; + int poll_flags = 0; + + /* + * tasklist_lock must be held because to avoid racing with + * changes in exit_state and wake up. Basically to avoid: + * + * P0: read exit_state = 0 + * P1: write exit_state = EXIT_DEAD + * P1: Do a wake up - wq is empty, so do nothing + * P0: Queue for polling - wait forever. + */ + read_lock(&tasklist_lock); + pid = file->private_data; + task = pid_task(pid, PIDTYPE_PID); + WARN_ON_ONCE(task && !thread_group_leader(task)); + + if (!task || (task->exit_state && thread_group_empty(task))) + poll_flags = POLLIN | POLLRDNORM; + + if (!poll_flags) + poll_wait(file, &pid->wait_pidfd, pts); + + read_unlock(&tasklist_lock); + + return poll_flags; +} + + const struct file_operations pidfd_fops = { .release = pidfd_release, + .poll = pidfd_poll, #ifdef CONFIG_PROC_FS .show_fdinfo = pidfd_show_fdinfo, #endif diff --git a/kernel/pid.c b/kernel/pid.c index 20881598bdfa..5c90c239242f 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns) for (type = 0; type < PIDTYPE_MAX; ++type) INIT_HLIST_HEAD(&pid->tasks[type]); + init_waitqueue_head(&pid->wait_pidfd); + upid = pid->numbers + ns->level; spin_lock_irq(&pidmap_lock); if (!(ns->pid_allocated & PIDNS_ADDING)) diff --git a/kernel/signal.c b/kernel/signal.c index 1581140f2d99..16e7718316e5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1800,6 +1800,17 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type) return ret; } +static void do_notify_pidfd(struct task_struct *task) +{ + struct pid *pid; + + lockdep_assert_held(&tasklist_lock); + + pid = get_task_pid(task, PIDTYPE_PID); + wake_up_all(&pid->wait_pidfd); + put_pid(pid); +} + /* * Let a parent know about the death of a child. * For a stopped/continued status change, use do_notify_parent_cldstop instead. @@ -1823,6 +1834,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig) BUG_ON(!tsk->ptrace && (tsk->group_leader != tsk || !thread_group_empty(tsk))); + /* Wake up all pidfd waiters */ + do_notify_pidfd(tsk); + if (sig != SIGCHLD) { /* * This is only possible if parent == real_parent. From patchwork Thu Apr 25 19:00:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Fernandes X-Patchwork-Id: 10917633 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 541D41398 for ; Thu, 25 Apr 2019 19:00:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 44EC828CE3 for ; Thu, 25 Apr 2019 19:00:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 387EC28CF3; Thu, 25 Apr 2019 19:00:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 710DE28CE3 for ; Thu, 25 Apr 2019 19:00:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726379AbfDYTAd (ORCPT ); Thu, 25 Apr 2019 15:00:33 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:40153 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725900AbfDYTAc (ORCPT ); Thu, 25 Apr 2019 15:00:32 -0400 Received: by mail-pf1-f194.google.com with SMTP id s4so365667pfh.7 for ; Thu, 25 Apr 2019 12:00:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=joelfernandes.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZZmg+vFR4tPKaX56SK4SSqAQgo7Z9G28nKX2pBYiJnE=; b=GUt90mBMWKKnenpnESwhb1sow6eokCGLQUmq5YaMiFBCOyfSfEkpGQr6JaLe7VhwaC qOxLpLCJYk8pa8EKkrXva2PW2TZNwqlC+0cWYK3VtKYiIBhPKDHaYKxSRc0c8rAzhmiw oJBN7xhg//7ZDJUDHChdauR4JdBevzTep0pyQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZZmg+vFR4tPKaX56SK4SSqAQgo7Z9G28nKX2pBYiJnE=; b=myCm6Oz1gwX9I7xL6VqUYuxCj2Us9nc9hy6hHNJ6HwRFRR9DBJ8gzJNqnRe3jDi5dX Xa7VSSXQFQqVTR0VVvu16mybY5HHowD4WK8cn9iy958y+5zQG15w6AslBOkK6xIIOC9C QznolFKpnTkFnTeaafB9if/tLB+0QPzqZYogc6cXywlbTzhOpGqz6E4PQUBVghjgg0WC ukCvY2A/LGjhVIPQTmooF1300bHROrB+C+gELJFabHk2NvvTUrwMSp/7aBoM+pNzouEH uyzczo2KLHQDF4jF+EEfculWbx1tTKTtjFQHujwucaVIPKv92bA35NXrm4bS8hDal+5X TWRg== X-Gm-Message-State: APjAAAUa2fLkAZ11OVhDqNsRB6tpYb8wOw7jHBNm3mvKgwzc8SVZYAxd ujtisWfchjCtBkxXsh0gqinuOg== X-Google-Smtp-Source: APXvYqzLKDwlRdqQZxGeLDG7zMZoILZ6Gt6xUVYUA57HhNoAcQ9am6KOpcnbWPVIVZFwMAEzN7Py9w== X-Received: by 2002:aa7:9627:: with SMTP id r7mr41453436pfg.245.1556218830955; Thu, 25 Apr 2019 12:00:30 -0700 (PDT) Received: from joelaf.cam.corp.google.com ([2620:15c:6:12:9c46:e0da:efbf:69cc]) by smtp.gmail.com with ESMTPSA id o14sm25480683pgn.4.2019.04.25.12.00.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Apr 2019 12:00:29 -0700 (PDT) From: "Joel Fernandes (Google)" To: linux-kernel@vger.kernel.org Cc: "Joel Fernandes (Google)" , Andrew Morton , Arnd Bergmann , Christian Brauner , dancol@google.com, "Eric W. Biederman" , Greg Kroah-Hartman , Ingo Molnar , jannh@google.com, Jann Horn , Jonathan Kowalski , kernel-team@android.com, linux-kselftest@vger.kernel.org, luto@amacapital.net, Michal Hocko , "Peter Zijlstra (Intel)" , rostedt@goodmis.org, Serge Hallyn , Shuah Khan , sspatil@google.com, Stephen Rothwell , surenb@google.com, Thomas Gleixner , timmurray@google.com, torvalds@linux-foundation.org, Tycho Andersen Subject: [PATCH v1 2/2] Add selftests for pidfd polling Date: Thu, 25 Apr 2019 15:00:10 -0400 Message-Id: <20190425190010.46489-2-joel@joelfernandes.org> X-Mailer: git-send-email 2.21.0.593.g511ec345e18-goog In-Reply-To: <20190425190010.46489-1-joel@joelfernandes.org> References: <20190425190010.46489-1-joel@joelfernandes.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Other than verifying pidfd based polling, the tests make sure that wait semantics are preserved with the pidfd poll. Notably the 2 cases: 1. If a thread group leader exits while threads still there, then no pidfd poll notifcation should happen. 2. If a non-thread group leader does an execve, then the thread group leader is signaled to exit and is replaced with the execing thread as the new leader, however the parent is not notified in this case. Signed-off-by: Joel Fernandes (Google) --- tools/testing/selftests/pidfd/Makefile | 2 +- tools/testing/selftests/pidfd/pidfd_test.c | 198 +++++++++++++++++++++ 2 files changed, 199 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile index deaf8073bc06..4b31c14f273c 100644 --- a/tools/testing/selftests/pidfd/Makefile +++ b/tools/testing/selftests/pidfd/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -g -I../../../../usr/include/ +CFLAGS += -g -I../../../../usr/include/ -lpthread TEST_GEN_PROGS := pidfd_test diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c index d59378a93782..e887f807645e 100644 --- a/tools/testing/selftests/pidfd/pidfd_test.c +++ b/tools/testing/selftests/pidfd/pidfd_test.c @@ -4,18 +4,42 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include +#include #include #include "../kselftest.h" +#define CHILD_THREAD_MIN_WAIT 3 /* seconds */ +#define MAX_EVENTS 5 +#define __NR_pidfd_send_signal 424 + +#ifndef CLONE_PIDFD +#define CLONE_PIDFD 0x00001000 +#endif + +static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) +{ + size_t stack_size = 1024; + char *stack[1024] = { 0 }; + +#ifdef __ia64__ + return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); +#else + return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); +#endif +} + static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { @@ -368,10 +392,184 @@ static int test_pidfd_send_signal_syscall_support(void) return 0; } +void *test_pidfd_poll_exec_thread(void *priv) +{ + char waittime[256]; + + ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", + getpid(), syscall(SYS_gettid)); + ksft_print_msg("Child Thread: doing exec of sleep\n"); + + sprintf(waittime, "%d", CHILD_THREAD_MIN_WAIT); + execl("/bin/sleep", "sleep", waittime, (char *)NULL); + + ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", + getpid(), syscall(SYS_gettid)); + return NULL; +} + +static int poll_pidfd(const char *test_name, int pidfd) +{ + int c; + int epoll_fd = epoll_create1(0); + struct epoll_event event, events[MAX_EVENTS]; + + if (epoll_fd == -1) + ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor\n", + test_name); + + event.events = EPOLLIN; + event.data.fd = pidfd; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { + ksft_print_msg("%s test: Failed to add epoll file descriptor: Skipping\n", + test_name); + _exit(PIDFD_SKIP); + } + + c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); + if (c != 1 || !(events[0].events & EPOLLIN)) + ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x)\n", + test_name, c, events[0].events); + + close(epoll_fd); + return events[0].events; + +} + +static int child_poll_exec_test(void *args) +{ + pthread_t t1; + + ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), + syscall(SYS_gettid)); + pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); + /* + * Exec in the non-leader thread will destroy the leader immediately. + * If the wait in the parent returns too soon, the test fails. + */ + while (1) + ; +} + +int test_pidfd_poll_exec(int use_waitpid) +{ + int pid, pidfd = 0; + int status, ret; + pthread_t t1; + time_t prog_start = time(NULL); + const char *test_name = "pidfd_poll check for premature notification on child thread exec"; + + ksft_print_msg("Parent: pid: %d\n", getpid()); + pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); + + ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); + + if (use_waitpid) { + ret = waitpid(pid, &status, 0); + if (ret == -1) + ksft_print_msg("Parent: error\n"); + + if (ret == pid) + ksft_print_msg("Parent: Child process waited for.\n"); + } else { + poll_pidfd(test_name, pidfd); + } + + time_t prog_time = time(NULL) - prog_start; + + ksft_print_msg("Time waited for child: %lu\n", prog_time); + + close(pidfd); + + if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) + ksft_exit_fail_msg("%s test: Failed\n", test_name); + else + ksft_test_result_pass("%s test: Passed\n", test_name); +} + +void *test_pidfd_poll_leader_exit_thread(void *priv) +{ + char waittime[256]; + + ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", + getpid(), syscall(SYS_gettid)); + sleep(CHILD_THREAD_MIN_WAIT); + ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); + return NULL; +} + +static time_t *child_exit_secs; +static int child_poll_leader_exit_test(void *args) +{ + pthread_t t1, t2; + + ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); + pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); + pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); + + /* + * glibc exit calls exit_group syscall, so explicity call exit only + * so that only the group leader exits, leaving the threads alone. + */ + *child_exit_secs = time(NULL); + syscall(SYS_exit, 0); +} + +int test_pidfd_poll_leader_exit(int use_waitpid) +{ + int pid, pidfd = 0; + int status, ret; + time_t prog_start = time(NULL); + const char *test_name = "pidfd_poll check for premature notification on non-empty" + "group leader exit"; + + child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + ksft_print_msg("Parent: pid: %d\n", getpid()); + pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); + + ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); + + if (use_waitpid) { + ret = waitpid(pid, &status, 0); + if (ret == -1) + ksft_print_msg("Parent: error\n"); + } else { + /* + * This sleep tests for the case where if the child exits, and is in + * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll + * doesn't prematurely return even though there are active threads + */ + sleep(1); + poll_pidfd(test_name, pidfd); + } + + if (ret == pid) + ksft_print_msg("Parent: Child process waited for.\n"); + + time_t since_child_exit = time(NULL) - *child_exit_secs; + + ksft_print_msg("Time since child exit: %lu\n", since_child_exit); + + close(pidfd); + + if (since_child_exit < CHILD_THREAD_MIN_WAIT || + since_child_exit > CHILD_THREAD_MIN_WAIT + 2) + ksft_exit_fail_msg("%s test: Failed\n", test_name); + else + ksft_test_result_pass("%s test: Passed\n", test_name); +} + int main(int argc, char **argv) { ksft_print_header(); + test_pidfd_poll_exec(0); + test_pidfd_poll_exec(1); + test_pidfd_poll_leader_exit(0); + test_pidfd_poll_leader_exit(1); test_pidfd_send_signal_syscall_support(); test_pidfd_send_signal_simple_success(); test_pidfd_send_signal_exited_fail();