pselect_v2.diff

nthery, 12/29/2007 10:15 PM

Download (16.4 KB)

View differences:

dfly/src/sys/kern/sys_generic.c 2007-12-29 23:02:24.000000000 +0100
77 77
static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
78 78
MALLOC_DEFINE(M_IOV, "iov", "large iov's");
79 79

  
80
static int 	doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex,
81
			struct timeval *tv, int *res);
80 82
static int	pollscan (struct proc *, struct pollfd *, u_int, int *);
81 83
static int	selscan (struct proc *, fd_mask **, fd_mask **,
82 84
			int, int *);
......
760 762
int
761 763
sys_select(struct select_args *uap)
762 764
{
765
	struct timeval ktv;
766
	struct timeval *ktvp;
767
	int error;
768

  
769
	/*
770
	 * Get timeout if any.
771
	 */
772
	if (uap->tv != NULL) {
773
		error = copyin(uap->tv, &ktv, sizeof (ktv));
774
		if (error)
775
			return (error);
776
		error = itimerfix(&ktv);
777
		if (error)
778
			return (error);
779
		ktvp = &ktv;
780
	} else {
781
		ktvp = NULL;
782
	}
783

  
784
	/*
785
	 * Do real work.
786
	 */
787
	error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
788
			&uap->sysmsg_result);
789

  
790
	return (error);
791
}
792

  
793

  
794
/*
795
 * Pselect system call.
796
 */
797
int
798
sys_pselect(struct pselect_args *uap)
799
{
800
	struct thread *td = curthread;
801
	struct lwp *lp = td->td_lwp;
802
	struct timespec kts;
803
	struct timeval ktv;
804
	struct timeval *ktvp;
805
	sigset_t sigmask;
806
	int error;
807

  
808
	/*
809
	 * Get timeout if any and convert it.
810
	 * Round up during conversion to avoid timeout going off early.
811
	 */
812
	if (uap->ts != NULL) {
813
		error = copyin(uap->ts, &kts, sizeof (kts));
814
		if (error)
815
			return (error);
816
		ktv.tv_sec = kts.tv_sec;
817
		ktv.tv_usec = (kts.tv_nsec + 999) / 1000;
818
		error = itimerfix(&ktv);
819
		if (error)
820
			return (error);
821
		ktvp = &ktv;
822
	} else {
823
		ktvp = NULL;
824
	}
825

  
826
	/*
827
	 * Install temporary signal mask if any provided.
828
	 */
829
	if (uap->sigmask != NULL) {
830
		error = copyin(uap->sigmask, &sigmask, sizeof(sigmask));
831
		if (error)
832
			return (error);
833
		lp->lwp_oldsigmask = lp->lwp_sigmask;
834
		SIG_CANTMASK(sigmask);
835
		lp->lwp_sigmask = sigmask;
836
	}
837

  
838
	/*
839
	 * Do real job.
840
	 */
841
	error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
842
			&uap->sysmsg_result);
843

  
844
	if (uap->sigmask != NULL) {
845
		/* doselect() responsible for turning ERESTART into EINTR */
846
		KKASSERT(error != ERESTART);
847
		if (error == EINTR) {
848
			/*
849
			 * We can't restore the previous signal mask now
850
			 * because it could block the signal that interrupted
851
			 * us.  So make a note to restore it after executing
852
			 * the handler.
853
			 */
854
			lp->lwp_flag |= LWP_OLDMASK;
855
		} else {
856
			/*
857
			 * No handler to run. Restore previous mask immediately.
858
			 */
859
			lp->lwp_sigmask = lp->lwp_oldsigmask;
860
		}
861
	}
862

  
863
	return (error);
864
}
865

  
866
/*
867
 * Common code for sys_select() and sys_pselect().
868
 *
869
 * in, out and ex are userland pointers.  tv must point to validated
870
 * kernel-side timeout value or NULL for infinite timeout.  res must
871
 * point to syscall return value.
872
 */
873
static int
874
doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv,
875
		int *res)
