The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/signalfd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  fs/signalfd.c
    3  *
    4  *  Copyright (C) 2003  Linus Torvalds
    5  *
    6  *  Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org>
    7  *      Changed ->read() to return a siginfo strcture instead of signal number.
    8  *      Fixed locking in ->poll().
    9  *      Added sighand-detach notification.
   10  *      Added fd re-use in sys_signalfd() syscall.
   11  *      Now using anonymous inode source.
   12  *      Thanks to Oleg Nesterov for useful code review and suggestions.
   13  *      More comments and suggestions from Arnd Bergmann.
   14  *  Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br>
   15  *      Retrieve multiple signals with one read() call
   16  *  Sun Jul 15, 2007: Davide Libenzi <davidel@xmailserver.org>
   17  *      Attach to the sighand only during read() and poll().
   18  */
   19 
   20 #include <linux/file.h>
   21 #include <linux/poll.h>
   22 #include <linux/init.h>
   23 #include <linux/fs.h>
   24 #include <linux/sched.h>
   25 #include <linux/slab.h>
   26 #include <linux/kernel.h>
   27 #include <linux/signal.h>
   28 #include <linux/list.h>
   29 #include <linux/anon_inodes.h>
   30 #include <linux/signalfd.h>
   31 #include <linux/syscalls.h>
   32 #include <linux/proc_fs.h>
   33 
   34 void signalfd_cleanup(struct sighand_struct *sighand)
   35 {
   36         wait_queue_head_t *wqh = &sighand->signalfd_wqh;
   37         /*
   38          * The lockless check can race with remove_wait_queue() in progress,
   39          * but in this case its caller should run under rcu_read_lock() and
   40          * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return.
   41          */
   42         if (likely(!waitqueue_active(wqh)))
   43                 return;
   44 
   45         /* wait_queue_t->func(POLLFREE) should do remove_wait_queue() */
   46         wake_up_poll(wqh, POLLHUP | POLLFREE);
   47 }
   48 
   49 struct signalfd_ctx {
   50         sigset_t sigmask;
   51 };
   52 
   53 static int signalfd_release(struct inode *inode, struct file *file)
   54 {
   55         kfree(file->private_data);
   56         return 0;
   57 }
   58 
   59 static unsigned int signalfd_poll(struct file *file, poll_table *wait)
   60 {
   61         struct signalfd_ctx *ctx = file->private_data;
   62         unsigned int events = 0;
   63 
   64         poll_wait(file, &current->sighand->signalfd_wqh, wait);
   65 
   66         spin_lock_irq(&current->sighand->siglock);
   67         if (next_signal(&current->pending, &ctx->sigmask) ||
   68             next_signal(&current->signal->shared_pending,
   69                         &ctx->sigmask))
   70                 events |= POLLIN;
   71         spin_unlock_irq(&current->sighand->siglock);
   72 
   73         return events;
   74 }
   75 
   76 /*
   77  * Copied from copy_siginfo_to_user() in kernel/signal.c
   78  */
   79 static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
   80                              siginfo_t const *kinfo)
   81 {
   82         long err;
   83 
   84         BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
   85 
   86         /*
   87          * Unused members should be zero ...
   88          */
   89         err = __clear_user(uinfo, sizeof(*uinfo));
   90 
   91         /*
   92          * If you change siginfo_t structure, please be sure
   93          * this code is fixed accordingly.
   94          */
   95         err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo);
   96         err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno);
   97         err |= __put_user((short) kinfo->si_code, &uinfo->ssi_code);
   98         switch (kinfo->si_code & __SI_MASK) {
   99         case __SI_KILL:
  100                 err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
  101                 err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
  102                 break;
  103         case __SI_TIMER:
  104                  err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid);
  105                  err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun);
  106                  err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
  107                  err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
  108                 break;
  109         case __SI_POLL:
  110                 err |= __put_user(kinfo->si_band, &uinfo->ssi_band);
  111                 err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd);
  112                 break;
  113         case __SI_FAULT:
  114                 err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr);
  115 #ifdef __ARCH_SI_TRAPNO
  116                 err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
  117 #endif
  118 #ifdef BUS_MCEERR_AO
  119                 /* 
  120                  * Other callers might not initialize the si_lsb field,
  121                  * so check explicitly for the right codes here.
  122                  */
  123                 if (kinfo->si_code == BUS_MCEERR_AR ||
  124                     kinfo->si_code == BUS_MCEERR_AO)
  125                         err |= __put_user((short) kinfo->si_addr_lsb,
  126                                           &uinfo->ssi_addr_lsb);
  127 #endif
  128                 break;
  129         case __SI_CHLD:
  130                 err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
  131                 err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
  132                 err |= __put_user(kinfo->si_status, &uinfo->ssi_status);
  133                 err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime);
  134                 err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime);
  135                 break;
  136         case __SI_RT: /* This is not generated by the kernel as of now. */
  137         case __SI_MESGQ: /* But this is */
  138                 err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
  139                 err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
  140                 err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
  141                 err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
  142                 break;
  143         default:
  144                 /*
  145                  * This case catches also the signals queued by sigqueue().
  146                  */
  147                 err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
  148                 err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
  149                 err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
  150                 err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
  151                 break;
  152         }
  153 
  154         return err ? -EFAULT: sizeof(*uinfo);
  155 }
  156 
  157 static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,
  158                                 int nonblock)
  159 {
  160         ssize_t ret;
  161         DECLARE_WAITQUEUE(wait, current);
  162 
  163         spin_lock_irq(&current->sighand->siglock);
  164         ret = dequeue_signal(current, &ctx->sigmask, info);
  165         switch (ret) {
  166         case 0:
  167                 if (!nonblock)
  168                         break;
  169                 ret = -EAGAIN;
  170         default:
  171                 spin_unlock_irq(&current->sighand->siglock);
  172                 return ret;
  173         }
  174 
  175         add_wait_queue(&current->sighand->signalfd_wqh, &wait);
  176         for (;;) {
  177                 set_current_state(TASK_INTERRUPTIBLE);
  178                 ret = dequeue_signal(current, &ctx->sigmask, info);
  179                 if (ret != 0)
  180                         break;
  181                 if (signal_pending(current)) {
  182                         ret = -ERESTARTSYS;
  183                         break;
  184                 }
  185                 spin_unlock_irq(&current->sighand->siglock);
  186                 schedule();
  187                 spin_lock_irq(&current->sighand->siglock);
  188         }
  189         spin_unlock_irq(&current->sighand->siglock);
  190 
  191         remove_wait_queue(&current->sighand->signalfd_wqh, &wait);
  192         __set_current_state(TASK_RUNNING);
  193 
  194         return ret;
  195 }
  196 
  197 /*
  198  * Returns a multiple of the size of a "struct signalfd_siginfo", or a negative
  199  * error code. The "count" parameter must be at least the size of a
  200  * "struct signalfd_siginfo".
  201  */
  202 static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
  203                              loff_t *ppos)
  204 {
  205         struct signalfd_ctx *ctx = file->private_data;
  206         struct signalfd_siginfo __user *siginfo;
  207         int nonblock = file->f_flags & O_NONBLOCK;
  208         ssize_t ret, total = 0;
  209         siginfo_t info;
  210 
  211         count /= sizeof(struct signalfd_siginfo);
  212         if (!count)
  213                 return -EINVAL;
  214 
  215         siginfo = (struct signalfd_siginfo __user *) buf;
  216         do {
  217                 ret = signalfd_dequeue(ctx, &info, nonblock);
  218                 if (unlikely(ret <= 0))
  219                         break;
  220                 ret = signalfd_copyinfo(siginfo, &info);
  221                 if (ret < 0)
  222                         break;
  223                 siginfo++;
  224                 total += ret;
  225                 nonblock = 1;
  226         } while (--count);
  227 
  228         return total ? total: ret;
  229 }
  230 
  231 #ifdef CONFIG_PROC_FS
  232 static int signalfd_show_fdinfo(struct seq_file *m, struct file *f)
  233 {
  234         struct signalfd_ctx *ctx = f->private_data;
  235         sigset_t sigmask;
  236 
  237         sigmask = ctx->sigmask;
  238         signotset(&sigmask);
  239         render_sigset_t(m, "sigmask:\t", &sigmask);
  240 
  241         return 0;
  242 }
  243 #endif
  244 
  245 static const struct file_operations signalfd_fops = {
  246 #ifdef CONFIG_PROC_FS
  247         .show_fdinfo    = signalfd_show_fdinfo,
  248 #endif
  249         .release        = signalfd_release,
  250         .poll           = signalfd_poll,
  251         .read           = signalfd_read,
  252         .llseek         = noop_llseek,
  253 };
  254 
  255 SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,
  256                 size_t, sizemask, int, flags)
  257 {
  258         sigset_t sigmask;
  259         struct signalfd_ctx *ctx;
  260 
  261         /* Check the SFD_* constants for consistency.  */
  262         BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC);
  263         BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK);
  264 
  265         if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))
  266                 return -EINVAL;
  267 
  268         if (sizemask != sizeof(sigset_t) ||
  269             copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
  270                 return -EINVAL;
  271         sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
  272         signotset(&sigmask);
  273 
  274         if (ufd == -1) {
  275                 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
  276                 if (!ctx)
  277                         return -ENOMEM;
  278 
  279                 ctx->sigmask = sigmask;
  280 
  281                 /*
  282                  * When we call this, the initialization must be complete, since
  283                  * anon_inode_getfd() will install the fd.
  284                  */
  285                 ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx,
  286                                        O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK)));
  287                 if (ufd < 0)
  288                         kfree(ctx);
  289         } else {
  290                 struct fd f = fdget(ufd);
  291                 if (!f.file)
  292                         return -EBADF;
  293                 ctx = f.file->private_data;
  294                 if (f.file->f_op != &signalfd_fops) {
  295                         fdput(f);
  296                         return -EINVAL;
  297                 }
  298                 spin_lock_irq(&current->sighand->siglock);
  299                 ctx->sigmask = sigmask;
  300                 spin_unlock_irq(&current->sighand->siglock);
  301 
  302                 wake_up(&current->sighand->signalfd_wqh);
  303                 fdput(f);
  304         }
  305 
  306         return ufd;
  307 }
  308 
  309 SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask,
  310                 size_t, sizemask)
  311 {
  312         return sys_signalfd4(ufd, user_mask, sizemask, 0);
  313 }

Cache object: a13c472662f07215c7b9de4330ac83d4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.