From: Paul Menage <pmenage@ensim.com>
To: linux-kernel@vger.kernel.org
Cc: pmenage@ensim.com
Subject: [PATCH][RFC] Pollable /proc/<pid>/ - avoid SIGCHLD/poll() races
Date: Thu, 04 Oct 2001 00:52:58 -0700 [thread overview]
Message-ID: <E15p3JS-0000ko-00@pmenage-dt.ensim.com> (raw)
I've recently run across a problem where a server (in this case, sshd)
can deadlock itself if a SIGCHLD arrives just before it calls select(),
but after it has checked whether its child_terminated. So when the
select() is called, the SIGCHLD signal handler has already run and set
the child_terminated flag, and there's nothing to wake the select().
The only real user-space solution to this is to have the SIGCHLD handler
somehow cause the select() to return immediately by e.g. writing a byte
to a looped pipe which is included in the select() readfd set, but this
seems a little contrived. This patch simply adds a proc_base_poll()
method to make /proc/<pid> pollable, with the following semantics:
- /proc/<your_pid>/ returns POLLHUP if you have any unreaped zombie
children.
- /proc/<your_child_pid>/ returns POLLHUP if the specified child is a
zombie or has been reaped.
- Any other /proc/<pid>/ directory returns POLLNVAL, as we've no way to
do a proper poll() on it - only a parent's wait_chldexit wait queue is
awakened when a process exits, so other processes won't get any kind of
notification.
So by including /proc/self in the readset for select(), you can
guarantee that select()/poll() will return if you've just received (and
handled) a SIGCHLD, but not yet reaped the child.
Alternatively, you could block SIGCHLD and just use select() for both
your child notifications and your I/O notifications. In this case, it
becomes a very specialised case of the sigopen() that Dan Kegel
proposed, but is minimally intrusive (consisting of just a single method
added to proc_base_operations).
If do_notify_parent() were changed to wake up tsk->wait_chldexit as well
as its parent's wait_chldexit, then sensible semantics could be added
for polling on any /proc/<pid>/ dir - just do a pollwait() on the target
process' exit_childwait queue. Provided that the target task is properly
refcounted (which should occur naturally due to the existence of the
/proc/<pid>/ inode), this should be safe. Would anyone have objections
to (or enthusiasm for) such a patch?
Paul
--- linux.orig/fs/proc/base.c Fri Jul 20 12:39:56 2001
+++ linux/fs/proc/base.c Thu Oct 4 00:19:45 2001
@@ -23,6 +23,8 @@
#include <linux/init.h>
#include <linux/file.h>
#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
/*
* For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -643,6 +645,44 @@
return 1;
}
+static unsigned int proc_base_poll(struct file *file, poll_table *wait)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ struct task_struct *task = inode->u.proc_i.task;
+
+ int mask = 0;
+
+ poll_wait(file, ¤t->wait_chldexit, wait);
+
+ if(task == current) {
+
+ /* Check for any zombie children */
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ do {
+ for (p = task->p_cptr ; p ; p = p->p_osptr) {
+ if(p->state == TASK_ZOMBIE) {
+ mask = POLLERR;
+ break;
+ }
+ }
+ task = next_thread(task);
+
+ } while(task != current && !mask);
+ read_unlock(&tasklist_lock);
+
+ } else if (task->p_pptr == current) {
+ /* Check for specific zombie child */
+ if(task->state == TASK_ZOMBIE)
+ mask = POLLERR;
+ } else {
+ mask = POLLNVAL;
+ }
+
+ return mask;
+}
+
/* building an inode */
static int task_dumpable(struct task_struct *task)
@@ -914,6 +954,7 @@
static struct file_operations proc_base_operations = {
read: generic_read_dir,
readdir: proc_base_readdir,
+ poll : proc_base_poll,
};
static struct inode_operations proc_base_inode_operations = {
next reply other threads:[~2001-10-04 7:53 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-10-04 7:52 Paul Menage [this message]
2001-10-04 8:59 ` Christoph Rohland
2001-10-04 9:31 ` Paul Menage
2001-10-04 10:25 ` Christoph Rohland
2001-10-13 15:44 ` Jamie Lokier
2001-10-04 14:18 ` Mattias Engdegård
2001-10-04 20:39 ` Paul Menage
2001-10-05 9:36 ` Mattias Engdegård
2001-10-13 15:36 ` Jamie Lokier
2001-10-14 2:25 ` John Alvord
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=E15p3JS-0000ko-00@pmenage-dt.ensim.com \
--to=pmenage@ensim.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®