/src/rtpproxy/src/rtpp_epoll.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2022 Sippy Software, Inc., http://www.sippysoft.com |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | | * SUCH DAMAGE. |
25 | | * |
26 | | */ |
27 | | |
28 | | #include "config.h" |
29 | | |
30 | | #if HAVE_KQUEUE |
31 | | #include <sys/types.h> |
32 | | #include <sys/event.h> |
33 | | #else |
34 | | #include <sys/epoll.h> |
35 | | #endif |
36 | | #include <assert.h> |
37 | | #include <stdint.h> |
38 | | #include <stdlib.h> |
39 | | #include <string.h> |
40 | | #include <time.h> |
41 | | |
42 | | #include "rtpp_epoll.h" |
43 | | #include "rtpp_debug.h" |
44 | | |
45 | | int |
46 | | rtpp_epoll_create() |
47 | 4 | { |
48 | | #if HAVE_KQUEUE |
49 | | int qid = kqueue(); |
50 | | |
51 | | return (qid); |
52 | | #else |
53 | 4 | return (epoll_create(1)); |
54 | 4 | #endif |
55 | 4 | } |
56 | | |
57 | | int |
58 | | rtpp_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) |
59 | 187k | { |
60 | | #if HAVE_KQUEUE |
61 | | struct kevent k_event; |
62 | | void *udata; |
63 | | |
64 | | if (op == EPOLL_CTL_DEL) { |
65 | | EV_SET(&k_event, fd, EVFILT_READ, op, 0, 0, NULL); |
66 | | int r1 = kevent(epfd, &k_event, 1, NULL, 0, NULL); |
67 | | #if 0 |
68 | | EV_SET(&k_event, fd, EVFILT_WRITE, op, 0, 0, NULL); |
69 | | int r2 = kevent(epfd, &k_event, 1, NULL, 0, NULL); |
70 | | return (r1 == 0 || r2 == 0) ? 0 : -1; |
71 | | #endif |
72 | | return (r1); |
73 | | } |
74 | | |
75 | | udata = event->data.ptr; |
76 | | if (event->events & EPOLLIN) { |
77 | | EV_SET(&k_event, fd, EVFILT_READ, op, 0, 0, udata); |
78 | | if (kevent(epfd, &k_event, 1, NULL, 0, NULL) != 0) |
79 | | return (-1); |
80 | | return (0); |
81 | | } |
82 | | #if 0 |
83 | | if (event->events & EPOLLOUT) { |
84 | | EV_SET(&k_event, fd, EVFILT_WRITE, op, 0, 0, udata); |
85 | | if (kevent(epfd, &k_event, 1, NULL, 0, NULL) != 0) |
86 | | return (-1); |
87 | | } |
88 | | #endif |
89 | | return (-1); |
90 | | #else |
91 | 187k | return (epoll_ctl(epfd, op, fd, event)); |
92 | 187k | #endif |
93 | 187k | } |
94 | | |
95 | | #if HAVE_KQUEUE |
96 | | static int |
97 | | append_kevent(struct epoll_event *events, int alloclen, const struct kevent *kep, int i) |
98 | | { |
99 | | int j; |
100 | | |
101 | | for (j = 0; j < alloclen; j++) { |
102 | | if (kep[j].ident == kep[i].ident) |
103 | | break; |
104 | | } |
105 | | if (j == alloclen) { |
106 | | memset(&events[j], '\0', sizeof(events[j])); |
107 | | events[j].data.ptr = kep[i].udata; |
108 | | } else { |
109 | | RTPP_DBG_ASSERT(events[j].data.ptr == kep[i].udata); |
110 | | } |
111 | | switch (kep[i].filter) { |
112 | | case EVFILT_READ: |
113 | | events[j].events |= EPOLLIN; |
114 | | break; |
115 | | |
116 | | #if 0 |
117 | | case EVFILT_WRITE: |
118 | | events[j].events |= EPOLLOUT; |
119 | | break; |
120 | | #endif |
121 | | |
122 | | default: |
123 | | abort(); |
124 | | } |
125 | | return (j < alloclen ? alloclen : alloclen + 1); |
126 | | } |
127 | | #endif |
128 | | |
129 | | int |
130 | | rtpp_epoll_wait(int epfd, struct epoll_event *events, |
131 | | int maxevents, int timeout) |
132 | 5.17k | { |
133 | | #if HAVE_KQUEUE |
134 | | struct kevent *kep; |
135 | | struct timespec tot, *top; |
136 | | int ret, kret; |
137 | | |
138 | | kep = alloca(sizeof(struct kevent) * maxevents); |
139 | | if (kep == NULL) |
140 | | return (-1); |
141 | | if (timeout >= 0) { |
142 | | tot.tv_sec = timeout / 1000; |
143 | | tot.tv_nsec = (timeout % 1000) * 1000000; |
144 | | top = &tot; |
145 | | } else { |
146 | | top = NULL; |
147 | | } |
148 | | kret = kevent(epfd, NULL, 0, kep, maxevents, top); |
149 | | if (kret <= 0) |
150 | | return (kret); |
151 | | ret = 0; |
152 | | for (int i = 0; i < kret; i++) { |
153 | | ret = append_kevent(events, ret, kep, i); |
154 | | } |
155 | | return (ret); |
156 | | #else |
157 | 5.17k | return (epoll_wait(epfd, events, maxevents, timeout)); |
158 | 5.17k | #endif |
159 | 5.17k | } |