2 * uloop - event loop implementation
4 * Copyright (C) 2010-2016 Felix Fietkau <nbd@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * FIXME: uClibc < 0.9.30.3 does not define EPOLLRDHUP for Linux >= 2.6.17
23 #define EPOLLRDHUP 0x2000
26 static int uloop_init_pollfd(void)
31 poll_fd
= epoll_create(32);
35 fcntl(poll_fd
, F_SETFD
, fcntl(poll_fd
, F_GETFD
) | FD_CLOEXEC
);
39 static int register_poll(struct uloop_fd
*fd
, unsigned int flags
)
41 struct epoll_event ev
;
42 int op
= fd
->registered
? EPOLL_CTL_MOD
: EPOLL_CTL_ADD
;
44 memset(&ev
, 0, sizeof(struct epoll_event
));
46 if (flags
& ULOOP_READ
)
47 ev
.events
|= EPOLLIN
| EPOLLRDHUP
;
49 if (flags
& ULOOP_WRITE
)
50 ev
.events
|= EPOLLOUT
;
52 if (flags
& ULOOP_EDGE_TRIGGER
)
57 return epoll_ctl(poll_fd
, op
, fd
->fd
, &ev
);
60 static struct epoll_event events
[ULOOP_MAX_EVENTS
];
62 static int __uloop_fd_delete(struct uloop_fd
*sock
)
65 return epoll_ctl(poll_fd
, EPOLL_CTL_DEL
, sock
->fd
, 0);
68 static int uloop_fetch_events(int timeout
)
72 nfds
= epoll_wait(poll_fd
, events
, ARRAY_SIZE(events
), timeout
);
73 for (n
= 0; n
< nfds
; ++n
) {
74 struct uloop_fd_event
*cur
= &cur_fds
[n
];
75 struct uloop_fd
*u
= events
[n
].data
.ptr
;
82 if (events
[n
].events
& (EPOLLERR
|EPOLLHUP
)) {
84 if (!(u
->flags
& ULOOP_ERROR_CB
))
88 if(!(events
[n
].events
& (EPOLLRDHUP
|EPOLLIN
|EPOLLOUT
|EPOLLERR
|EPOLLHUP
))) {
93 if(events
[n
].events
& EPOLLRDHUP
)
96 if(events
[n
].events
& EPOLLIN
)
99 if(events
[n
].events
& EPOLLOUT
)
108 static void dispatch_timer(struct uloop_fd
*u
, unsigned int events
)
110 if (!(events
& ULOOP_READ
))
115 if (read(u
->fd
, &fired
, sizeof(fired
)) != sizeof(fired
))
118 struct uloop_interval
*tm
= container_of(u
, struct uloop_interval
, priv
.ufd
);
120 tm
->expirations
+= fired
;
124 static int timer_register(struct uloop_interval
*tm
, unsigned int msecs
)
126 if (!tm
->priv
.ufd
.registered
) {
127 int fd
= timerfd_create(CLOCK_MONOTONIC
, TFD_CLOEXEC
|TFD_NONBLOCK
);
132 tm
->priv
.ufd
.fd
= fd
;
133 tm
->priv
.ufd
.cb
= dispatch_timer
;
136 struct itimerspec spec
= {
138 .tv_sec
= msecs
/ 1000,
139 .tv_nsec
= (msecs
% 1000) * 1000000
142 .tv_sec
= msecs
/ 1000,
143 .tv_nsec
= (msecs
% 1000) * 1000000
147 if (timerfd_settime(tm
->priv
.ufd
.fd
, 0, &spec
, NULL
) == -1)
150 if (uloop_fd_add(&tm
->priv
.ufd
, ULOOP_READ
) == -1)
156 uloop_fd_delete(&tm
->priv
.ufd
);
157 close(tm
->priv
.ufd
.fd
);
158 memset(&tm
->priv
.ufd
, 0, sizeof(tm
->priv
.ufd
));
163 static int timer_remove(struct uloop_interval
*tm
)
165 int ret
= __uloop_fd_delete(&tm
->priv
.ufd
);
168 close(tm
->priv
.ufd
.fd
);
169 memset(&tm
->priv
.ufd
, 0, sizeof(tm
->priv
.ufd
));
175 static int64_t timer_next(struct uloop_interval
*tm
)
177 struct itimerspec spec
;
179 if (!tm
->priv
.ufd
.registered
)
182 if (timerfd_gettime(tm
->priv
.ufd
.fd
, &spec
) == -1)
185 return spec
.it_value
.tv_sec
* 1000 + spec
.it_value
.tv_nsec
/ 1000000;