]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/mainloop.c
mainloop: add lxc_mainloop_add_handler_events
[mirror_lxc.git] / src / lxc / mainloop.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/epoll.h>
12 #include <unistd.h>
13
14 #include "config.h"
15 #include "mainloop.h"
16
17 struct mainloop_handler {
18 lxc_mainloop_callback_t callback;
19 int fd;
20 void *data;
21 };
22
23 #define MAX_EVENTS 10
24
25 int lxc_mainloop(struct lxc_epoll_descr *descr, int timeout_ms)
26 {
27 int i, nfds, ret;
28 struct mainloop_handler *handler;
29 struct epoll_event events[MAX_EVENTS];
30
31 for (;;) {
32 nfds = epoll_wait(descr->epfd, events, MAX_EVENTS, timeout_ms);
33 if (nfds < 0) {
34 if (errno == EINTR)
35 continue;
36
37 return -errno;
38 }
39
40 for (i = 0; i < nfds; i++) {
41 handler = events[i].data.ptr;
42
43 /* If the handler returns a positive value, exit the
44 * mainloop.
45 */
46 ret = handler->callback(handler->fd, events[i].events,
47 handler->data, descr);
48 if (ret == LXC_MAINLOOP_ERROR)
49 return -1;
50 if (ret == LXC_MAINLOOP_CLOSE)
51 return 0;
52 }
53
54 if (nfds == 0)
55 return 0;
56
57 if (lxc_list_empty(&descr->handlers))
58 return 0;
59 }
60 }
61
62 int lxc_mainloop_add_handler_events(struct lxc_epoll_descr *descr, int fd,
63 int events,
64 lxc_mainloop_callback_t callback,
65 void *data)
66 {
67 __do_free struct mainloop_handler *handler = NULL;
68 __do_free struct lxc_list *item = NULL;
69 struct epoll_event ev;
70
71 if (fd < 0)
72 return -1;
73
74 handler = malloc(sizeof(*handler));
75 if (!handler)
76 return -1;
77
78 handler->callback = callback;
79 handler->fd = fd;
80 handler->data = data;
81
82 ev.events = events;
83 ev.data.ptr = handler;
84
85 if (epoll_ctl(descr->epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
86 return -errno;
87
88 item = malloc(sizeof(*item));
89 if (!item)
90 return ret_errno(ENOMEM);
91
92 item->elem = move_ptr(handler);
93 lxc_list_add(&descr->handlers, move_ptr(item));
94 return 0;
95 }
96
97 int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
98 lxc_mainloop_callback_t callback, void *data)
99 {
100 return lxc_mainloop_add_handler_events(descr, fd, EPOLLIN, callback,
101 data);
102 }
103
104 int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd)
105 {
106 struct mainloop_handler *handler;
107 struct lxc_list *iterator;
108
109 lxc_list_for_each(iterator, &descr->handlers) {
110 handler = iterator->elem;
111
112 if (handler->fd == fd) {
113 /* found */
114 if (epoll_ctl(descr->epfd, EPOLL_CTL_DEL, fd, NULL))
115 return -errno;
116
117 lxc_list_del(iterator);
118 free(iterator->elem);
119 free(iterator);
120 return 0;
121 }
122 }
123
124 return ret_errno(EINVAL);
125 }
126
127 int lxc_mainloop_open(struct lxc_epoll_descr *descr)
128 {
129 descr->epfd = epoll_create1(EPOLL_CLOEXEC);
130 if (descr->epfd < 0)
131 return -errno;
132
133 lxc_list_init(&descr->handlers);
134 return 0;
135 }
136
137 void lxc_mainloop_close(struct lxc_epoll_descr *descr)
138 {
139 struct lxc_list *iterator, *next;
140
141 iterator = descr->handlers.next;
142 while (iterator != &descr->handlers) {
143 next = iterator->next;
144
145 lxc_list_del(iterator);
146 free(iterator->elem);
147 free(iterator);
148 iterator = next;
149 }
150
151 close_prot_errno_disarm(descr->epfd);
152 }