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.
19 #include <sys/signalfd.h>
22 * FIXME: uClibc < 0.9.30.3 does not define EPOLLRDHUP for Linux >= 2.6.17
25 #define EPOLLRDHUP 0x2000
29 uloop_signal_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
31 struct signalfd_siginfo fdsi
;
36 ret
= read(fd
->fd
, &fdsi
, sizeof(fdsi
));
37 if (ret
< 0 && errno
== EINTR
)
40 if (ret
!= sizeof(fdsi
))
43 switch (fdsi
.ssi_signo
) {
47 sigaction(fdsi
.ssi_signo
, NULL
, &act
);
48 if (act
.sa_handler
!= SIG_IGN
&&
49 act
.sa_handler
!= SIG_DFL
) {
50 act
.sa_handler(fdsi
.ssi_signo
);
56 uloop_handle_signal(fdsi
.ssi_signo
);
62 uloop_setup_signalfd(bool add
)
64 static struct uloop_fd sfd
= {
65 .cb
= uloop_signal_fd_cb
67 static sigset_t prev_mask
;
76 uloop_fd_delete(&sfd
);
77 sigprocmask(SIG_BLOCK
, &prev_mask
, NULL
);
79 sigaddset(&mask
, SIGQUIT
);
80 sigaddset(&mask
, SIGINT
);
81 sigaddset(&mask
, SIGTERM
);
82 sigaddset(&mask
, SIGCHLD
);
83 sigprocmask(SIG_BLOCK
, &mask
, &prev_mask
);
86 uloop_fd_add(&sfd
, ULOOP_READ
| ULOOP_EDGE_TRIGGER
);
89 if (signalfd(signal_fd
, &mask
, SFD_NONBLOCK
| SFD_CLOEXEC
) < 0) {
90 sigprocmask(SIG_BLOCK
, &prev_mask
, NULL
);
104 poll_fd
= epoll_create(32);
108 fcntl(poll_fd
, F_SETFD
, fcntl(poll_fd
, F_GETFD
) | FD_CLOEXEC
);
111 signal_fd
= signalfd(-1, &mask
, SFD_NONBLOCK
| SFD_CLOEXEC
);
116 static int register_poll(struct uloop_fd
*fd
, unsigned int flags
)
118 struct epoll_event ev
;
119 int op
= fd
->registered
? EPOLL_CTL_MOD
: EPOLL_CTL_ADD
;
121 memset(&ev
, 0, sizeof(struct epoll_event
));
123 if (flags
& ULOOP_READ
)
124 ev
.events
|= EPOLLIN
| EPOLLRDHUP
;
126 if (flags
& ULOOP_WRITE
)
127 ev
.events
|= EPOLLOUT
;
129 if (flags
& ULOOP_EDGE_TRIGGER
)
130 ev
.events
|= EPOLLET
;
136 return epoll_ctl(poll_fd
, op
, fd
->fd
, &ev
);
139 static struct epoll_event events
[ULOOP_MAX_EVENTS
];
141 static int __uloop_fd_delete(struct uloop_fd
*sock
)
144 return epoll_ctl(poll_fd
, EPOLL_CTL_DEL
, sock
->fd
, 0);
147 static int uloop_fetch_events(int timeout
)
151 nfds
= epoll_wait(poll_fd
, events
, ARRAY_SIZE(events
), timeout
);
152 for (n
= 0; n
< nfds
; ++n
) {
153 struct uloop_fd_event
*cur
= &cur_fds
[n
];
154 struct uloop_fd
*u
= events
[n
].data
.ptr
;
161 if (events
[n
].events
& (EPOLLERR
|EPOLLHUP
)) {
163 if (!(u
->flags
& ULOOP_ERROR_CB
))
167 if(!(events
[n
].events
& (EPOLLRDHUP
|EPOLLIN
|EPOLLOUT
|EPOLLERR
|EPOLLHUP
))) {
172 if(events
[n
].events
& EPOLLRDHUP
)
175 if(events
[n
].events
& EPOLLIN
)
178 if(events
[n
].events
& EPOLLOUT
)