diff -r -bBwd -U 3 linux-2.4.13/fs/fcntl.c linux-2.4.13-sig-per-fd/fs/fcntl.c --- linux-2.4.13/fs/fcntl.c Mon Sep 17 13:16:30 2001 +++ linux-2.4.13-sig-per-fd/fs/fcntl.c Sat Dec 8 13:25:34 2001 @@ -320,6 +320,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.13/fs/file.c linux-2.4.13-sig-per-fd/fs/file.c --- linux-2.4.13/fs/file.c Fri Feb 9 11:29:44 2001 +++ linux-2.4.13-sig-per-fd/fs/file.c Sat Dec 8 13:25:34 2001 @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -88,9 +89,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 */ @@ -109,18 +110,22 @@ 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; } @@ -187,10 +192,11 @@ 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; /* Copy the existing tables and install the new pointers */ @@ -212,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.13/fs/file_table.c linux-2.4.13-sig-per-fd/fs/file_table.c --- linux-2.4.13/fs/file_table.c Mon Sep 17 13:16:30 2001 +++ linux-2.4.13-sig-per-fd/fs/file_table.c Sat Dec 8 13:25:34 2001 @@ -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.13/include/linux/fcntl.h linux-2.4.13-sig-per-fd/include/linux/fcntl.h --- linux-2.4.13/include/linux/fcntl.h Sun Sep 23 09:48:01 2001 +++ linux-2.4.13-sig-per-fd/include/linux/fcntl.h Sat Dec 8 13:25:34 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,6 +27,12 @@ #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 */ #ifdef __KERNEL__ diff -r -bBwd -U 3 linux-2.4.13/include/linux/fs.h linux-2.4.13-sig-per-fd/include/linux/fs.h --- linux-2.4.13/include/linux/fs.h Tue Oct 23 21:59:06 2001 +++ linux-2.4.13-sig-per-fd/include/linux/fs.h Sat Dec 8 13:25:34 2001 @@ -520,6 +520,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.13/kernel/signal.c linux-2.4.13-sig-per-fd/kernel/signal.c --- linux-2.4.13/kernel/signal.c Mon Sep 17 16:40:01 2001 +++ linux-2.4.13-sig-per-fd/kernel/signal.c Sat Dec 8 13:27:16 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 == (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); @@ -267,9 +279,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; @@ -280,6 +300,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); @@ -288,18 +317,8 @@ } pp = &q->next; } - return 1; -} -/* - * 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); + return 1; } /* @@ -399,9 +418,37 @@ } } -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 @@ -415,6 +462,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 +544,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); Only in linux-2.4.13-sig-per-fd/kernel: signal.c~