diff -r -bBwd -U 3 linux-2.4.19/fs/fcntl.c linux-2.4.19-onesignalperfd/fs/fcntl.c --- linux-2.4.19/fs/fcntl.c 2002-08-03 09:39:45.000000000 +0900 +++ linux-2.4.19-onesignalperfd/fs/fcntl.c 2002-10-27 15:02:54.000000000 +0900 @@ -324,6 +324,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 -r -bBwd -U 3 linux-2.4.19/fs/file.c linux-2.4.19-onesignalperfd/fs/file.c --- linux-2.4.19/fs/file.c 2002-08-03 09:39:45.000000000 +0900 +++ linux-2.4.19-onesignalperfd/fs/file.c 2002-10-27 15:05:27.000000000 +0900 @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -89,9 +90,9 @@ error = -ENOMEM; new_fds = alloc_fd_array(nfds); - write_lock(&files->file_lock); if (!new_fds) goto out; + write_lock_bh(&files->file_lock); /* Copy the existing array and install the new pointer */ @@ -110,18 +111,21 @@ memset(&new_fds[i], 0, (nfds-i) * sizeof(struct file *)); - write_unlock(&files->file_lock); + write_unlock_bh(&files->file_lock); free_fd_array(old_fds, i); - write_lock(&files->file_lock); + } + else + { + write_unlock_bh(&files->file_lock); } } else { /* Somebody expanded the array while we slept ... */ - write_unlock(&files->file_lock); + write_unlock_bh(&files->file_lock); free_fd_array(new_fds, nfds); - write_lock(&files->file_lock); } error = 0; out: + write_lock(&files->file_lock); return error; } @@ -189,9 +193,9 @@ error = -ENOMEM; new_openset = alloc_fdset(nfds); new_execset = alloc_fdset(nfds); - write_lock(&files->file_lock); if (!new_openset || !new_execset) goto out; + write_lock_bh(&files->file_lock); error = 0; @@ -214,16 +218,18 @@ nfds = xchg(&files->max_fdset, nfds); new_openset = xchg(&files->open_fds, new_openset); new_execset = xchg(&files->close_on_exec, new_execset); - write_unlock(&files->file_lock); + write_unlock_bh(&files->file_lock); free_fdset (new_openset, nfds); free_fdset (new_execset, nfds); write_lock(&files->file_lock); return 0; } + else + write_unlock_bh(&files->file_lock); + /* Somebody expanded the array while we slept ... */ out: - write_unlock(&files->file_lock); if (new_openset) free_fdset(new_openset, nfds); if (new_execset) diff -r -bBwd -U 3 linux-2.4.19/fs/file_table.c linux-2.4.19-onesignalperfd/fs/file_table.c --- linux-2.4.19/fs/file_table.c 2001-09-18 05:16:30.000000000 +0900 +++ linux-2.4.19-onesignalperfd/fs/file_table.c 2002-10-27 15:05:58.000000000 +0900 @@ -117,6 +117,8 @@ file_list_lock(); file->f_dentry = NULL; file->f_vfsmnt = NULL; + file->f_auxflags = 0; + file->f_infoptr = NULL; /* Should this be dequeued ? */ list_del(&file->f_list); list_add(&file->f_list, &free_list); files_stat.nr_free_files++; diff -r -bBwd -U 3 linux-2.4.19/include/linux/fcntl.h linux-2.4.19-onesignalperfd/include/linux/fcntl.h --- linux-2.4.19/include/linux/fcntl.h 2001-09-24 01:48:01.000000000 +0900 +++ linux-2.4.19-onesignalperfd/include/linux/fcntl.h 2002-10-27 15:07:05.000000000 +0900 @@ -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. */ @@ -23,6 +28,11 @@ #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 */ + #ifdef __KERNEL__ #if BITS_PER_LONG == 32 diff -r -bBwd -U 3 linux-2.4.19/include/linux/fs.h linux-2.4.19-onesignalperfd/include/linux/fs.h --- linux-2.4.19/include/linux/fs.h 2002-08-03 09:39:45.000000000 +0900 +++ linux-2.4.19-onesignalperfd/include/linux/fs.h 2002-10-27 15:07:28.000000000 +0900 @@ -534,6 +534,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 -r -bBwd -U 3 linux-2.4.19/kernel/signal.c linux-2.4.19-onesignalperfd/kernel/signal.c --- linux-2.4.19/kernel/signal.c 2002-08-03 09:39:46.000000000 +0900 +++ linux-2.4.19-onesignalperfd/kernel/signal.c 2002-10-27 15:10:46.000000000 +0900 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -232,6 +233,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 == (struct sigqueue *) 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); @@ -296,9 +308,17 @@ return sig; } -static int rm_from_queue(int sig, struct sigpending *s) +/* + * Remove signal sig from t->pending. + * Returns 1 if sig was found. + * + * All callers must be holding t->sigmask_lock. + */ +static int rm_sig_from_queue(int sig, struct task_struct *t) { struct sigqueue *q, **pp; + struct sigpending *s = &t->pending; + struct files_struct *files = t->files; if (!sigismember(&s->signal, sig)) return 0; @@ -309,6 +329,15 @@ while ((q = *pp) != NULL) { if (q->info.si_signo == sig) { + struct file *filep; + + if( ( files && (q->info.si_fd < files->max_fds)) && + ( filep = files->fd[ q->info.si_fd ] ) && + ( filep->f_auxflags & O_ONESIGFD ) && + ( filep->f_infoptr ) && + ( filep->f_infoptr == q) ) + filep->f_infoptr = NULL; + if ((*pp = q->next) == NULL) s->tail = pp; kmem_cache_free(sigqueue_cachep,q); @@ -321,17 +350,6 @@ } /* - * Remove signal sig from t->pending. - * Returns 1 if sig was found. - * - * All callers must be holding t->sigmask_lock. - */ -static int rm_sig_from_queue(int sig, struct task_struct *t) -{ - return rm_from_queue(sig, &t->pending); -} - -/* * Bad permissions for sending the signal */ int bad_signal(int sig, struct siginfo *info, struct task_struct *t) @@ -428,9 +446,36 @@ } } -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 sigpending *signals = &t->pending ; + unsigned int newsignal = 0; + struct file *filep = NULL; + struct files_struct *files = NULL; + + if( (sig >= SIGRTMIN) && ( (unsigned long) info > 1) ) { + + files = t->files; + + if( 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 @@ -443,6 +488,10 @@ if (atomic_read(&nr_queued_signals) < max_queued_signals) { 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); @@ -521,7 +570,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);