diff -rdN -bB -U 3 linux/fs/fcntl.c linux-2.4.4.onesigfd/fs/fcntl.c --- linux/fs/fcntl.c Wed Nov 15 22:50:25 2000 +++ linux-2.4.4.onesigfd/fs/fcntl.c Fri May 18 16:02:17 2001 @@ -300,6 +300,13 @@ case F_NOTIFY: err = fcntl_dirnotify(fd, filp, arg); break; + case F_GETAUXFL: + err = filp->f_auxflags; + break; + case F_SETAUXFL: + filp->f_auxflags = arg; + err = 0; + break; default: /* sockets need a few special fcntls. */ err = -EINVAL; diff -rdN -bB -U 3 linux/fs/file_table.c linux-2.4.4.onesigfd/fs/file_table.c --- linux/fs/file_table.c Wed Apr 18 11:49:12 2001 +++ linux-2.4.4.onesigfd/fs/file_table.c Fri May 18 16:02:17 2001 @@ -109,6 +109,8 @@ fops_put(file->f_op); file->f_dentry = NULL; file->f_vfsmnt = NULL; + file->f_auxflags = 0; + file->f_infoptr = NULL; /* Should this be dequeued ? */ if (file->f_mode & FMODE_WRITE) put_write_access(inode); dput(dentry); diff -rdN -bB -U 3 linux/include/linux/fcntl.h linux-2.4.4.onesigfd/include/linux/fcntl.h --- linux/include/linux/fcntl.h Fri Sep 22 14:21:22 2000 +++ linux-2.4.4.onesigfd/include/linux/fcntl.h Fri May 18 16:02:17 2001 @@ -12,6 +12,11 @@ */ #define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) +/* Request only one rt-signal per fd discipline + */ +#define F_SETAUXFL (F_LINUX_SPECIFIC_BASE+3) +#define F_GETAUXFL (F_LINUX_SPECIFIC_BASE+4) + /* * Types of directory notifications that may be requested. */ @@ -22,5 +27,11 @@ #define DN_RENAME 0x00000010 /* File renamed */ #define DN_ATTRIB 0x00000020 /* File changed attibutes */ #define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ + +/* + * Auxillary flags + */ +#define O_ONESIGFD (2<<17) /* Allow only one rt signal */ + /* per fd in sigqueue */ #endif diff -rdN -bB -U 3 linux/include/linux/fs.h linux-2.4.4.onesigfd/include/linux/fs.h --- linux/include/linux/fs.h Fri Apr 27 15:48:28 2001 +++ linux-2.4.4.onesigfd/include/linux/fs.h Fri May 18 16:02:17 2001 @@ -486,6 +486,8 @@ int f_error; unsigned long f_version; + unsigned int f_auxflags; + void *f_infoptr; /* needed for tty driver, and maybe others */ void *private_data; diff -rdN -bB -U 3 linux/kernel/signal.c linux-2.4.4.onesigfd/kernel/signal.c --- linux/kernel/signal.c Wed Jan 3 20:45:26 2001 +++ linux-2.4.4.onesigfd/kernel/signal.c Fri May 18 16:02:17 2001 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -203,6 +204,17 @@ if ((*pp = q->next) == NULL) list->tail = pp; + /* For one signal per fd discipline, indicate signal + * delivery so a new one can be queued + */ + if (sig >= SIGRTMIN) { + struct file *filep = fcheck( q->info.si_fd ); + + if( filep && (filep->f_auxflags & O_ONESIGFD) && + ( q == (siginfo_t *) filep->f_infoptr ) ) + filep->f_infoptr = NULL; + } + /* Copy the sigqueue information and free the queue entry */ copy_siginfo(info, &q->info); kmem_cache_free(sigqueue_cachep,q); @@ -399,9 +411,31 @@ } } -static int send_signal(int sig, struct siginfo *info, struct sigpending *signals) +static int send_signal(int sig, struct siginfo *info, struct task_struct *t) { - struct sigqueue * q = NULL; + struct sigqueue *q = NULL; + struct sigpending *signals = &t->pending ; + unsigned int newsignal = 0; + struct file *filep = NULL; + + if( (sig >= SIGRTMIN) && ( (unsigned long) info > 1) ) { + struct files_struct * files = t->files; + + if( (info->si_fd < files->max_fds) && + ( filep = files->fd[ info->si_fd ] ) && + ( filep->f_auxflags & O_ONESIGFD ) ) { + if( filep->f_infoptr ){ + /* signal is already queued for this fd + but the reason for signal may be different*/ + q = ( struct sigqueue *) filep->f_infoptr; + q->info.si_band |= info->si_band; + return 0; + } + else + newsignal = 1; + } + } + /* Real-time signals must be queued if sent by sigqueue, or some other real-time mechanism. It is implementation @@ -415,6 +449,11 @@ q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC); } + /* Set a reference for signal queued in fd for + one-signal-per-fd discipline */ + if( newsignal && q ) + filep->f_infoptr = q; + if (q) { atomic_inc(&nr_queued_signals); q->next = NULL; @@ -492,7 +531,7 @@ static int deliver_signal(int sig, struct siginfo *info, struct task_struct *t) { - int retval = send_signal(sig, info, &t->pending); + int retval = send_signal(sig, info, t); if (!retval && !sigismember(&t->blocked, sig)) signal_wake_up(t);