1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* Poll a set of streams to see if any is available for I/O.
25 ** Ready streams are moved to front of array but retain the
26 ** same relative order.
28 ** Written by Kiem-Phong Vo.
32 int sfpoll(Sfio_t
** fa
, reg
int n
, int tm
)
35 Sfio_t
** fa
; /* array of streams to poll */
36 reg
int n
; /* number of streams in array */
37 int tm
; /* time in millisecs for select/poll */
42 reg
int *status
, *check
;
47 if(!(status
= (int*)malloc(2*n
*sizeof(int))) )
49 check
= status
+n
; /* streams that need polling */
51 /* a SF_READ stream is ready if there is buffered read data */
52 #define RDREADY(f) (((f->mode&SF_READ) && f->next < f->endb) || \
53 ((f->mode&SF_WRITE) && f->proc && f->proc->ndata > 0) )
55 /* a SF_WRITE stream is ready if there is no write data */
56 #define WRREADY(f) (!(f->mode&SF_WRITE) || f->next == f->data)
58 #define HASAUXFD(f) (f->proc && f->proc->file >= 0 && f->proc->file != f->file)
60 for(r
= c
= 0; r
< n
; ++r
) /* compute streams that must be checked */
64 /* check accessibility */
66 if((int)f
->mode
!= m
&& _sfmode(f
,m
,0) < 0)
69 if((f
->flags
&SF_READ
) && RDREADY(f
))
72 if((f
->flags
&SF_WRITE
) && WRREADY(f
))
73 status
[r
] |= SF_WRITE
;
75 if((f
->flags
&SF_RDWR
) == status
[r
])
78 /* has discipline, ask its opinion */
79 if(f
->disc
&& f
->disc
->exceptf
)
80 { if((m
= (*f
->disc
->exceptf
)(f
,SF_DPOLL
,&tm
,f
->disc
)) < 0)
83 { status
[r
] = m
&SF_RDWR
;
88 if(f
->extent
< 0) /* unseekable stream, must poll/select */
90 else /* seekable streams are always ready */
91 { if(f
->flags
&SF_READ
)
94 status
[r
] |= SF_WRITE
;
101 { struct pollfd
* fds
;
103 /* construct the poll array */
104 for(m
= 0, r
= 0; r
< c
; ++r
, ++m
)
109 if(!(fds
= (struct pollfd
*)malloc(m
*sizeof(struct pollfd
))) )
112 for(m
= 0, r
= 0; r
< c
; ++r
, ++m
)
116 fds
[m
].events
= fds
[m
].revents
= 0;
118 if((f
->flags
&SF_WRITE
) && !WRREADY(f
) )
119 fds
[m
].events
|= POLLOUT
;
121 if((f
->flags
&SF_READ
) && !RDREADY(f
) )
122 { /* a sfpopen situation with two file descriptors */
123 if((f
->mode
&SF_WRITE
) && HASAUXFD(f
))
125 fds
[m
].fd
= f
->proc
->file
;
129 fds
[m
].events
|= POLLIN
;
133 while((np
= SFPOLL(fds
,m
,tm
)) < 0 )
134 { if(errno
== EINTR
|| errno
== EAGAIN
)
138 if(np
> 0) /* poll succeeded */
141 for(m
= 0, r
= 0; r
< np
; ++r
, ++m
)
144 if((f
->flags
&SF_WRITE
) && !WRREADY(f
) )
145 { if(fds
[m
].revents
&POLLOUT
)
146 status
[check
[r
]] |= SF_WRITE
;
149 if((f
->flags
&SF_READ
) && !RDREADY(f
))
150 { if((f
->mode
&SF_WRITE
) && HASAUXFD(f
))
152 if(fds
[m
].revents
&POLLIN
)
153 status
[check
[r
]] |= SF_READ
;
164 struct timeval tmb
, *tmp
;
169 for(r
= 0; r
< c
; ++r
)
175 if((f
->flags
&SF_WRITE
) && !WRREADY(f
))
178 if((f
->flags
&SF_READ
) && !RDREADY(f
))
179 { if((f
->mode
&SF_WRITE
) && HASAUXFD(f
))
180 { if(f
->proc
->file
> m
)
182 FD_SET(f
->proc
->file
, &rd
);
184 else FD_SET(f
->file
,&rd
);
188 tmp
= NIL(struct timeval
*);
191 tmb
.tv_sec
= tm
/SECOND
;
192 tmb
.tv_usec
= (tm
%SECOND
)*SECOND
;
195 while((np
= select(m
+1,&rd
,&wr
,NIL(fd_set
*),tmp
)) < 0 )
203 for(r
= 0; r
< np
; ++r
)
206 if((f
->flags
&SF_WRITE
) && !WRREADY(f
) )
207 { if(FD_ISSET(f
->file
,&wr
) )
208 status
[check
[r
]] |= SF_WRITE
;
211 if((f
->flags
&SF_READ
) && !RDREADY(f
) )
212 { if((f
->mode
&SF_WRITE
) && HASAUXFD(f
) )
213 { if(FD_ISSET(f
->proc
->file
, &rd
) )
214 status
[check
[r
]] |= SF_READ
;
217 { if(FD_ISSET(f
->file
,&rd
) )
218 status
[check
[r
]] |= SF_READ
;
223 #endif /*_lib_select*/
225 for(r
= c
= 0; c
< n
; ++c
)
230 f
->val
= (ssize_t
)status
[c
];
232 /* announce status */
233 if(f
->disc
&& f
->disc
->exceptf
)
234 (*f
->disc
->exceptf
)(f
,SF_READY
,(Void_t
*)(long)status
[c
],f
->disc
);
236 if(c
> r
) /* move to front of list */
243 free((Void_t
*)status
);