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