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 2007 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 ret; 106 int error = 0; 107 k_siginfo_t info, *infop; 108 model_t datamodel = get_udatamodel(); 109 110 if (timeoutp) { 111 timespec_t now; 112 113 gethrestime(&now); 114 if (datamodel == DATAMODEL_NATIVE) { 115 if (copyin(timeoutp, &sig_timeout, 116 sizeof (sig_timeout))) 117 return (set_errno(EFAULT)); 118 } else { 119 timespec32_t timeout32; 120 121 if (copyin(timeoutp, &timeout32, sizeof (timeout32))) 122 return (set_errno(EFAULT)); 123 TIMESPEC32_TO_TIMESPEC(&sig_timeout, &timeout32) 124 } 125 126 if (itimerspecfix(&sig_timeout)) 127 return (set_errno(EINVAL)); 128 /* 129 * Convert the timespec value into absolute time. 130 */ 131 timespecadd(&sig_timeout, &now); 132 rqtp = &sig_timeout; 133 } 134 if (copyin(setp, &set, sizeof (set))) 135 return (set_errno(EFAULT)); 136 sigutok(&set, &kset); 137 if (sigisempty(&kset)) 138 return (set_errno(EINVAL)); 139 140 mutex_enter(&p->p_lock); 141 /* 142 * set the thread's signal mask to unmask 143 * those signals in the specified set. 144 */ 145 schedctl_finish_sigblock(t); 146 oldmask = t->t_hold; 147 sigdiffset(&t->t_hold, &kset); 148 149 /* 150 * Wait until we take a signal or until 151 * the absolute future time is passed. 152 */ 153 while ((ret = cv_waituntil_sig(&t->t_delay_cv, &p->p_lock, 154 rqtp)) > 0) 155 continue; 156 if (ret == -1) 157 error = EAGAIN; 158 159 /* 160 * Restore thread's signal mask to its previous value. 161 */ 162 t->t_hold = oldmask; 163 t->t_sig_check = 1; /* so post_syscall sees new t_hold mask */ 164 165 if (error) { 166 mutex_exit(&p->p_lock); 167 return (set_errno(error)); /* timer expired */ 168 } 169 /* 170 * Don't bother with signal if it is not in request set. 171 */ 172 if (lwp->lwp_cursig == 0 || !sigismember(&kset, lwp->lwp_cursig)) { 173 mutex_exit(&p->p_lock); 174 /* 175 * lwp_cursig is zero if pokelwps() awakened cv_wait_sig(). 176 * This happens if some other thread in this process called 177 * forkall() or exit(). 178 */ 179 return (set_errno(EINTR)); 180 } 181 182 if (lwp->lwp_curinfo) 183 infop = &lwp->lwp_curinfo->sq_info; 184 else { 185 infop = &info; 186 bzero(infop, sizeof (info)); 187 infop->si_signo = lwp->lwp_cursig; 188 infop->si_code = SI_NOINFO; 189 } 190 191 lwp->lwp_ru.nsignals++; 192 ret = lwp->lwp_cursig; 193 DTRACE_PROC2(signal__clear, int, ret, ksiginfo_t *, infop); 194 lwp->lwp_cursig = 0; 195 lwp->lwp_extsig = 0; 196 mutex_exit(&p->p_lock); 197 198 if (siginfop) 199 ret = copyout_siginfo(datamodel, infop, siginfop); 200 if (lwp->lwp_curinfo) { 201 siginfofree(lwp->lwp_curinfo); 202 lwp->lwp_curinfo = NULL; 203 } 204 return (ret); 205 } 206