xref: /spdk/lib/util/fd_group.c (revision 6f338d4bf3a8a91b7abe377a605a321ea2b05bf7)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright(c) Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk_internal/usdt.h"
7 
8 #include "spdk/env.h"
9 #include "spdk/log.h"
10 #include "spdk/queue.h"
11 
12 #include "spdk/fd_group.h"
13 
14 #ifdef __linux__
15 #include <sys/epoll.h>
16 #endif
17 
18 #define SPDK_MAX_EVENT_NAME_LEN 256
19 
20 enum event_handler_state {
21 	/* The event_handler is added into an fd_group waiting for event,
22 	 * but not currently in the execution of a wait loop.
23 	 */
24 	EVENT_HANDLER_STATE_WAITING,
25 
26 	/* The event_handler is currently in the execution of a wait loop. */
27 	EVENT_HANDLER_STATE_RUNNING,
28 
29 	/* The event_handler was removed during the execution of a wait loop. */
30 	EVENT_HANDLER_STATE_REMOVED,
31 };
32 
33 /* file descriptor of the interrupt event */
34 
35 /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
36 struct event_handler {
37 	TAILQ_ENTRY(event_handler)	next;
38 	enum event_handler_state	state;
39 
40 	spdk_fd_fn			fn;
41 	void				*fn_arg;
42 	/* file descriptor of the interrupt event */
43 	int				fd;
44 	char				name[SPDK_MAX_EVENT_NAME_LEN + 1];
45 };
46 
47 struct spdk_fd_group {
48 	int epfd;
49 	int num_fds; /* Number of fds registered in this group. */
50 
51 	/* interrupt sources list */
52 	TAILQ_HEAD(, event_handler) event_handlers;
53 };
54 
55 int
56 spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
57 {
58 	return fgrp->epfd;
59 }
60 
61 #ifdef __linux__
62 
63 int
64 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
65 		  void *arg, const char *name)
66 {
67 	struct event_handler *ehdlr = NULL;
68 	struct epoll_event epevent = {0};
69 	int rc;
70 
71 	/* parameter checking */
72 	if (fgrp == NULL || efd < 0 || fn == NULL) {
73 		return -EINVAL;
74 	}
75 
76 	/* check if there is already one function registered for this fd */
77 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
78 		if (ehdlr->fd == efd) {
79 			return -EEXIST;
80 		}
81 	}
82 
83 	/* create a new event src */
84 	ehdlr = calloc(1, sizeof(*ehdlr));
85 	if (ehdlr == NULL) {
86 		return -errno;
87 	}
88 
89 	ehdlr->fd = efd;
90 	ehdlr->fn = fn;
91 	ehdlr->fn_arg = arg;
92 	ehdlr->state = EVENT_HANDLER_STATE_WAITING;
93 	snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
94 
95 	epevent.events = EPOLLIN;
96 	epevent.data.ptr = ehdlr;
97 	rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_ADD, efd, &epevent);
98 	if (rc < 0) {
99 		free(ehdlr);
100 		return -errno;
101 	}
102 
103 	TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
104 	fgrp->num_fds++;
105 
106 	return 0;
107 }
108 
109 void
110 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
111 {
112 	struct event_handler *ehdlr;
113 	int rc;
114 
115 	if (fgrp == NULL || efd < 0) {
116 		SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
117 		assert(0);
118 		return;
119 	}
120 
121 
122 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
123 		if (ehdlr->fd == efd) {
124 			break;
125 		}
126 	}
127 
128 	if (ehdlr == NULL) {
129 		SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
130 		return;
131 	}
132 
133 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
134 
135 	rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
136 	if (rc < 0) {
137 		SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
138 		return;
139 	}
140 
141 	assert(fgrp->num_fds > 0);
142 	fgrp->num_fds--;
143 	TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
144 
145 	/* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
146 	if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
147 		ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
148 	} else {
149 		free(ehdlr);
150 	}
151 }
152 
153 int
154 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
155 			   int efd, int event_types)
156 {
157 	struct epoll_event epevent;
158 	struct event_handler *ehdlr;
159 
160 	if (fgrp == NULL || efd < 0) {
161 		return -EINVAL;
162 	}
163 
164 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
165 		if (ehdlr->fd == efd) {
166 			break;
167 		}
168 	}
169 
170 	if (ehdlr == NULL) {
171 		return -EINVAL;
172 	}
173 
174 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
175 
176 	epevent.events = event_types;
177 	epevent.data.ptr = ehdlr;
178 
179 	return epoll_ctl(fgrp->epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
180 }
181 
182 int
183 spdk_fd_group_create(struct spdk_fd_group **_egrp)
184 {
185 	struct spdk_fd_group *fgrp;
186 
187 	if (_egrp == NULL) {
188 		return -EINVAL;
189 	}
190 
191 	fgrp = calloc(1, sizeof(*fgrp));
192 	if (fgrp == NULL) {
193 		return -ENOMEM;
194 	}
195 
196 	/* init the event source head */
197 	TAILQ_INIT(&fgrp->event_handlers);
198 
199 	fgrp->num_fds = 0;
200 	fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
201 	if (fgrp->epfd < 0) {
202 		free(fgrp);
203 		return -errno;
204 	}
205 
206 	*_egrp = fgrp;
207 
208 	return 0;
209 }
210 
211 void
212 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
213 {
214 	if (fgrp == NULL || fgrp->num_fds > 0) {
215 		SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
216 		assert(0);
217 		return;
218 	}
219 
220 	close(fgrp->epfd);
221 	free(fgrp);
222 
223 	return;
224 }
225 
226 int
227 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
228 {
229 	int totalfds = fgrp->num_fds;
230 	struct epoll_event events[totalfds];
231 	struct event_handler *ehdlr;
232 	int n;
233 	int nfds;
234 
235 	nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
236 	if (nfds < 0) {
237 		if (errno != EINTR) {
238 			SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
239 		}
240 
241 		return -errno;
242 	} else if (nfds == 0) {
243 		return 0;
244 	}
245 
246 	for (n = 0; n < nfds; n++) {
247 		/* find the event_handler */
248 		ehdlr = events[n].data.ptr;
249 
250 		if (ehdlr == NULL) {
251 			continue;
252 		}
253 
254 		/* Tag ehdlr as running state in case that it is removed
255 		 * during this wait loop but before or when it get executed.
256 		 */
257 		assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
258 		ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
259 	}
260 
261 	for (n = 0; n < nfds; n++) {
262 		/* find the event_handler */
263 		ehdlr = events[n].data.ptr;
264 
265 		if (ehdlr == NULL || ehdlr->fn == NULL) {
266 			continue;
267 		}
268 
269 		/* It is possible that the ehdlr was removed
270 		 * during this wait loop but before it get executed.
271 		 */
272 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
273 			free(ehdlr);
274 			continue;
275 		}
276 
277 		SPDK_DTRACE_PROBE4(interrupt_fd_process, ehdlr->name, ehdlr->fd,
278 				   ehdlr->fn, ehdlr->fn_arg);
279 
280 		/* call the interrupt response function */
281 		ehdlr->fn(ehdlr->fn_arg);
282 
283 		/* It is possible that the ehdlr was removed
284 		 * during this wait loop when it get executed.
285 		 */
286 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
287 			free(ehdlr);
288 		} else {
289 			ehdlr->state = EVENT_HANDLER_STATE_WAITING;
290 		}
291 	}
292 
293 	return nfds;
294 }
295 
296 #else
297 
298 int
299 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
300 		  void *arg, const char *name)
301 {
302 	return -ENOTSUP;
303 }
304 
305 void
306 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
307 {
308 }
309 
310 int
311 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
312 			   int efd, int event_types)
313 {
314 	return -ENOTSUP;
315 }
316 
317 int
318 spdk_fd_group_create(struct spdk_fd_group **fgrp)
319 {
320 	return -ENOTSUP;
321 }
322 
323 void
324 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
325 {
326 }
327 
328 int
329 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
330 {
331 	return -ENOTSUP;
332 }
333 
334 #endif
335