root/luci2/libubox/uloop.c @ 5934

Revision 5934, 3.5 KB (checked in by Cyrus, 3 years ago)

ubox/uloop: Make FDs close-on-exec

Line 
1/*
2 *   Copyright (C) 2010 John Crispin <blogic@openwrt.org>
3 *   Copyright (C) 2010 Steven Barth <steven@midlink.org>
4 *
5 *   This program is free software; you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *   GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program; if not, write to the Free Software
17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21#include <unistd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <poll.h>
26#include <string.h>
27#include <time.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/epoll.h>
33
34#include <libubus.h>
35#include "uloop.h"
36#include "ulog.h"
37
38struct uloop_sock
39{
40    int sock;
41    void *priv;
42    _uloop_sock_handler cb;
43};
44
45static int epoll_fd = 0;
46static int uloop_loop = 1;
47static struct ubus_ctx *uloop_ubus = 0;
48
49void uloop_init(void)
50{
51    epoll_fd = epoll_create(32);
52    fcntl(epoll_fd, F_SETFD, fcntl(epoll_fd, F_GETFD) | FD_CLOEXEC);
53}
54
55static void uloop_ubus_cb(struct uloop_sock *u)
56{
57    ubus_recv(uloop_ubus);
58}
59
60struct uloop_sock* uloop_sock_add(int sock, void *priv, _uloop_sock_handler cb)
61{
62    struct epoll_event ev;
63    struct uloop_sock *u = malloc(sizeof(struct uloop_sock));
64    u->sock = sock;
65    u->priv = priv;
66    u->cb = cb;
67    memset(&ev, 0, sizeof(struct epoll_event));
68    ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
69    ev.data.fd = sock;
70    ev.data.ptr = u;
71    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
72    return u;
73}
74
75void uloop_ubus_add(struct ubus_ctx *ctx)
76{
77    if(!uloop_ubus)
78        uloop_ubus = ctx;
79}
80
81void uloop_sock_delete(struct uloop_sock *u)
82{
83    if(u->priv != uloop_ubus)
84        free(u->priv);
85    free(u);
86}
87
88static void uloop_handler_INT(int signo)
89{
90    LOG("away we go\n");
91    uloop_loop = 0;
92}
93
94static void uloop_setup_signals(void)
95{
96    struct sigaction s1, s2;
97    memset(&s1, 0, sizeof(struct sigaction));
98    memset(&s2, 0, sizeof(struct sigaction));
99    s1.sa_handler = uloop_handler_INT;
100    s1.sa_flags = 0;
101    sigaction(SIGINT, &s1, NULL);
102    s2.sa_handler = uloop_handler_INT;
103    s2.sa_flags = 0;
104    sigaction(SIGTERM, &s2, NULL);
105}
106
107int uloop(void (*cb)(void), int timeout)
108{
109    #define MAX_EVENTS  10
110    struct uloop_sock *ubus_sock = 0;
111    struct epoll_event events[MAX_EVENTS];
112    int nfds, n;
113    time_t t = time(0);
114    uloop_loop = 1;
115    uloop_setup_signals();
116    while(uloop_loop)
117    {
118        if(uloop_ubus)
119            if(ubus_connect(uloop_ubus) > 0)
120            {
121                int ubus_fd = ubus_get_sock(uloop_ubus);
122                fcntl(ubus_fd, F_SETFD, fcntl(ubus_fd, F_GETFD) | FD_CLOEXEC);
123                ubus_sock = uloop_sock_add(ubus_fd, uloop_ubus, uloop_ubus_cb);
124            }
125        nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 1000);
126        for(n = 0; n < nfds; ++n)
127        {
128            struct uloop_sock *u = (struct uloop_sock*)events[n].data.ptr;
129            if(events[n].events & EPOLLRDHUP)
130            {
131                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, u->sock, 0);
132                uloop_sock_delete(u);
133            } else if(events[n].events & EPOLLIN)
134            {
135                if(u->cb)
136                    u->cb(u);
137            }
138        }
139        if(cb)
140        {
141            if(difftime(time(0), t) < timeout)
142                continue;
143            t = time(0);
144            cb();
145        }
146    }
147    if(ubus_sock)
148        uloop_sock_delete(ubus_sock);
149    return 0;
150}
Note: See TracBrowser for help on using the browser.