lkml.org 
[lkml]   [2009]   [Aug]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH 3/2] fcntl: F_[SG]ETOWN_TID
From
Date

In order to direct the SIGIO signal to a particular thread of a
multi-threaded application we cannot, like suggested by the manpage, put
a TID into the regular fcntl(F_SETOWN) call. It will still be send to
the whole process of which that thread is part.

Since people do want to properly direct SIGIO we introduce F_SETOWN_TID,
which functions similarly to F_SETOWN, except positive arguments are
interpreted as TIDs and negative arguments are interpreted as PIDs.

The need to direct SIGIO comes from self-monitoring profiling such as
with perf-counters. Perf-counters uses SIGIO to notify that new sample
data is available. If the signal is delivered to the same task that
generated the new sample it can augment that data by inspecting the
task's user-space state right after it returns from the kernel. This
is esp. convenient for interpreted or virtual machine driven environments.

This extension is fully bug compatible with the old F_GETOWN
implementation in that F_GETOWN_TID will be troubled by the negative
return value for PIDs similarly to F_GETOWN's trouble with process
groups.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Tested-by: stephane eranian <eranian@googlemail.com>
---
arch/alpha/include/asm/fcntl.h | 2 +
arch/parisc/include/asm/fcntl.h | 2 +
fs/fcntl.c | 62 ++++++++++++++++++++++++++++++++++------
include/asm-generic/fcntl.h | 4 ++
include/linux/fs.h | 11 +++++--
net/socket.c | 2 -
6 files changed, 71 insertions(+), 12 deletions(-)

Index: linux-2.6/arch/parisc/include/asm/fcntl.h
===================================================================
--- linux-2.6.orig/arch/parisc/include/asm/fcntl.h
+++ linux-2.6/arch/parisc/include/asm/fcntl.h
@@ -28,6 +28,8 @@
#define F_SETOWN 12 /* for sockets. */
#define F_SETSIG 13 /* for sockets. */
#define F_GETSIG 14 /* for sockets. */
+#define F_GETOWN_TID 15
+#define F_SETOWN_TID 16

/* for posix fcntl() and lockf() */
#define F_RDLCK 01
Index: linux-2.6/fs/fcntl.c
===================================================================
--- linux-2.6.orig/fs/fcntl.c
+++ linux-2.6/fs/fcntl.c
@@ -197,13 +197,15 @@ static int setfl(int fd, struct file * f
}

