1/* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. --- 22 unchanged lines hidden (view full) --- 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)sys_generic.c 8.5 (Berkeley) 1/21/94 |
39 * $FreeBSD: head/sys/kern/sys_generic.c 92252 2002-03-14 01:32:30Z alfred $ |
40 */ 41 42#include "opt_ktrace.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/sysproto.h> 47#include <sys/filedesc.h> --- 643 unchanged lines hidden (view full) --- 691 if (memp) 692 free(memp, M_IOCTLOPS); 693 fdrop(fp, td); 694done: 695 mtx_unlock(&Giant); 696 return (error); 697} 698 |
699/* 700 * sellock and selwait are initialized in selectinit() via SYSINIT. 701 */ 702struct mtx sellock; |
703struct cv selwait; |
704int nselcoll; /* Select collisions since boot */ |
705SYSCTL_INT(_kern, OID_AUTO, nselcoll, CTLFLAG_RD, &nselcoll, 0, ""); 706 707/* 708 * Select system call. 709 */ 710#ifndef _SYS_SYSPROTO_H_ 711struct select_args { 712 int nd; --- 61 unchanged lines hidden (view full) --- 774 if (uap->name == NULL) \ 775 ibits[x] = NULL; \ 776 else { \ 777 ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \ 778 obits[x] = sbp; \ 779 sbp += ncpbytes / sizeof *sbp; \ 780 error = copyin(uap->name, ibits[x], ncpbytes); \ 781 if (error != 0) \ |
782 goto done_nosellock; \ |
783 } \ 784 } while (0) 785 getbits(in, 0); 786 getbits(ou, 1); 787 getbits(ex, 2); 788#undef getbits 789 if (nbufbytes != 0) 790 bzero(selbits, nbufbytes / 2); 791 792 if (uap->tv) { 793 error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 794 sizeof (atv)); 795 if (error) |
796 goto done_nosellock; |
797 if (itimerfix(&atv)) { 798 error = EINVAL; |
799 goto done_nosellock; |
800 } 801 getmicrouptime(&rtv); 802 timevaladd(&atv, &rtv); 803 } else { 804 atv.tv_sec = 0; 805 atv.tv_usec = 0; 806 } 807 timo = 0; |
808 mtx_lock(&sellock); |
809retry: 810 ncoll = nselcoll; 811 mtx_lock_spin(&sched_lock); 812 td->td_flags |= TDF_SELECT; 813 mtx_unlock_spin(&sched_lock); |
814 mtx_unlock(&sellock); 815 816 /* XXX Is there a better place for this? */ 817 TAILQ_INIT(&td->td_selq); |
818 error = selscan(td, ibits, obits, uap->nd); |
819 mtx_lock(&sellock); |
820 if (error || td->td_retval[0]) 821 goto done; 822 if (atv.tv_sec || atv.tv_usec) { 823 getmicrouptime(&rtv); |
824 if (timevalcmp(&rtv, &atv, >=)) |
825 goto done; |
826 ttv = atv; 827 timevalsub(&ttv, &rtv); 828 timo = ttv.tv_sec > 24 * 60 * 60 ? 829 24 * 60 * 60 * hz : tvtohz(&ttv); 830 } |
831 832 /* 833 * An event of interest may occur while we do not hold 834 * sellock, so check TDF_SELECT and the number of 835 * collisions and rescan the file descriptors if 836 * necessary. 837 */ |
838 mtx_lock_spin(&sched_lock); |
839 if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { 840 mtx_unlock_spin(&sched_lock); 841 goto retry; 842 } |
843 mtx_unlock_spin(&sched_lock); 844 845 if (timo > 0) |
846 error = cv_timedwait_sig(&selwait, &sellock, timo); |
847 else |
848 error = cv_wait_sig(&selwait, &sellock); |
849 850 if (error == 0) 851 goto retry; 852 853done: |
854 clear_selinfo_list(td); |
855 mtx_lock_spin(&sched_lock); 856 td->td_flags &= ~TDF_SELECT; 857 mtx_unlock_spin(&sched_lock); |
858 mtx_unlock(&sellock); 859 860done_nosellock: |
861 /* select is not restarted after signals... */ 862 if (error == ERESTART) 863 error = EINTR; 864 if (error == EWOULDBLOCK) 865 error = 0; 866#define putbits(name, x) \ 867 if (uap->name && (error2 = copyout(obits[x], uap->name, ncpbytes))) \ 868 error = error2; --- 95 unchanged lines hidden (view full) --- 964 } 965 ni = nfds * sizeof(struct pollfd); 966 if (ni > sizeof(smallbits)) 967 bits = malloc(ni, M_TEMP, M_WAITOK); 968 else 969 bits = smallbits; 970 error = copyin(SCARG(uap, fds), bits, ni); 971 if (error) |
972 goto done_nosellock; |
973 if (SCARG(uap, timeout) != INFTIM) { 974 atv.tv_sec = SCARG(uap, timeout) / 1000; 975 atv.tv_usec = (SCARG(uap, timeout) % 1000) * 1000; 976 if (itimerfix(&atv)) { 977 error = EINVAL; |
978 goto done_nosellock; |
979 } 980 getmicrouptime(&rtv); 981 timevaladd(&atv, &rtv); 982 } else { 983 atv.tv_sec = 0; 984 atv.tv_usec = 0; 985 } 986 timo = 0; |
987 mtx_lock(&sellock); |
988retry: 989 ncoll = nselcoll; 990 mtx_lock_spin(&sched_lock); 991 td->td_flags |= TDF_SELECT; 992 mtx_unlock_spin(&sched_lock); |
993 mtx_unlock(&sellock); 994 995 /* XXX Is there a better place for this? */ 996 TAILQ_INIT(&td->td_selq); |
997 error = pollscan(td, (struct pollfd *)bits, nfds); |
998 mtx_lock(&sellock); |
999 if (error || td->td_retval[0]) 1000 goto done; 1001 if (atv.tv_sec || atv.tv_usec) { 1002 getmicrouptime(&rtv); |
1003 if (timevalcmp(&rtv, &atv, >=)) |
1004 goto done; |
1005 ttv = atv; 1006 timevalsub(&ttv, &rtv); 1007 timo = ttv.tv_sec > 24 * 60 * 60 ? 1008 24 * 60 * 60 * hz : tvtohz(&ttv); 1009 } |
1010 /* 1011 * An event of interest may occur while we do not hold 1012 * sellock, so check TDF_SELECT and the number of collisions 1013 * and rescan the file descriptors if necessary. 1014 */ |
1015 mtx_lock_spin(&sched_lock); |
1016 if ((td->td_flags & TDF_SELECT) == 0 || nselcoll != ncoll) { 1017 mtx_unlock_spin(&sched_lock); 1018 goto retry; 1019 } |
1020 mtx_unlock_spin(&sched_lock); |
1021 |
1022 if (timo > 0) |
1023 error = cv_timedwait_sig(&selwait, &sellock, timo); |
1024 else |
1025 error = cv_wait_sig(&selwait, &sellock); 1026 |
1027 if (error == 0) 1028 goto retry; 1029 1030done: |
1031 clear_selinfo_list(td); |
1032 mtx_lock_spin(&sched_lock); 1033 td->td_flags &= ~TDF_SELECT; 1034 mtx_unlock_spin(&sched_lock); |
1035 mtx_unlock(&sellock); 1036 1037done_nosellock: |
1038 /* poll is not restarted after signals... */ 1039 if (error == ERESTART) 1040 error = EINTR; 1041 if (error == EWOULDBLOCK) 1042 error = 0; 1043 if (error == 0) { 1044 error = copyout(bits, SCARG(uap, fds), ni); 1045 if (error) --- 64 unchanged lines hidden (view full) --- 1110int 1111openbsd_poll(td, uap) 1112 register struct thread *td; 1113 register struct openbsd_poll_args *uap; 1114{ 1115 return (poll(td, (struct poll_args *)uap)); 1116} 1117 |
1118/* 1119 * Remove the references to the thread from all of the objects 1120 * we were polling. 1121 * 1122 * This code assumes that the underlying owner of the selinfo 1123 * structure will hold sellock before it changes it, and that 1124 * it will unlink itself from our list if it goes away. 1125 */ 1126void 1127clear_selinfo_list(td) 1128 struct thread *td; 1129{ 1130 struct selinfo *si; 1131 1132 mtx_assert(&sellock, MA_OWNED); 1133 TAILQ_FOREACH(si, &td->td_selq, si_thrlist) 1134 si->si_thread = NULL; 1135 TAILQ_INIT(&td->td_selq); 1136} 1137 |
1138/*ARGSUSED*/ 1139int 1140seltrue(dev, events, td) 1141 dev_t dev; 1142 int events; 1143 struct thread *td; 1144{ 1145 1146 return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 1147} 1148 |
1149/* 1150 * Record a select request. 1151 */ 1152void 1153selrecord(selector, sip) 1154 struct thread *selector; 1155 struct selinfo *sip; 1156{ |
1157 |
1158 mtx_lock(&sellock); 1159 /* 1160 * If the thread is NULL then take ownership of selinfo 1161 * however if the thread is not NULL and the thread points to 1162 * someone else, then we have a collision, otherwise leave it alone 1163 * as we've owned it in a previous selrecord on this selinfo. 1164 */ 1165 if (sip->si_thread == NULL) { 1166 sip->si_thread = selector; 1167 TAILQ_INSERT_TAIL(&selector->td_selq, sip, si_thrlist); 1168 } else if (sip->si_thread != selector) { 1169 sip->si_flags |= SI_COLL; |
1170 } |
1171 1172 mtx_unlock(&sellock); |
1173} 1174 1175/* 1176 * Do a wakeup when a selectable event occurs. 1177 */ 1178void 1179selwakeup(sip) |
1180 struct selinfo *sip; |
1181{ 1182 struct thread *td; |
1183 |
1184 mtx_lock(&sellock); 1185 td = sip->si_thread; 1186 if ((sip->si_flags & SI_COLL) != 0) { |
1187 nselcoll++; 1188 sip->si_flags &= ~SI_COLL; 1189 cv_broadcast(&selwait); 1190 } |
1191 if (td == NULL) { 1192 mtx_unlock(&sellock); 1193 return; |
1194 } |
1195 TAILQ_REMOVE(&td->td_selq, sip, si_thrlist); 1196 sip->si_thread = NULL; 1197 mtx_lock_spin(&sched_lock); 1198 if (td->td_wchan == (caddr_t)&selwait) { 1199 if (td->td_proc->p_stat == SSLEEP) 1200 setrunnable(td); 1201 else 1202 cv_waitq_remove(td); 1203 } else 1204 td->td_flags &= ~TDF_SELECT; 1205 mtx_unlock_spin(&sched_lock); 1206 mtx_unlock(&sellock); |
1207} 1208 1209static void selectinit __P((void *)); 1210SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, selectinit, NULL) 1211 1212/* ARGSUSED*/ 1213static void 1214selectinit(dummy) 1215 void *dummy; 1216{ 1217 cv_init(&selwait, "select"); |
1218 mtx_init(&sellock, "sellck", MTX_DEF); |
1219} |