Home | History | Annotate | Download | only in syscall
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <sys/param.h>
     30 #include <sys/types.h>
     31 #include <sys/bitmap.h>
     32 #include <sys/sysmacros.h>
     33 #include <sys/systm.h>
     34 #include <sys/user.h>
     35 #include <sys/errno.h>
     36 #include <sys/proc.h>
     37 #include <sys/fault.h>
     38 #include <sys/procset.h>
     39 #include <sys/signal.h>
     40 #include <sys/siginfo.h>
     41 #include <sys/time.h>
     42 #include <sys/kmem.h>
     43 #include <sys/schedctl.h>
     44 #include <sys/debug.h>
     45 #include <sys/condvar_impl.h>
     46 #include <sys/model.h>
     47 #include <sys/sdt.h>
     48 #include <sys/zone.h>
     49 
     50 static int
     51 copyout_siginfo(model_t datamodel, k_siginfo_t *ksip, void *uaddr)
     52 {
     53 	zoneid_t zoneid = getzoneid();
     54 
     55 	if (datamodel == DATAMODEL_NATIVE) {
     56 		if (SI_FROMUSER(ksip) && zoneid != GLOBAL_ZONEID &&
     57 		    zoneid != ksip->si_zoneid) {
     58 			k_siginfo_t sani_sip = *ksip;
     59 			sani_sip.si_pid = curproc->p_zone->zone_zsched->p_pid;
     60 			sani_sip.si_uid = 0;
     61 			sani_sip.si_ctid = -1;
     62 			sani_sip.si_zoneid = zoneid;
     63 			if (copyout(&sani_sip, uaddr, sizeof (sani_sip)))
     64 				return (set_errno(EFAULT));
     65 		} else {
     66 			if (copyout(ksip, uaddr, sizeof (*ksip)))
     67 				return (set_errno(EFAULT));
     68 		}
     69 	}
     70 #ifdef _SYSCALL32_IMPL
     71 	else {
     72 		siginfo32_t si32;
     73 
     74 		siginfo_kto32(ksip, &si32);
     75 		if (SI_FROMUSER(ksip) && zoneid != GLOBAL_ZONEID &&
     76 		    zoneid != ksip->si_zoneid) {
     77 			si32.si_pid = curproc->p_zone->zone_zsched->p_pid;
     78 			si32.si_uid = 0;
     79 			si32.si_ctid = -1;
     80 			si32.si_zoneid = zoneid;
     81 		}
     82 		if (copyout(&si32, uaddr, sizeof (si32)))
     83 			return (set_errno(EFAULT));
     84 	}
     85 #endif
     86 	return (ksip->si_signo);
     87 }
     88 
     89 /*
     90  * Wait until a signal within a specified set is posted or until the
     91  * time interval 'timeout' if specified.  The signal is caught but
     92  * not delivered. The value of the signal is returned to the caller.
     93  */
     94 int
     95 sigtimedwait(sigset_t *setp, siginfo_t *siginfop, timespec_t *timeoutp)
     96 {
     97 	sigset_t set;
     98 	k_sigset_t kset;
     99 	k_sigset_t oldmask;
    100 	kthread_t *t = curthread;
    101 	klwp_t *lwp = ttolwp(t);
    102 	proc_t *p = ttoproc(t);
    103 	timespec_t sig_timeout;
    104 	timespec_t *rqtp = NULL;
    105 	int timecheck = 0;
    106 	int ret;
    107 	int error = 0;
    108 	k_siginfo_t info, *infop;
    109 	model_t datamodel = get_udatamodel();
    110 
    111 	if (timeoutp) {
    112 		timespec_t now;
    113 
    114 		timecheck = timechanged;
    115 		gethrestime(&now);
    116 		if (datamodel == DATAMODEL_NATIVE) {
    117 			if (copyin(timeoutp, &sig_timeout,
    118 			    sizeof (sig_timeout)))
    119 				return (set_errno(EFAULT));
    120 		} else {
    121 			timespec32_t timeout32;
    122 
    123 			if (copyin(timeoutp, &timeout32, sizeof (timeout32)))
    124 				return (set_errno(EFAULT));
    125 			TIMESPEC32_TO_TIMESPEC(&sig_timeout, &timeout32)
    126 		}
    127 
    128 		if (itimerspecfix(&sig_timeout))
    129 			return (set_errno(EINVAL));
    130 		/*
    131 		 * Convert the timespec value into absolute time.
    132 		 */
    133 		timespecadd(&sig_timeout, &now);
    134 		rqtp = &sig_timeout;
    135 	}
    136 	if (copyin(setp, &set, sizeof (set)))
    137 		return (set_errno(EFAULT));
    138 	sigutok(&set, &kset);
    139 	if (sigisempty(&kset))
    140 		return (set_errno(EINVAL));
    141 
    142 	mutex_enter(&p->p_lock);
    143 	/*
    144 	 * set the thread's signal mask to unmask
    145 	 * those signals in the specified set.
    146 	 */
    147 	schedctl_finish_sigblock(t);
    148 	oldmask = t->t_hold;
    149 	sigdiffset(&t->t_hold, &kset);
    150 
    151 	/*
    152 	 * Wait until we take a signal or until
    153 	 * the absolute future time is passed.
    154 	 */
    155 	while ((ret = cv_waituntil_sig(&t->t_delay_cv, &p->p_lock,
    156 	    rqtp, timecheck)) > 0)
    157 		continue;
    158 	if (ret == -1)
    159 		error = EAGAIN;
    160 
    161 	/*
    162 	 * Restore thread's signal mask to its previous value.
    163 	 */
    164 	t->t_hold = oldmask;
    165 	t->t_sig_check = 1;	/* so post_syscall sees new t_hold mask */
    166 
    167 	if (error) {
    168 		mutex_exit(&p->p_lock);
    169 		return (set_errno(error));	/* timer expired */
    170 	}
    171 	/*
    172 	 * Don't bother with signal if it is not in request set.
    173 	 */
    174 	if (lwp->lwp_cursig == 0 || !sigismember(&kset, lwp->lwp_cursig)) {
    175 		mutex_exit(&p->p_lock);
    176 		/*
    177 		 * lwp_cursig is zero if pokelwps() awakened cv_wait_sig().
    178 		 * This happens if some other thread in this process called
    179 		 * forkall() or exit().
    180 		 */
    181 		return (set_errno(EINTR));
    182 	}
    183 
    184 	if (lwp->lwp_curinfo)
    185 		infop = &lwp->lwp_curinfo->sq_info;
    186 	else {
    187 		infop = &info;
    188 		bzero(infop, sizeof (info));
    189 		infop->si_signo = lwp->lwp_cursig;
    190 		infop->si_code = SI_NOINFO;
    191 	}
    192 
    193 	lwp->lwp_ru.nsignals++;
    194 	ret = lwp->lwp_cursig;
    195 	DTRACE_PROC2(signal__clear, int, ret, ksiginfo_t *, infop);
    196 	lwp->lwp_cursig = 0;
    197 	lwp->lwp_extsig = 0;
    198 	mutex_exit(&p->p_lock);
    199 
    200 	if (siginfop)
    201 		ret = copyout_siginfo(datamodel, infop, siginfop);
    202 	if (lwp->lwp_curinfo) {
    203 		siginfofree(lwp->lwp_curinfo);
    204 		lwp->lwp_curinfo = NULL;
    205 	}
    206 	return (ret);
    207 }
    208