static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
- int force)
+ int flags)
{
write_lock_irq(&filp->f_owner.lock);
- if (force || !filp->f_owner.pid) {
+ if ((flags & FF_SETOWN_FORCE) || !filp->f_owner.pid) {
put_pid(filp->f_owner.pid);
filp->f_owner.pid = get_pid(pid);
filp->f_owner.pid_type = type;
+ filp->f_owner.task_only =
+ (type == PIDTYPE_PID && (flags & FF_SETOWN_TID));

if (pid) {
const struct cred *cred = current_cred();
@@ -215,7 +217,7 @@ static void f_modown(struct file *filp,
}

int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
- int force)
+ int flags)
{
int err;

@@ -223,12 +225,12 @@ int __f_setown(struct file *filp, struct
if (err)
return err;

- f_modown(filp, pid, type, force);
+ f_modown(filp, pid, type, flags);
return 0;
}
EXPORT_SYMBOL(__f_setown);

-int f_setown(struct file *filp, unsigned long arg, int force)
+int f_setown(struct file *filp, unsigned long arg, int flags)
{
enum pid_type type;
struct pid *pid;
@@ -241,7 +243,7 @@ int f_setown(struct file *filp, unsigned
}
rcu_read_lock();
pid = find_vpid(who);
- result = __f_setown(filp, pid, type, force);
+ result = __f_setown(filp, pid, type, flags);
rcu_read_unlock();
return result;
}
@@ -263,6 +265,40 @@ pid_t f_getown(struct file *filp)
return pid;
}

+static int f_setown_tid(struct file *filp, unsigned long arg)
+{
+ int flags = FF_SETOWN_FORCE;
+ struct pid *pid;
+ int who = arg;
+ int ret = 0;
+
+ if (who < 0)
+ who = -who;
+ else
+ flags |= FF_SETOWN_TID;
+
+ rcu_read_lock();
+ pid = find_vpid(who);
+ ret = __f_setown(filp, pid, PIDTYPE_PID, flags);
+ rcu_read_unlock();
+
+ return ret;
+}
+
+static pid_t f_getown_tid(struct file *filp)
+{
+ pid_t tid;
+
+ read_lock(&filp->f_owner.lock);
+ tid = pid_vnr(filp->f_owner.pid);
+ if (filp->f_owner.pid_type == PIDTYPE_PGID)
+ tid = 0;
+ if (!filp->f_owner.task_only)
+ tid = -tid;
+ read_unlock(&filp->f_owner.lock);
+ return tid;
+}
+
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
struct file *filp)
{
@@ -311,7 +347,14 @@ static long do_fcntl(int fd, unsigned in
force_successful_syscall_return();
break;
case F_SETOWN:
- err = f_setown(filp, arg, 1);
+ err = f_setown(filp, arg, FF_SETOWN_FORCE);
+ break;
+ case F_GETOWN_TID:
+ err = f_getown_tid(filp);
+ force_successful_syscall_return();
+ break;
+ case F_SETOWN_TID:
+ err = f_setown_tid(filp, arg);
break;
case F_GETSIG:
err = filp->f_owner.signum;
@@ -436,6 +479,7 @@ static void send_sigio_to_task(struct ta
* sure we read it once and use the same value throughout.
*/
int signum = ACCESS_ONCE(fown->signum);
+ int group = !fown->task_only;

if (!sigio_perm(p, fown, signum))
return;
@@ -461,11 +505,11 @@ static void send_sigio_to_task(struct ta
else
si.si_band = band_table[reason - POLL_IN];
si.si_fd = fd;
- if (!do_send_sig_info(signum, &si, p, true))
+ if (!do_send_sig_info(signum, &si, p, group))
break;
/* fall-through: fall back on the old plain SIGIO signal */
case 0:
- do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, true);
+ do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, group);
}
}

Index: linux-2.6/include/asm-generic/fcntl.h
===================================================================
--- linux-2.6.orig/include/asm-generic/fcntl.h
+++ linux-2.6/include/asm-generic/fcntl.h
@@ -73,6 +73,10 @@
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
#endif
+#ifndef F_SETOWN_TID
+#define F_SETOWN_TID 12
+#define F_GETOWN_TID 13
+#endif

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h
+++ linux-2.6/include/linux/fs.h
@@ -872,6 +872,7 @@ struct fown_struct {
rwlock_t lock; /* protects pid, uid, euid fields */
struct pid *pid; /* pid or -pgrp where SIGIO should be sent */
enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
+ bool task_only; /* task or group signal */
uid_t uid, euid; /* uid/euid of process setting the owner */
int signum; /* posix.1b rt signal to be delivered on IO */
};
@@ -1291,8 +1292,14 @@ extern void kill_fasync(struct fasync_st
/* only for net: no internal synchronization */
extern void __kill_fasync(struct fasync_struct *, int, int);

-extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
-extern int f_setown(struct file *filp, unsigned long arg, int force);
+/*
+ * setown flags
+ */
+#define FF_SETOWN_FORCE 1
+#define FF_SETOWN_TID 2
+
+extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int flags);
+extern int f_setown(struct file *filp, unsigned long arg, int flags);
extern void f_delown(struct file *filp);
extern pid_t f_getown(struct file *filp);
extern int send_sigurg(struct fown_struct *fown);
Index: linux-2.6/net/socket.c
===================================================================
--- linux-2.6.orig/net/socket.c
+++ linux-2.6/net/socket.c
@@ -916,7 +916,7 @@ static long sock_ioctl(struct file *file
err = -EFAULT;
if (get_user(pid, (int __user *)argp))
break;
- err = f_setown(sock->file, pid, 1);
+ err = f_setown(sock->file, pid, FF_SETOWN_FORCE);
break;
case FIOGETOWN:
case SIOCGPGRP:
Index: linux-2.6/arch/alpha/include/asm/fcntl.h
===================================================================
--- linux-2.6.orig/arch/alpha/include/asm/fcntl.h
+++ linux-2.6/arch/alpha/include/asm/fcntl.h
@@ -26,6 +26,8 @@
#define F_GETOWN 6 /* for sockets. */
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
+#define F_SETOWN_TID 12
+#define F_GETOWN_TID 13

/* for posix fcntl() and lockf() */
#define F_RDLCK 1



\
 
 \ /
  Last update: 2009-08-03 17:51    [W:0.863 / U:0.072 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site