SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, size_t, sizemask, int, flags) { sigset_t sigmask; struct signalfd_ctx *ctx; BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK); if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) return -EINVAL; if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) return -EINVAL; sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(&sigmask); if (ufd == -1) { ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; ctx->sigmask = sigmask; ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK))); if (ufd < 0) kfree(ctx); } else { struct file *file = fget(ufd); if (!file) return -EBADF; ctx = file->private_data; if (file->f_op != &signalfd_fops) { fput(file); return -EINVAL; } spin_lock_irq(¤t->sighand->siglock); ctx->sigmask = sigmask; spin_unlock_irq(¤t->sighand->siglock); wake_up(¤t->sighand->signalfd_wqh); fput(file); } return ufd; }
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) { sigset_t sigmask; struct signalfd_ctx *ctx; if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) return -EINVAL; sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(&sigmask); if (ufd == -1) { ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; ctx->sigmask = sigmask; /* * When we call this, the initialization must be complete, since * anon_inode_getfd() will install the fd. */ ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx); if (ufd < 0) kfree(ctx); } else { struct file *file = fget(ufd); if (!file) return -EBADF; ctx = file->private_data; if (file->f_op != &signalfd_fops) { fput(file); return -EINVAL; } spin_lock_irq(¤t->sighand->siglock); ctx->sigmask = sigmask; spin_unlock_irq(¤t->sighand->siglock); wake_up(¤t->sighand->signalfd_wqh); fput(file); } return ufd; }
SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, size_t, sizemask, int, flags) { sigset_t sigmask; /* Check the SFD_* constants for consistency. */ BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK); if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) return -EINVAL; if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) return -EINVAL; sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(&sigmask); return do_signalfd(ufd, &sigmask, flags); }
int sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo, struct compat_timespec *uts, compat_time_t sigsetsize) { int ret, sig; sigset_t these; compat_sigset_t these32; struct timespec ts; siginfo_t info; long timeout = 0; /* * As the result of a brainfarting competition a few years ago the * size of sigset_t for the 32-bit kernel was choosen to be 128 bits * but nothing so far is actually using that many, 64 are enough. So * for now we just drop the high bits. */ if (copy_from_user (&these32, uthese, sizeof(compat_old_sigset_t))) return -EFAULT; switch (_NSIG_WORDS) { #ifdef __MIPSEB__ case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); #endif #ifdef __MIPSEL__ case 4: these.sig[3] = these32.sig[7] | (((long)these32.sig[6]) << 32); case 3: these.sig[2] = these32.sig[5] | (((long)these32.sig[4]) << 32); case 2: these.sig[1] = these32.sig[3] | (((long)these32.sig[2]) << 32); case 1: these.sig[0] = these32.sig[1] | (((long)these32.sig[0]) << 32); #endif } /* * Invert the set of allowed signals to get those we * want to block. */ sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); signotset(&these); if (uts) { if (get_user (ts.tv_sec, &uts->tv_sec) || get_user (ts.tv_nsec, &uts->tv_nsec)) return -EINVAL; if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 || ts.tv_sec < 0) return -EINVAL; } spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); if (!sig) { /* None ready -- temporarily unblock those we're interested in so that we'll be awakened when they arrive. */ sigset_t oldblocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &these); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); timeout = MAX_SCHEDULE_TIMEOUT; if (uts) timeout = (timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec)); current->state = TASK_INTERRUPTIBLE; timeout = schedule_timeout(timeout); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); current->blocked = oldblocked; recalc_sigpending(); } spin_unlock_irq(¤t->sighand->siglock); if (sig) { ret = sig; if (uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) ret = -EFAULT; } } else { ret = -EAGAIN; if (timeout) ret = -EINTR; } return ret; }