876
{
763 877
	struct lwp *lp = curthread->td_lwp;
764 878
	struct proc *p = curproc;
765 879

  
......
775 889
	int ncoll, error, timo;
776 890
	u_int nbufbytes, ncpbytes, nfdbits;
777 891

  
778
	if (uap->nd < 0)
892
	if (nd < 0)
779 893
		return (EINVAL);
780
	if (uap->nd > p->p_fd->fd_nfiles)
781
		uap->nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
894
	if (nd > p->p_fd->fd_nfiles)
895
		nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
782 896

  
783 897
	/*
784 898
	 * Allocate just enough bits for the non-null fd_sets.  Use the
785 899
	 * preallocated auto buffer if possible.
786 900
	 */
787
	nfdbits = roundup(uap->nd, NFDBITS);
901
	nfdbits = roundup(nd, NFDBITS);
788 902
	ncpbytes = nfdbits / NBBY;
789 903
	nbufbytes = 0;
790
	if (uap->in != NULL)
904
	if (in != NULL)
791 905
		nbufbytes += 2 * ncpbytes;
792
	if (uap->ou != NULL)
906
	if (ou != NULL)
793 907
		nbufbytes += 2 * ncpbytes;
794
	if (uap->ex != NULL)
908
	if (ex != NULL)
795 909
		nbufbytes += 2 * ncpbytes;
796 910
	if (nbufbytes <= sizeof s_selbits)
797 911
		selbits = &s_selbits[0];
......
806 920
	sbp = selbits;
807 921
#define	getbits(name, x) \
808 922
	do {								\
809
		if (uap->name == NULL)					\
923
		if (name == NULL)					\
810 924
			ibits[x] = NULL;				\
811 925
		else {							\
812 926
			ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp;	\
813 927
			obits[x] = sbp;					\
814 928
			sbp += ncpbytes / sizeof *sbp;			\
815
			error = copyin(uap->name, ibits[x], ncpbytes);	\
929
			error = copyin(name, ibits[x], ncpbytes);	\
816 930
			if (error != 0)					\
817 931
				goto done;				\
818 932
		}							\
......
824 938
	if (nbufbytes != 0)
825 939
		bzero(selbits, nbufbytes / 2);
826 940

  
827
	if (uap->tv) {
828
		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
829
			sizeof (atv));
830
		if (error)
831
			goto done;
832
		if (itimerfix(&atv)) {
833
			error = EINVAL;
834
			goto done;
835
		}
941
	if (tv != NULL) {
942
		atv = *tv;
836 943
		getmicrouptime(&rtv);
837 944
		timevaladd(&atv, &rtv);
838 945
	} else {
......
843 950
retry:
844 951
	ncoll = nselcoll;
845 952
	lp->lwp_flag |= LWP_SELECT;
846
	error = selscan(p, ibits, obits, uap->nd, &uap->sysmsg_result);
847
	if (error || uap->sysmsg_result)
953
	error = selscan(p, ibits, obits, nd, res);
954
	if (error || *res)
848 955
		goto done;
849 956
	if (atv.tv_sec || atv.tv_usec) {
850 957
		getmicrouptime(&rtv);
851
		if (timevalcmp(&rtv, &atv, >=)) 
958
		if (timevalcmp(&rtv, &atv, >=))
852 959
			goto done;
853 960
		ttv = atv;
854 961
		timevalsub(&ttv, &rtv);
......
875 982
	if (error == EWOULDBLOCK)
876 983
		error = 0;
877 984
#define	putbits(name, x) \
878
	if (uap->name && (error2 = copyout(obits[x], uap->name, ncpbytes))) \
985
	if (name && (error2 = copyout(obits[x], name, ncpbytes))) \
879 986
		error = error2;
880 987
	if (error == 0) {
881 988
		int error2;
dfly/src/sys/kern/syscalls.master 2007-12-27 02:20:49.000000000 +0100
681 681
496	STD	BSD	{ lwpid_t lwp_gettid(void); }
682 682
497	STD	BSD	{ int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
683 683
498	STD	BSD	{ int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
684
499	STD	BSD	{ int pselect(int nd, fd_set *in, fd_set *ou, \
685
			    fd_set *ex, const struct timespec *ts,    \
686
			    const sigset_t *sigmask); }
dfly/src/include/unistd.h 2007-12-27 02:20:49.000000000 +0100
195 195
struct timeval;				/* select(2) */
196 196
int	 select(int, fd_set * __restrict, fd_set * __restrict,
197 197
		fd_set * __restrict, struct timeval * __restrict);
198
struct timespec;			/* pselect(2) */
199
int	 pselect(int, fd_set * __restrict, fd_set * __restrict,
200
		fd_set * __restrict, const struct timespec * __restrict,
201
		const sigset_t * __restrict);
198 202
#endif
199 203
int	 setdomainname(const char *, int);
200 204
int	 setegid(gid_t);
dfly/src/sys/sys/select.h 2007-12-27 02:20:49.000000000 +0100
85 85
struct timeval;
86 86
int	select(int, fd_set * __restrict, fd_set * __restrict,
87 87
	       fd_set * __restrict, struct timeval * __restrict);
88
struct timespec;
89
int	 pselect(int, fd_set * __restrict, fd_set * __restrict,
90
		fd_set * __restrict, const struct timespec * __restrict,
91
		const sigset_t * __restrict);
88 92
#endif
89 93
__END_DECLS
90 94

  
dfly/src/lib/libthread_xu/thread/thr_syscalls.c 2007-12-27 02:20:49.000000000 +0100
95 95

  
96 96
extern int	__creat(const char *, mode_t);
97 97
extern int	__pause(void);
98
extern int	__pselect(int, fd_set *, fd_set *, fd_set *,
98
extern int	__sys_pselect(int, fd_set *, fd_set *, fd_set *,
99 99
			const struct timespec *, const sigset_t *);
100 100
extern unsigned	__sleep(unsigned int);
101 101
extern int	__system(const char *);
......
382 382
}
383 383

  
384 384
__strong_reference(__poll, poll);
385
#if 0
386 385

  
387 386
int 
388
_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, 
387
__pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
389 388
	const struct timespec *timo, const sigset_t *mask)
390 389
{
391 390
	struct pthread *curthread = tls_get_curthread();
......
393 392
	int ret;
394 393

  
395 394
	oldcancel = _thr_cancel_enter(curthread);
396
	ret = __pselect(count, rfds, wfds, efds, timo, mask);
395
	ret = __sys_pselect(count, rfds, wfds, efds, timo, mask);
397 396
	_thr_cancel_leave(curthread, oldcancel);
398 397

  
399 398
	return (ret);
400 399
}
401
__strong_reference(_pselect, pselect);
402
#endif
400
__strong_reference(__pselect, pselect);
403 401

  
404 402

  
405 403
int
dfly/src/lib/libc_r/uthread/uthread_select.c 2007-12-27 02:20:49.000000000 +0100
228 228

  
229 229
	return ret;
230 230
}
231

  
232

  
233
int
234
pselect(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
235
	const struct timespec *timeout, const sigset_t *mask)
236
{
237
	sigset_t omask;
238
	struct timeval tv;
239
	struct timeval *tvp;
240
	int ret;
241

  
242
	_thread_enter_cancellation_point();
243

  
244
	if (timeout != NULL) {
245
		tv.tv_sec = timeout->tv_sec;
246
		tv.tv_usec = (timeout->tv_nsec + 999) / 1000;
247
		tvp = &tv;
248
	} else {
249
		tvp = NULL;
250
	}
251

  
252
	/*
253
	 * XXX The masking/select/unmasking sequence below is not atomic.  See
254
	 * man page.
255
	 *
256
	 * The Right Thing would be to mask/unmask signals kernel-side.  We do
257
	 * this for single-threaded and libthread_xu processes but this is far
258
	 * from trivial for libc_r because select() is actually a poll()
259
	 * wrapper there and not using poll() would involve complex changes in
260
	 * the user thread scheduler.  We're deprecating libc_r in favor of
261
	 * libthread_xu so the usefulness of such a change is questionable.
262
	 */
263

  
264
	if (mask != NULL)
265
		(void) sigprocmask(SIG_SETMASK, mask, &omask);
266

  
267
	ret = _select(numfds, readfds, writefds, exceptfds, tvp);
268

  
269
	if (mask != NULL)
270
		(void) sigprocmask(SIG_SETMASK, &omask, NULL);
271

  
272
	_thread_leave_cancellation_point();
273

  
274
	return ret;
275
}
dfly/src/lib/libc/sys/Makefile.inc 2007-12-27 02:20:49.000000000 +0100
91 91
	sigstack.2 sigsuspend.2 socket.2 socketpair.2 stat.2 statfs.2 \
92 92
	swapon.2 symlink.2 sync.2 sysarch.2 syscall.2 syslink.2 \
93 93
	truncate.2 tls.2 umask.2 umtx.2 undelete.2 \
94
	unlink.2 utimes.2 upc_register.2 usched_set.2 uuidgen.2 vfork.2 wait.2 write.2
94
	unlink.2 utimes.2 upc_register.2 usched_set.2 uuidgen.2 vfork.2 \
95
	wait.2 write.2 pselect.2
96

  
95 97
.if !defined(NO_P1003_1B)
96 98
MAN+=	sched_get_priority_max.2 sched_setparam.2 \
97 99
	sched_setscheduler.2 sched_yield.2
dfly/src/lib/libc/sys/pselect.2 2007-12-27 02:20:49.000000000 +0100
1
.\"
2
.\" Copyright 2002 Massachusetts Institute of Technology
3
.\"
4
.\" Permission to use, copy, modify, and distribute this software and
5
.\" its documentation for any purpose and without fee is hereby
6
.\" granted, provided that both the above copyright notice and this
7
.\" permission notice appear in all copies, that both the above
8
.\" copyright notice and this permission notice appear in all
9
.\" supporting documentation, and that the name of M.I.T. not be used
10
.\" in advertising or publicity pertaining to distribution of the
11
.\" software without specific, written prior permission.  M.I.T. makes
12
.\" no representations about the suitability of this software for any
13
.\" purpose.  It is provided "as is" without express or implied
14
.\" warranty.
15
.\"
16
.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17
.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20
.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26
.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
.\" SUCH DAMAGE.
28
.\"
29
.\" $FreeBSD: src/lib/libc/gen/pselect.3,v 1.4 2002/12/18 10:13:54 ru Exp $
30
.\"
31
.Dd December 24, 2007
32
.Dt PSELECT 2
33
.Os
34
.Sh NAME
35
.Nm pselect
36
.Nd synchronous I/O multiplexing a la POSIX.1g
37
.Sh LIBRARY
38
.Lb libc
39
.Sh SYNOPSIS
40
.In sys/select.h
41
.Ft int
42
.Fo pselect
43
.Fa "int nfds"
44
.Fa "fd_set * restrict readfds"
45
.Fa "fd_set * restrict writefds"
46
.Fa "fd_set * restrict exceptfds"
47
.Fa "const struct timespec * restrict timeout"
48
.Fa "const sigset_t * restrict newsigmask"
49
.Fc
50
.Sh DESCRIPTION
51
The
52
.Fn pselect
53
function was introduced by
54
.St -p1003.1g-2000
55
as a slightly stronger version of
56
.Xr select 2 .
57
The
58
.Fa nfds , readfds , writefds ,
59
and
60
.Fa exceptfds
61
arguments are all identical to the analogous arguments of
62
.Fn select .
63
The
64
.Fa timeout
65
argument in
66
.Fn pselect
67
points to a
68
.Vt "const struct timespec"
69
rather than the (modifiable)
70
.Vt "struct timeval"
71
used by
72
.Fn select ;
73
as in
74
.Fn select ,
75
a null pointer may be passed to indicate that
76
.Fn pselect
77
should wait indefinitely.
78
Finally,
79
.Fa newsigmask
80
specifies a signal mask which is set while waiting for input.
81
When
82
.Fn pselect
83
returns, the original signal mask is restored.
84
.Pp
85
See
86
.Xr select 2
87
for a more detailed discussion of the semantics of this interface, and
88
for macros used to manipulate the
89
.Vt "fd_set"
90
data type.
91
.Sh RETURN VALUES
92
The
93
.Fn pselect
94
function returns the same values and under the same conditions as
95
.Fn select .
96
.Sh ERRORS
97
The
98
.Fn pselect
99
function may fail for any of the reasons documented for
100
.Xr select 2
101
and (if a signal mask is provided)
102
.Xr sigprocmask 2 .
103
.Sh SEE ALSO
104
.Xr kqueue 2 ,
105
.Xr poll 2 ,
106
.Xr select 2 ,
107
.Xr sigprocmask 2
108
.Sh STANDARDS
109
The
110
.Fn pselect
111
function conforms to
112
.St -p1003.1-2001 .
113
.Sh BUGS
114
The
115
.Fn pselect
116
implementation in libc_r (user multi-threading) does not mask signals, calls
117
.Fn select ,
118
and restores the original signal mask atomically.  A calling user thread
119
using
120
.Fn pselect
121
to block until either a signal occurs or some descriptor changes may therefore
122
block forever.
123
The
124
.Fn pselect
125
implementations in libthread_xu (kernel multi-threading) and libc
126
(single-threading) operate atomically and are therefore race-free.
127
.Sh HISTORY
128
The
129
.Fn pselect
130
function first appeared in
131
.Dx 1.11 .
132
.Sh AUTHORS
133
This manual page was originally written by
134
.An Garrett Wollman Aq wollman@FreeBSD.org
135
for FreeBSD and later modified for DragonFly.
dfly/src/lib/libbind/port_after.h 2007-12-27 02:20:49.000000000 +0100
13 13
#include <inttypes.h>
14 14
#endif
15 15

  
16
#define NEED_PSELECT
17 16
#define HAVE_SA_LEN 1
18 17
#define HAVE_MINIMUM_IFREQ 1
19 18
#undef NEED_DAEMON
dfly/src/sys/platform/pc32/i386/trap.c 2007-12-29 22:58:02.000000000 +0100
302 302
		rel_mplock();
303 303
		goto recheck;
304 304
	}
305

  
306
	/*
307
	 * Make sure postsig() handled request to restore old signal mask after
308
	 * running signal handler.
309
	 */
310
	KKASSERT((lp->lwp_flag & LWP_OLDMASK) == 0);
305 311
}
306 312

  
307 313
/*
dfly/src/sys/platform/vkernel/i386/trap.c 2007-12-29 22:58:02.000000000 +0100
286 286
		rel_mplock();
287 287
		goto recheck;
288 288
	}
289

  
290
	/*
291
	 * Make sure postsig() handled request to restore old signal mask after
292
	 * running signal handler.
293
	 */
294
	KKASSERT((lp->lwp_flag & LWP_OLDMASK) == 0);
289 295
}
290 296

  
291 297
/*