2 * Copyright 2016 IoT.bzh
3 * Author: José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <sys/epoll.h>
25 #include "utils-upoll.h"
34 void (*write)(void *);
35 void (*hangup)(void *);
48 static int pollfd = 0;
49 static struct upollfd *head = NULL;
50 static struct upoll *current = NULL;
51 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
53 static int update(struct upollfd *ufd)
62 pthread_mutex_lock(&mutex);
65 /* no more watchers */
74 pthread_mutex_unlock(&mutex);
75 epoll_ctl(pollfd, EPOLL_CTL_DEL, ufd->fd, NULL);
79 /* compute the events for the watchers */
87 pthread_mutex_unlock(&mutex);
88 if (ufd->events == events)
92 rc = epoll_ctl(pollfd, EPOLL_CTL_MOD, ufd->fd, &e);
98 static struct upollfd *get_fd(int fd)
100 struct epoll_event e;
101 struct upollfd *result;
104 /* opens the epoll stream */
106 pollfd = epoll_create1(EPOLL_CLOEXEC);
119 while (result != NULL) {
120 if (result->fd == fd)
122 result = result->next;
126 result = calloc(1, sizeof *result);
132 pthread_mutex_lock(&mutex);
135 pthread_mutex_unlock(&mutex);
140 rc = epoll_ctl(pollfd, EPOLL_CTL_ADD, fd, &e);
144 /* revert on error */
151 int upoll_is_valid(struct upoll *upoll)
153 struct upollfd *itfd = head;
155 while (itfd != NULL) {
167 struct upoll *upoll_open(int fd, void *closure)
170 struct upoll *result;
173 result = calloc(1, sizeof *result);
186 result->closure = closure;
187 pthread_mutex_lock(&mutex);
188 result->next = ufd->head;
190 pthread_mutex_unlock(&mutex);
194 int upoll_on_readable(struct upoll *upoll, void (*process)(void *))
197 assert(upoll_is_valid(upoll));
199 upoll->read = process;
200 return update(upoll->fd);
203 int upoll_on_writable(struct upoll *upoll, void (*process)(void *))
206 assert(upoll_is_valid(upoll));
208 upoll->write = process;
209 return update(upoll->fd);
212 void upoll_on_hangup(struct upoll *upoll, void (*process)(void *))
215 assert(upoll_is_valid(upoll));
217 upoll->hangup = process;
220 void upoll_close(struct upoll *upoll)
226 assert(upoll_is_valid(upoll));
229 pthread_mutex_lock(&mutex);
230 if (current == upoll)
236 pthread_mutex_unlock(&mutex);
241 int upoll_wait(int timeout)
244 struct epoll_event e;
253 rc = epoll_wait(pollfd, &e, 1, timeout);
254 } while (rc < 0 && errno == EINTR);
258 e.events &= EPOLLIN | EPOLLOUT | EPOLLHUP;
259 while (current != NULL && e.events != 0) {
260 if ((e.events & EPOLLIN) && current->read) {
261 current->read(current->closure);
262 e.events &= (uint32_t)~EPOLLIN;
265 if ((e.events & EPOLLOUT) && current->write) {
266 current->write(current->closure);
267 e.events &= (uint32_t)~EPOLLOUT;
270 if ((e.events & EPOLLHUP) && current->hangup) {
271 current->hangup(current->closure);
275 current = current->next;
278 return rc < 0 ? rc : 0;