2 * Copyright (c) 2015-2020 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/types.h>
37 #include <arpa/inet.h>
38 #include <sys/queue.h>
45 #include "pr-poll-array.h"
46 #include "pr-poll-loop.h"
49 * Needed for creating nspr handle from unix fd
51 #include <private/pprio.h>
54 * Helper functions declarations
56 static PRInt16
poll_events_to_pr_events(short events
);
58 static short pr_events_to_poll_events(PRInt16 events
);
60 static int pr_poll_loop_add_fd_int(struct pr_poll_loop
*poll_loop
,
61 int fd
, PRFileDesc
*prfd
,
62 short events
, pr_poll_loop_fd_set_events_cb_fn fd_set_events_cb
,
63 pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb
,
64 pr_poll_loop_fd_read_cb_fn fd_read_cb
, pr_poll_loop_prfd_read_cb_fn prfd_read_cb
,
65 pr_poll_loop_fd_write_cb_fn fd_write_cb
, pr_poll_loop_prfd_write_cb_fn prfd_write_cb
,
66 pr_poll_loop_fd_err_cb_fn fd_err_cb
, pr_poll_loop_prfd_err_cb_fn prfd_err_cb
,
67 void *user_data1
, void *user_data2
);
69 static int pr_poll_loop_del_fd_int(struct pr_poll_loop
*poll_loop
,
70 int fd
, PRFileDesc
*prfd
);
72 static struct pr_poll_loop_fd_entry
*pr_poll_loop_find_by_fd(
73 const struct pr_poll_loop
*poll_loop
, int fd
, PRFileDesc
*prfd
);
75 static int prepare_poll_array(struct pr_poll_loop
*poll_loop
);
78 * Helper functions definitions
81 poll_events_to_pr_events(short events
)
87 if (events
& POLLIN
) {
91 if (events
& POLLOUT
) {
95 if (events
& POLLPRI
) {
96 res
|= PR_POLL_EXCEPT
;
103 pr_events_to_poll_events(PRInt16 events
)
109 if (events
& PR_POLL_READ
) {
113 if (events
& PR_POLL_WRITE
) {
117 if (events
& PR_POLL_ERR
) {
121 if (events
& PR_POLL_NVAL
) {
125 if (events
& PR_POLL_HUP
) {
129 if (events
& PR_POLL_EXCEPT
) {
137 pr_poll_loop_add_fd_int(struct pr_poll_loop
*poll_loop
, int fd
, PRFileDesc
*prfd
,
138 short events
, pr_poll_loop_fd_set_events_cb_fn fd_set_events_cb
,
139 pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb
,
140 pr_poll_loop_fd_read_cb_fn fd_read_cb
, pr_poll_loop_prfd_read_cb_fn prfd_read_cb
,
141 pr_poll_loop_fd_write_cb_fn fd_write_cb
, pr_poll_loop_prfd_write_cb_fn prfd_write_cb
,
142 pr_poll_loop_fd_err_cb_fn fd_err_cb
, pr_poll_loop_prfd_err_cb_fn prfd_err_cb
,
143 void *user_data1
, void *user_data2
)
145 struct pr_poll_loop_fd_entry
*new_entry
;
147 assert((prfd
!= NULL
&& fd
== -1) || (fd
!= -1 && prfd
== NULL
));
149 if ((events
& ~(POLLIN
|POLLOUT
|POLLPRI
)) != 0) {
153 if (pr_poll_loop_find_by_fd(poll_loop
, fd
, prfd
) != NULL
) {
157 new_entry
= malloc(sizeof(*new_entry
));
158 if (new_entry
== NULL
) {
162 memset(new_entry
, 0, sizeof(*new_entry
));
167 new_entry
->prfd
= PR_CreateSocketPollFd(fd
);
168 if (new_entry
->prfd
== NULL
) {
174 new_entry
->prfd
= prfd
;
177 new_entry
->events
= events
;
179 new_entry
->fd_set_events_cb
= fd_set_events_cb
;
180 new_entry
->prfd_set_events_cb
= prfd_set_events_cb
;
182 new_entry
->fd_read_cb
= fd_read_cb
;
183 new_entry
->prfd_read_cb
= prfd_read_cb
;
185 new_entry
->fd_write_cb
= fd_write_cb
;
186 new_entry
->prfd_write_cb
= prfd_write_cb
;
188 new_entry
->fd_err_cb
= fd_err_cb
;
189 new_entry
->prfd_err_cb
= prfd_err_cb
;
191 new_entry
->user_data1
= user_data1
;
192 new_entry
->user_data2
= user_data2
;
194 TAILQ_INSERT_TAIL(&poll_loop
->fd_list
, new_entry
, entries
);
200 pr_poll_loop_del_fd_int(struct pr_poll_loop
*poll_loop
, int fd
, PRFileDesc
*prfd
)
202 struct pr_poll_loop_fd_entry
*fd_entry
;
204 fd_entry
= pr_poll_loop_find_by_fd(poll_loop
, fd
, prfd
);
205 if (fd_entry
== NULL
) {
209 TAILQ_REMOVE(&poll_loop
->fd_list
, fd_entry
, entries
);
211 if (fd_entry
->fd
!= -1) {
212 (void)PR_DestroySocketPollFd(fd_entry
->prfd
);
220 static struct pr_poll_loop_fd_entry
*
221 pr_poll_loop_find_by_fd(const struct pr_poll_loop
*poll_loop
, int fd
, PRFileDesc
*prfd
)
223 struct pr_poll_loop_fd_entry
*fd_entry
;
225 assert((prfd
!= NULL
&& fd
== -1) || (fd
!= -1 && prfd
== NULL
));
227 TAILQ_FOREACH(fd_entry
, &poll_loop
->fd_list
, entries
) {
229 if (fd_entry
->fd
== fd
) {
233 if (fd_entry
->prfd
== prfd
) {
243 int prepare_poll_array(struct pr_poll_loop
*poll_loop
)
245 struct pr_poll_loop_fd_entry
*fd_entry
;
246 struct pr_poll_loop_fd_entry
*fd_entry_next
;
247 struct pr_poll_loop_fd_entry
**user_data
;
250 PRPollDesc
*poll_desc
;
251 struct pr_poll_array
*poll_array
;
253 poll_array
= &poll_loop
->poll_array
;
255 pr_poll_array_clean(poll_array
);
260 fd_entry
= TAILQ_FIRST(&poll_loop
->fd_list
);
262 while (fd_entry
!= NULL
) {
263 fd_entry_next
= TAILQ_NEXT(fd_entry
, entries
);
265 events
= fd_entry
->events
;
267 if (fd_entry
->fd_set_events_cb
!= NULL
|| fd_entry
->prfd_set_events_cb
!= NULL
) {
268 if (fd_entry
->fd_set_events_cb
!= NULL
) {
269 res
= fd_entry
->fd_set_events_cb(fd_entry
->fd
, &events
,
270 fd_entry
->user_data1
, fd_entry
->user_data2
);
272 res
= fd_entry
->prfd_set_events_cb(fd_entry
->prfd
, &events
,
273 fd_entry
->user_data1
, fd_entry
->user_data2
);
282 if ((events
& ~(POLLIN
|POLLOUT
|POLLPRI
)) != 0) {
288 * Empty events -> do not add entry
298 if (pr_poll_array_add(poll_array
, &poll_desc
, (void **)&user_data
) < 0) {
302 poll_desc
->fd
= fd_entry
->prfd
;
303 poll_desc
->in_flags
= poll_events_to_pr_events(events
);
305 *user_data
= fd_entry
;
314 * -2 = return immediately
323 fd_entry
= fd_entry_next
;
326 pr_poll_array_gc(poll_array
);
335 pr_poll_loop_init(struct pr_poll_loop
*poll_loop
)
338 memset(poll_loop
, 0, sizeof(*poll_loop
));
340 TAILQ_INIT(&(poll_loop
->fd_list
));
342 pr_poll_array_init(&poll_loop
->poll_array
, sizeof(struct pr_poll_loop_fd_entry
*));
343 timer_list_init(&poll_loop
->tlist
);
347 pr_poll_loop_del_fd(struct pr_poll_loop
*poll_loop
, int fd
)
350 return (pr_poll_loop_del_fd_int(poll_loop
, fd
, NULL
));
354 pr_poll_loop_del_prfd(struct pr_poll_loop
*poll_loop
, PRFileDesc
*prfd
)
357 return (pr_poll_loop_del_fd_int(poll_loop
, -1, prfd
));
361 pr_poll_loop_destroy(struct pr_poll_loop
*poll_loop
)
363 struct pr_poll_loop_fd_entry
*fd_entry
;
364 struct pr_poll_loop_fd_entry
*fd_entry_next
;
366 fd_entry
= TAILQ_FIRST(&poll_loop
->fd_list
);
368 while (fd_entry
!= NULL
) {
369 fd_entry_next
= TAILQ_NEXT(fd_entry
, entries
);
371 if (fd_entry
->fd
!= -1) {
372 (void)PR_DestroySocketPollFd(fd_entry
->prfd
);
377 fd_entry
= fd_entry_next
;
380 TAILQ_INIT(&(poll_loop
->fd_list
));
382 pr_poll_array_destroy(&poll_loop
->poll_array
);
383 timer_list_free(&poll_loop
->tlist
);
389 pr_poll_loop_add_fd(struct pr_poll_loop
*poll_loop
, int fd
,
390 short events
, pr_poll_loop_fd_set_events_cb_fn fd_set_events_cb
,
391 pr_poll_loop_fd_read_cb_fn fd_read_cb
,
392 pr_poll_loop_fd_write_cb_fn fd_write_cb
,
393 pr_poll_loop_fd_err_cb_fn fd_err_cb
,
394 void *user_data1
, void *user_data2
)
397 return (pr_poll_loop_add_fd_int(poll_loop
, fd
, NULL
, events
,
398 fd_set_events_cb
, NULL
, fd_read_cb
, NULL
, fd_write_cb
, NULL
,
400 user_data1
, user_data2
));
404 pr_poll_loop_add_prfd(struct pr_poll_loop
*poll_loop
, PRFileDesc
*prfd
,
405 short events
, pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb
,
406 pr_poll_loop_prfd_read_cb_fn prfd_read_cb
,
407 pr_poll_loop_prfd_read_cb_fn prfd_write_cb
,
408 pr_poll_loop_prfd_err_cb_fn prfd_err_cb
,
409 void *user_data1
, void *user_data2
)
412 return (pr_poll_loop_add_fd_int(poll_loop
, -1, prfd
, events
,
413 NULL
, prfd_set_events_cb
, NULL
, prfd_read_cb
, NULL
, prfd_write_cb
,
415 user_data1
, user_data2
));
419 pr_poll_loop_exec(struct pr_poll_loop
*poll_loop
)
422 struct pr_poll_loop_fd_entry
*fd_entry
;
423 struct pr_poll_loop_fd_entry
**user_data
;
426 static PRPollDesc
*pfds
;
429 if ((res
= prepare_poll_array(poll_loop
)) != 0) {
433 pfds
= poll_loop
->poll_array
.array
;
435 if ((poll_res
= PR_Poll(pfds
, pr_poll_array_size(&poll_loop
->poll_array
),
436 timer_list_time_to_expire(&poll_loop
->tlist
))) > 0) {
437 for (i
= 0; i
< pr_poll_array_size(&poll_loop
->poll_array
); i
++) {
438 user_data
= pr_poll_array_get_user_data(&poll_loop
->poll_array
, i
);
439 fd_entry
= *user_data
;
441 if (pfds
[i
].out_flags
& PR_POLL_READ
&&
442 (fd_entry
->fd_read_cb
!= NULL
|| fd_entry
->prfd_read_cb
!= NULL
)) {
443 if (fd_entry
->fd_read_cb
) {
444 cb_res
= fd_entry
->fd_read_cb(fd_entry
->fd
,
445 fd_entry
->user_data1
, fd_entry
->user_data2
);
447 cb_res
= fd_entry
->prfd_read_cb(fd_entry
->prfd
,
448 fd_entry
->user_data1
, fd_entry
->user_data2
);
456 if (pfds
[i
].out_flags
& PR_POLL_WRITE
&&
457 (fd_entry
->fd_write_cb
!= NULL
|| fd_entry
->prfd_write_cb
!= NULL
)) {
458 if (fd_entry
->fd_write_cb
) {
459 cb_res
= fd_entry
->fd_write_cb(fd_entry
->fd
,
460 fd_entry
->user_data1
, fd_entry
->user_data2
);
462 cb_res
= fd_entry
->prfd_write_cb(fd_entry
->prfd
,
463 fd_entry
->user_data1
, fd_entry
->user_data2
);
471 if ((pfds
[i
].out_flags
& (PR_POLL_ERR
|PR_POLL_NVAL
|PR_POLL_HUP
|PR_POLL_EXCEPT
)) &&
472 !(pfds
[i
].out_flags
& (PR_POLL_READ
|PR_POLL_WRITE
)) &&
473 (fd_entry
->fd_err_cb
!= NULL
|| fd_entry
->prfd_err_cb
!= NULL
)) {
474 if (fd_entry
->fd_err_cb
) {
475 cb_res
= fd_entry
->fd_err_cb(fd_entry
->fd
,
476 pr_events_to_poll_events(pfds
[i
].out_flags
),
477 fd_entry
->user_data1
, fd_entry
->user_data2
);
479 cb_res
= fd_entry
->prfd_err_cb(fd_entry
->prfd
,
480 pr_events_to_poll_events(pfds
[i
].out_flags
),
481 fd_entry
->user_data1
, fd_entry
->user_data2
);
491 if (poll_res
== -1) {
495 timer_list_expire(&poll_loop
->tlist
);
501 pr_poll_loop_get_timer_list(struct pr_poll_loop
*poll_loop
)
504 return (&poll_loop
->tlist
);