xref: /spdk/lib/util/fd_group.c (revision fecffda6ecf8853b82edccde429b68252f0a62c5)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 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 static __thread struct epoll_event *g_event = NULL;
64 
65 int
66 spdk_fd_group_get_epoll_event(struct epoll_event *event)
67 {
68 	if (g_event == NULL) {
69 		return -EINVAL;
70 	}
71 	*event = *g_event;
72 	return 0;
73 }
74 
75 int
76 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
77 		  void *arg, const char *name)
78 {
79 	struct event_handler *ehdlr = NULL;
80 	struct epoll_event epevent = {0};
81 	int rc;
82 
83 	/* parameter checking */
84 	if (fgrp == NULL || efd < 0 || fn == NULL) {
85 		return -EINVAL;
86 	}
87 
88 	/* check if there is already one function registered for this fd */
89 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
90 		if (ehdlr->fd == efd) {
91 			return -EEXIST;
92 		}
93 	}
94 
95 	/* create a new event src */
96 	ehdlr = calloc(1, sizeof(*ehdlr));
97 	if (ehdlr == NULL) {
98 		return -errno;
99 	}
100 
101 	ehdlr->fd = efd;
102 	ehdlr->fn = fn;
103 	ehdlr->fn_arg = arg;
104 	ehdlr->state = EVENT_HANDLER_STATE_WAITING;
105 	snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
106 
107 	epevent.events = EPOLLIN;
108 	epevent.data.ptr = ehdlr;
109 	rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_ADD, efd, &epevent);
110 	if (rc < 0) {
111 		free(ehdlr);
112 		return -errno;
113 	}
114 
115 	TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
116 	fgrp->num_fds++;
117 
118 	return 0;
119 }
120 
121 void
122 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
123 {
124 	struct event_handler *ehdlr;
125 	int rc;
126 
127 	if (fgrp == NULL || efd < 0) {
128 		SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
129 		assert(0);
130 		return;
131 	}
132 
133 
134 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
135 		if (ehdlr->fd == efd) {
136 			break;
137 		}
138 	}
139 
140 	if (ehdlr == NULL) {
141 		SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
142 		return;
143 	}
144 
145 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
146 
147 	rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
148 	if (rc < 0) {
149 		SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
150 		return;
151 	}
152 
153 	assert(fgrp->num_fds > 0);
154 	fgrp->num_fds--;
155 	TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
156 
157 	/* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
158 	if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
159 		ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
160 	} else {
161 		free(ehdlr);
162 	}
163 }
164 
165 int
166 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
167 			   int efd, int event_types)
168 {
169 	struct epoll_event epevent;
170 	struct event_handler *ehdlr;
171 
172 	if (fgrp == NULL || efd < 0) {
173 		return -EINVAL;
174 	}
175 
176 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
177 		if (ehdlr->fd == efd) {
178 			break;
179 		}
180 	}
181 
182 	if (ehdlr == NULL) {
183 		return -EINVAL;
184 	}
185 
186 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
187 
188 	epevent.events = event_types;
189 	epevent.data.ptr = ehdlr;
190 
191 	return epoll_ctl(fgrp->epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
192 }
193 
194 int
195 spdk_fd_group_create(struct spdk_fd_group **_egrp)
196 {
197 	struct spdk_fd_group *fgrp;
198 
199 	if (_egrp == NULL) {
200 		return -EINVAL;
201 	}
202 
203 	fgrp = calloc(1, sizeof(*fgrp));
204 	if (fgrp == NULL) {
205 		return -ENOMEM;
206 	}
207 
208 	/* init the event source head */
209 	TAILQ_INIT(&fgrp->event_handlers);
210 
211 	fgrp->num_fds = 0;
212 	fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
213 	if (fgrp->epfd < 0) {
214 		free(fgrp);
215 		return -errno;
216 	}
217 
218 	*_egrp = fgrp;
219 
220 	return 0;
221 }
222 
223 void
224 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
225 {
226 	if (fgrp == NULL || fgrp->num_fds > 0) {
227 		SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
228 		assert(0);
229 		return;
230 	}
231 
232 	close(fgrp->epfd);
233 	free(fgrp);
234 
235 	return;
236 }
237 
238 int
239 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
240 {
241 	int totalfds = fgrp->num_fds;
242 	struct epoll_event events[totalfds];
243 	struct event_handler *ehdlr;
244 	int n;
245 	int nfds;
246 
247 	nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
248 	if (nfds < 0) {
249 		if (errno != EINTR) {
250 			SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
251 		}
252 
253 		return -errno;
254 	} else if (nfds == 0) {
255 		return 0;
256 	}
257 
258 	for (n = 0; n < nfds; n++) {
259 		/* find the event_handler */
260 		ehdlr = events[n].data.ptr;
261 
262 		if (ehdlr == NULL) {
263 			continue;
264 		}
265 
266 		/* Tag ehdlr as running state in case that it is removed
267 		 * during this wait loop but before or when it get executed.
268 		 */
269 		assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
270 		ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
271 	}
272 
273 	for (n = 0; n < nfds; n++) {
274 		/* find the event_handler */
275 		ehdlr = events[n].data.ptr;
276 
277 		if (ehdlr == NULL || ehdlr->fn == NULL) {
278 			continue;
279 		}
280 
281 		/* It is possible that the ehdlr was removed
282 		 * during this wait loop but before it get executed.
283 		 */
284 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
285 			free(ehdlr);
286 			continue;
287 		}
288 
289 		SPDK_DTRACE_PROBE4(interrupt_fd_process, ehdlr->name, ehdlr->fd,
290 				   ehdlr->fn, ehdlr->fn_arg);
291 
292 		g_event = &events[n];
293 		/* call the interrupt response function */
294 		ehdlr->fn(ehdlr->fn_arg);
295 		g_event = NULL;
296 
297 		/* It is possible that the ehdlr was removed
298 		 * during this wait loop when it get executed.
299 		 */
300 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
301 			free(ehdlr);
302 		} else {
303 			ehdlr->state = EVENT_HANDLER_STATE_WAITING;
304 		}
305 	}
306 
307 	return nfds;
308 }
309 
310 #else
311 
312 int
313 spdk_fd_group_get_epoll_event(struct epoll_event *event)
314 {
315 	return -ENOTSUP;
316 }
317 
318 int
319 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
320 		  void *arg, const char *name)
321 {
322 	return -ENOTSUP;
323 }
324 
325 void
326 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
327 {
328 }
329 
330 int
331 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
332 			   int efd, int event_types)
333 {
334 	return -ENOTSUP;
335 }
336 
337 int
338 spdk_fd_group_create(struct spdk_fd_group **fgrp)
339 {
340 	return -ENOTSUP;
341 }
342 
343 void
344 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
345 {
346 }
347 
348 int
349 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
350 {
351 	return -ENOTSUP;
352 }
353 
354 #endif
355