]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/select.c
Fix build errors on Fedora.
[thirdparty/cups.git] / scheduler / select.c
CommitLineData
f7deaa1a 1/*
f2d18633 2 * "$Id$"
f7deaa1a 3 *
5a1d7a17 4 * Select abstraction functions for the CUPS scheduler.
f7deaa1a 5 *
7e86f2f6 6 * Copyright 2007-2014 by Apple Inc.
5a1d7a17 7 * Copyright 2006-2007 by Easy Software Products.
f7deaa1a 8 *
5a1d7a17
MS
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
f7deaa1a 14 */
15
16/*
17 * Include necessary headers...
18 */
19
20#include "cupsd.h"
21
22#ifdef HAVE_EPOLL
23# include <sys/epoll.h>
dcb445bc 24# include <poll.h>
f7deaa1a 25#elif defined(HAVE_KQUEUE)
26# include <sys/event.h>
27# include <sys/time.h>
28#elif defined(HAVE_POLL)
dcb445bc 29# include <poll.h>
f7deaa1a 30#else
31# include <sys/select.h>
32#endif /* HAVE_EPOLL */
33
34
35/*
36 * Design Notes for Poll/Select API in CUPSD
37 * -----------------------------------------
3dd9c340 38 *
f7deaa1a 39 * SUPPORTED APIS
3dd9c340 40 *
f7deaa1a 41 * OS select poll epoll kqueue /dev/poll
42 * -------------- ------ ------ ------ ------ ---------
43 * AIX YES YES NO NO NO
44 * FreeBSD YES YES NO YES NO
45 * HP-UX YES YES NO NO NO
f7deaa1a 46 * Linux YES YES YES NO NO
47 * MacOS X YES YES NO YES NO
48 * NetBSD YES YES NO YES NO
49 * OpenBSD YES YES NO YES NO
50 * Solaris YES YES NO NO YES
51 * Tru64 YES YES NO NO NO
52 * Windows YES NO NO NO NO
3dd9c340
MS
53 *
54 *
f7deaa1a 55 * HIGH-LEVEL API
3dd9c340 56 *
f7deaa1a 57 * typedef void (*cupsd_selfunc_t)(void *data);
3dd9c340 58 *
f7deaa1a 59 * void cupsdStartSelect(void);
60 * void cupsdStopSelect(void);
61 * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
62 * cupsd_selfunc_t write_cb, void *data);
63 * void cupsdRemoveSelect(int fd);
64 * int cupsdDoSelect(int timeout);
3dd9c340
MS
65 *
66 *
f7deaa1a 67 * IMPLEMENTATION STRATEGY
3dd9c340 68 *
f7deaa1a 69 * 0. Common Stuff
70 * a. CUPS array of file descriptor to callback functions
c0e1af83 71 * and data + temporary array of removed fd's.
72 * b. cupsdStartSelect() creates the arrays
73 * c. cupsdStopSelect() destroys the arrays and all elements.
f7deaa1a 74 * d. cupsdAddSelect() adds to the array and allocates a
75 * new callback element.
c0e1af83 76 * e. cupsdRemoveSelect() removes from the active array and
77 * adds to the inactive array.
f7deaa1a 78 * f. _cupsd_fd_t provides a reference-counted structure for
79 * tracking file descriptors that are monitored.
c0e1af83 80 * g. cupsdDoSelect() frees all inactive FDs.
81 *
f7deaa1a 82 * 1. select() O(n)
83 * a. Input/Output fd_set variables, copied to working
84 * copies and then used with select().
85 * b. Loop through CUPS array, using FD_ISSET and calling
86 * the read/write callbacks as needed.
87 * c. cupsdRemoveSelect() clears fd_set bit from main and
88 * working sets.
89 * d. cupsdStopSelect() frees all of the memory used by the
90 * CUPS array and fd_set's.
3dd9c340 91 *
f7deaa1a 92 * 2. poll() - O(n log n)
93 * a. Regular array of pollfd, sorted the same as the CUPS
94 * array.
95 * b. Loop through pollfd array, call the corresponding
96 * read/write callbacks as needed.
97 * c. cupsdAddSelect() adds first to CUPS array and flags the
98 * pollfd array as invalid.
99 * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
100 * poll(), then loops through the pollfd array looking up
101 * as needed.
102 * e. cupsdRemoveSelect() flags the pollfd array as invalid.
103 * f. cupsdStopSelect() frees all of the memory used by the
104 * CUPS array and pollfd array.
3dd9c340 105 *
f7deaa1a 106 * 3. epoll() - O(n)
107 * a. cupsdStartSelect() creates epoll file descriptor using
108 * epoll_create() with the maximum fd count, and
109 * allocates an events buffer for the maximum fd count.
110 * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
111 * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
112 * event using the level-triggered semantics. The event
113 * user data field is a pointer to the new callback array
114 * element.
115 * c. cupsdDoSelect() uses epoll_wait() with the global event
116 * buffer allocated in cupsdStartSelect() and then loops
117 * through the events, using the user data field to find
118 * the callback record.
119 * d. cupsdStopSelect() closes the epoll file descriptor and
120 * frees all of the memory used by the event buffer.
3dd9c340 121 *
f7deaa1a 122 * 4. kqueue() - O(n)
123 * b. cupsdStartSelect() creates kqueue file descriptor
41681883 124 * using kqueue() function and allocates a global event
f7deaa1a 125 * buffer.
126 * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
127 * register the changes. The event user data field is a
128 * pointer to the new callback array element.
129 * d. cupsdDoSelect() uses kevent() to poll for events and
130 * loops through the events, using the user data field to
131 * find the callback record.
41681883 132 * e. cupsdStopSelect() closes the kqueue() file descriptor
f7deaa1a 133 * and frees all of the memory used by the event buffer.
3dd9c340 134 *
f7deaa1a 135 * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
136 * a. cupsdStartSelect() opens /dev/poll and allocates an
137 * array of pollfd structs; on failure to open /dev/poll,
138 * revert to poll() system call.
139 * b. cupsdAddSelect() writes a single pollfd struct to
140 * /dev/poll with the new file descriptor and the
141 * POLLIN/POLLOUT flags.
142 * c. cupsdRemoveSelect() writes a single pollfd struct to
143 * /dev/poll with the file descriptor and the POLLREMOVE
144 * flag.
145 * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
146 * events from /dev/poll and then loops through the
147 * returned pollfd array, looking up the file descriptors
148 * as needed.
149 * e. cupsdStopSelect() closes /dev/poll and frees the
150 * pollfd array.
151 *
152 * PERFORMANCE
153 *
154 * In tests using the "make test" target with option 0 (keep cupsd
155 * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
0a682745
MS
156 * performed 5.5% slower than select(), followed by kqueue() at 16%
157 * slower than select() and poll() at 18% slower than select(). Similar
f7deaa1a 158 * results were seen with twice the number of client connections.
159 *
160 * The epoll() and kqueue() performance is likely limited by the
161 * number of system calls used to add/modify/remove file
162 * descriptors dynamically. Further optimizations may be possible
163 * in the area of limiting use of cupsdAddSelect() and
164 * cupsdRemoveSelect(), however extreme care will be needed to avoid
165 * excess CPU usage and deadlock conditions.
166 *
167 * We may be able to improve the poll() implementation simply by
168 * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
169 * will eliminate the rebuilding of the array whenever there is a
170 * change and eliminate the fd array lookups in the inner loop of
171 * cupsdDoSelect().
172 *
173 * Since /dev/poll will never be able to use a shadow array, it may
174 * not make sense to implement support for it. ioctl() overhead will
175 * impact performance as well, so my guess would be that, for CUPS,
176 * /dev/poll will yield a net performance loss.
177 */
178
179/*
180 * Local structures...
181 */
182
183typedef struct _cupsd_fd_s
184{
185 int fd, /* File descriptor */
186 use; /* Use count */
187 cupsd_selfunc_t read_cb, /* Read callback */
188 write_cb; /* Write callback */
189 void *data; /* Data pointer for callbacks */
190} _cupsd_fd_t;
191
192
193/*
194 * Local globals...
195 */
196
197static cups_array_t *cupsd_fds = NULL;
c0e1af83 198#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
199static cups_array_t *cupsd_inactive_fds = NULL;
200static int cupsd_in_select = 0;
201#endif /* HAVE_EPOLL || HAVE_KQUEUE */
f7deaa1a 202
0a682745 203#ifdef HAVE_KQUEUE
f7deaa1a 204static int cupsd_kqueue_fd = -1,
205 cupsd_kqueue_changes = 0;
206static struct kevent *cupsd_kqueue_events = NULL;
207#elif defined(HAVE_POLL)
208static int cupsd_alloc_pollfds = 0,
209 cupsd_update_pollfds = 0;
210static struct pollfd *cupsd_pollfds = NULL;
0a682745
MS
211# ifdef HAVE_EPOLL
212static int cupsd_epoll_fd = -1;
213static struct epoll_event *cupsd_epoll_events = NULL;
214# endif /* HAVE_EPOLL */
f7deaa1a 215#else /* select() */
216static fd_set cupsd_global_input,
217 cupsd_global_output,
218 cupsd_current_input,
219 cupsd_current_output;
0a682745 220#endif /* HAVE_KQUEUE */
f7deaa1a 221
222
223/*
224 * Local functions...
225 */
226
227static int compare_fds(_cupsd_fd_t *a, _cupsd_fd_t *b);
228static _cupsd_fd_t *find_fd(int fd);
c7017ecc 229#define release_fd(f) { \
f7deaa1a 230 (f)->use --; \
231 if (!(f)->use) free((f));\
232 }
c7017ecc 233#define retain_fd(f) (f)->use++
f7deaa1a 234
235
236/*
237 * 'cupsdAddSelect()' - Add a file descriptor to the list.
238 */
239
240int /* O - 1 on success, 0 on error */
241cupsdAddSelect(int fd, /* I - File descriptor */
242 cupsd_selfunc_t read_cb, /* I - Read callback */
243 cupsd_selfunc_t write_cb,/* I - Write callback */
244 void *data) /* I - Data to pass to callback */
245{
246 _cupsd_fd_t *fdptr; /* File descriptor record */
1f0275e3 247#ifdef HAVE_EPOLL
f7deaa1a 248 int added; /* 1 if added, 0 if modified */
1f0275e3 249#endif /* HAVE_EPOLL */
f7deaa1a 250
251
252 /*
253 * Range check input...
254 */
255
1bc82dd9 256 cupsdLogMessage(CUPSD_LOG_DEBUG2,
b9faaae1 257 "cupsdAddSelect(fd=%d, read_cb=%p, write_cb=%p, data=%p)",
f7deaa1a 258 fd, read_cb, write_cb, data);
259
260 if (fd < 0)
261 return (0);
262
263 /*
264 * See if this FD has already been added...
265 */
266
267 if ((fdptr = find_fd(fd)) == NULL)
268 {
269 /*
270 * No, add a new entry...
271 */
272
273 if ((fdptr = calloc(1, sizeof(_cupsd_fd_t))) == NULL)
274 return (0);
275
276 fdptr->fd = fd;
277 fdptr->use = 1;
278
279 if (!cupsArrayAdd(cupsd_fds, fdptr))
280 {
281 cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to add fd %d to array!", fd);
282 free(fdptr);
283 return (0);
284 }
285
1f0275e3 286#ifdef HAVE_EPOLL
f7deaa1a 287 added = 1;
288 }
289 else
290 added = 0;
1f0275e3
MS
291#else
292 }
293#endif /* HAVE_EPOLL */
f7deaa1a 294
0a682745 295#ifdef HAVE_KQUEUE
f7deaa1a 296 {
297 struct kevent event; /* Event data */
298 struct timespec timeout; /* Timeout value */
299
300
301 timeout.tv_sec = 0;
302 timeout.tv_nsec = 0;
303
304 if (fdptr->read_cb != read_cb)
305 {
306 if (read_cb)
307 EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, fdptr);
308 else
309 EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
310
311 if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
312 {
b9faaae1 313 cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
f7deaa1a 314 strerror(errno));
315 return (0);
316 }
317 }
318
319 if (fdptr->write_cb != write_cb)
320 {
321 if (write_cb)
322 EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, fdptr);
323 else
324 EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
325
326 if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
327 {
b9faaae1 328 cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
f7deaa1a 329 strerror(errno));
330 return (0);
331 }
332 }
333 }
334
335#elif defined(HAVE_POLL)
0a682745
MS
336# ifdef HAVE_EPOLL
337 if (cupsd_epoll_fd >= 0)
338 {
339 struct epoll_event event; /* Event data */
340
341
342 event.events = 0;
343
344 if (read_cb)
345 event.events |= EPOLLIN;
346
347 if (write_cb)
348 event.events |= EPOLLOUT;
349
350 event.data.ptr = fdptr;
351
352 if (epoll_ctl(cupsd_epoll_fd, added ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd,
353 &event))
354 {
355 close(cupsd_epoll_fd);
356 cupsd_epoll_fd = -1;
357 cupsd_update_pollfds = 1;
358 }
359 }
360 else
361# endif /* HAVE_EPOLL */
362
f7deaa1a 363 cupsd_update_pollfds = 1;
364
365#else /* select() */
366 /*
367 * Add or remove the file descriptor in the input and output sets
368 * for select()...
369 */
370
371 if (read_cb)
f7deaa1a 372 FD_SET(fd, &cupsd_global_input);
f7deaa1a 373 else
374 {
f7deaa1a 375 FD_CLR(fd, &cupsd_global_input);
376 FD_CLR(fd, &cupsd_current_input);
377 }
378
379 if (write_cb)
f7deaa1a 380 FD_SET(fd, &cupsd_global_output);
f7deaa1a 381 else
382 {
f7deaa1a 383 FD_CLR(fd, &cupsd_global_output);
384 FD_CLR(fd, &cupsd_current_output);
385 }
0a682745 386#endif /* HAVE_KQUEUE */
f7deaa1a 387
388 /*
389 * Save the (new) read and write callbacks...
390 */
391
392 fdptr->read_cb = read_cb;
393 fdptr->write_cb = write_cb;
394 fdptr->data = data;
395
396 return (1);
397}
398
399
400/*
401 * 'cupsdDoSelect()' - Do a select-like operation.
402 */
403
404int /* O - Number of files or -1 on error */
405cupsdDoSelect(long timeout) /* I - Timeout in seconds */
406{
407 int nfds; /* Number of file descriptors */
408 _cupsd_fd_t *fdptr; /* Current file descriptor */
0a682745 409#ifdef HAVE_KQUEUE
f7deaa1a 410 int i; /* Looping var */
411 struct kevent *event; /* Current event */
412 struct timespec ktimeout; /* kevent() timeout */
413
414
c0e1af83 415 cupsd_in_select = 1;
416
f7deaa1a 417 if (timeout >= 0 && timeout < 86400)
418 {
419 ktimeout.tv_sec = timeout;
420 ktimeout.tv_nsec = 0;
421
422 nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs,
423 &ktimeout);
424 }
425 else
426 nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs, NULL);
427
f7deaa1a 428 cupsd_kqueue_changes = 0;
429
430 for (i = nfds, event = cupsd_kqueue_events; i > 0; i --, event ++)
431 {
432 fdptr = (_cupsd_fd_t *)event->udata;
433
c0e1af83 434 if (cupsArrayFind(cupsd_inactive_fds, fdptr))
435 continue;
436
f7deaa1a 437 retain_fd(fdptr);
438
439 if (fdptr->read_cb && event->filter == EVFILT_READ)
f7deaa1a 440 (*(fdptr->read_cb))(fdptr->data);
f7deaa1a 441
c7017ecc
MS
442 if (fdptr->use > 1 && fdptr->write_cb && event->filter == EVFILT_WRITE &&
443 !cupsArrayFind(cupsd_inactive_fds, fdptr))
f7deaa1a 444 (*(fdptr->write_cb))(fdptr->data);
f7deaa1a 445
446 release_fd(fdptr);
447 }
448
449#elif defined(HAVE_POLL)
450 struct pollfd *pfd; /* Current pollfd structure */
451 int count; /* Number of file descriptors */
452
453
0a682745
MS
454# ifdef HAVE_EPOLL
455 cupsd_in_select = 1;
456
457 if (cupsd_epoll_fd >= 0)
458 {
459 int i; /* Looping var */
460 struct epoll_event *event; /* Current event */
461
462
463 if (timeout >= 0 && timeout < 86400)
464 nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs,
465 timeout * 1000);
466 else
467 nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, -1);
468
0a682745
MS
469 if (nfds < 0 && errno != EINTR)
470 {
471 close(cupsd_epoll_fd);
472 cupsd_epoll_fd = -1;
473 }
474 else
475 {
476 for (i = nfds, event = cupsd_epoll_events; i > 0; i --, event ++)
477 {
478 fdptr = (_cupsd_fd_t *)event->data.ptr;
479
480 if (cupsArrayFind(cupsd_inactive_fds, fdptr))
481 continue;
482
483 retain_fd(fdptr);
484
485 if (fdptr->read_cb && (event->events & (EPOLLIN | EPOLLERR | EPOLLHUP)))
0a682745 486 (*(fdptr->read_cb))(fdptr->data);
0a682745 487
ef55b745 488 if (fdptr->use > 1 && fdptr->write_cb &&
c7017ecc
MS
489 (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) &&
490 !cupsArrayFind(cupsd_inactive_fds, fdptr))
0a682745 491 (*(fdptr->write_cb))(fdptr->data);
0a682745
MS
492
493 release_fd(fdptr);
494 }
495
496 goto release_inactive;
497 }
498 }
499# endif /* HAVE_EPOLL */
500
f7deaa1a 501 count = cupsArrayCount(cupsd_fds);
502
503 if (cupsd_update_pollfds)
504 {
505 /*
506 * Update the cupsd_pollfds array to match the current FD array...
507 */
508
509 cupsd_update_pollfds = 0;
510
f7deaa1a 511 /*
512 * (Re)allocate memory as needed...
513 */
514
515 if (count > cupsd_alloc_pollfds)
516 {
517 int allocfds = count + 16;
518
519
520 if (cupsd_pollfds)
07623986 521 pfd = realloc(cupsd_pollfds, (size_t)allocfds * sizeof(struct pollfd));
f7deaa1a 522 else
07623986 523 pfd = malloc((size_t)allocfds * sizeof(struct pollfd));
f7deaa1a 524
525 if (!pfd)
526 {
07623986 527 cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to allocate %d bytes for polling.", (int)((size_t)allocfds * sizeof(struct pollfd)));
f7deaa1a 528
529 return (-1);
530 }
531
532 cupsd_pollfds = pfd;
533 cupsd_alloc_pollfds = allocfds;
534 }
535
536 /*
537 * Rebuild the array...
538 */
539
540 for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds), pfd = cupsd_pollfds;
541 fdptr;
542 fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds), pfd ++)
543 {
544 pfd->fd = fdptr->fd;
545 pfd->events = 0;
546
547 if (fdptr->read_cb)
548 pfd->events |= POLLIN;
549
550 if (fdptr->write_cb)
551 pfd->events |= POLLOUT;
552 }
553 }
554
f7deaa1a 555 if (timeout >= 0 && timeout < 86400)
07623986 556 nfds = poll(cupsd_pollfds, (nfds_t)count, timeout * 1000);
f7deaa1a 557 else
07623986 558 nfds = poll(cupsd_pollfds, (nfds_t)count, -1);
f7deaa1a 559
f7deaa1a 560 if (nfds > 0)
561 {
562 /*
563 * Do callbacks for each file descriptor...
564 */
565
566 for (pfd = cupsd_pollfds; count > 0; pfd ++, count --)
567 {
f7deaa1a 568 if (!pfd->revents)
569 continue;
570
571 if ((fdptr = find_fd(pfd->fd)) == NULL)
572 continue;
573
574 retain_fd(fdptr);
575
576 if (fdptr->read_cb && (pfd->revents & (POLLIN | POLLERR | POLLHUP)))
f7deaa1a 577 (*(fdptr->read_cb))(fdptr->data);
f7deaa1a 578
ef55b745
MS
579 if (fdptr->use > 1 && fdptr->write_cb &&
580 (pfd->revents & (POLLOUT | POLLERR | POLLHUP)))
f7deaa1a 581 (*(fdptr->write_cb))(fdptr->data);
f7deaa1a 582
583 release_fd(fdptr);
584 }
585 }
586
587#else /* select() */
588 struct timeval stimeout; /* Timeout for select() */
589 int maxfd; /* Maximum file descriptor */
590
591
592 /*
593 * Figure out the highest file descriptor number...
594 */
595
596 if ((fdptr = (_cupsd_fd_t *)cupsArrayLast(cupsd_fds)) == NULL)
597 maxfd = 1;
598 else
599 maxfd = fdptr->fd + 1;
600
601 /*
602 * Do the select()...
603 */
604
605 cupsd_current_input = cupsd_global_input;
606 cupsd_current_output = cupsd_global_output;
607
f7deaa1a 608 if (timeout >= 0 && timeout < 86400)
609 {
610 stimeout.tv_sec = timeout;
611 stimeout.tv_usec = 0;
612
613 nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
614 &stimeout);
615 }
616 else
617 nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
618 NULL);
619
f7deaa1a 620 if (nfds > 0)
621 {
622 /*
623 * Do callbacks for each file descriptor...
624 */
625
626 for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
627 fdptr;
628 fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
629 {
630 retain_fd(fdptr);
631
632 if (fdptr->read_cb && FD_ISSET(fdptr->fd, &cupsd_current_input))
f7deaa1a 633 (*(fdptr->read_cb))(fdptr->data);
f7deaa1a 634
ef55b745
MS
635 if (fdptr->use > 1 && fdptr->write_cb &&
636 FD_ISSET(fdptr->fd, &cupsd_current_output))
f7deaa1a 637 (*(fdptr->write_cb))(fdptr->data);
f7deaa1a 638
639 release_fd(fdptr);
640 }
641 }
642
0a682745 643#endif /* HAVE_KQUEUE */
f7deaa1a 644
c0e1af83 645#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
646 /*
647 * Release all inactive file descriptors...
648 */
649
0a682745
MS
650# ifndef HAVE_KQUEUE
651 release_inactive:
652# endif /* !HAVE_KQUEUE */
653
c0e1af83 654 cupsd_in_select = 0;
655
656 for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_inactive_fds);
657 fdptr;
658 fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_inactive_fds))
659 {
660 cupsArrayRemove(cupsd_inactive_fds, fdptr);
661 release_fd(fdptr);
662 }
663#endif /* HAVE_EPOLL || HAVE_KQUEUE */
664
f7deaa1a 665 /*
666 * Return the number of file descriptors handled...
667 */
668
669 return (nfds);
670}
671
672
f899b121 673#ifdef CUPSD_IS_SELECTING
f7deaa1a 674/*
675 * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
676 * descriptor.
677 */
678
679int /* O - 1 if selecting, 0 otherwise */
680cupsdIsSelecting(int fd) /* I - File descriptor */
681{
682 return (find_fd(fd) != NULL);
683}
f899b121 684#endif /* CUPSD_IS_SELECTING */
f7deaa1a 685
686
687/*
688 * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
689 */
690
691void
692cupsdRemoveSelect(int fd) /* I - File descriptor */
693{
694 _cupsd_fd_t *fdptr; /* File descriptor record */
695#ifdef HAVE_EPOLL
696 struct epoll_event event; /* Event data */
697#elif defined(HAVE_KQUEUE)
698 struct kevent event; /* Event data */
699 struct timespec timeout; /* Timeout value */
700#elif defined(HAVE_POLL)
701 /* No variables for poll() */
702#endif /* HAVE_EPOLL */
703
704
705 /*
706 * Range check input...
707 */
708
1bc82dd9 709 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRemoveSelect(fd=%d)", fd);
f7deaa1a 710
711 if (fd < 0)
712 return;
713
714 /*
715 * Find the file descriptor...
716 */
717
718 if ((fdptr = find_fd(fd)) == NULL)
719 return;
720
721#ifdef HAVE_EPOLL
0a682745
MS
722 if (epoll_ctl(cupsd_epoll_fd, EPOLL_CTL_DEL, fd, &event))
723 {
724 close(cupsd_epoll_fd);
725 cupsd_epoll_fd = -1;
726 cupsd_update_pollfds = 1;
727 }
f7deaa1a 728
729#elif defined(HAVE_KQUEUE)
730 timeout.tv_sec = 0;
731 timeout.tv_nsec = 0;
732
733 if (fdptr->read_cb)
734 {
735 EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
736
737 if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
738 {
b9faaae1 739 cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
f7deaa1a 740 strerror(errno));
4a4b4f99 741 goto cleanup;
f7deaa1a 742 }
743 }
744
745 if (fdptr->write_cb)
746 {
747 EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
748
749 if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
750 {
b9faaae1 751 cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
f7deaa1a 752 strerror(errno));
4a4b4f99 753 goto cleanup;
f7deaa1a 754 }
755 }
756
f7deaa1a 757#elif defined(HAVE_POLL)
758 /*
759 * Update the pollfds array...
760 */
761
762 cupsd_update_pollfds = 1;
763
764#else /* select() */
f7deaa1a 765 FD_CLR(fd, &cupsd_global_input);
766 FD_CLR(fd, &cupsd_global_output);
767 FD_CLR(fd, &cupsd_current_input);
768 FD_CLR(fd, &cupsd_current_output);
769#endif /* HAVE_EPOLL */
770
4a4b4f99
MS
771#ifdef HAVE_KQUEUE
772 cleanup:
773#endif /* HAVE_KQUEUE */
774
f7deaa1a 775 /*
c0e1af83 776 * Remove the file descriptor from the active array and add to the
777 * inactive array (or release, if we don't need the inactive array...)
f7deaa1a 778 */
779
780 cupsArrayRemove(cupsd_fds, fdptr);
c0e1af83 781
782#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
783 if (cupsd_in_select)
784 cupsArrayAdd(cupsd_inactive_fds, fdptr);
785 else
786#endif /* HAVE_EPOLL || HAVE_KQUEUE */
787
f7deaa1a 788 release_fd(fdptr);
789}
790
791
792/*
793 * 'cupsdStartSelect()' - Initialize the file polling engine.
794 */
795
796void
797cupsdStartSelect(void)
798{
f2d18633 799 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartSelect()");
b9faaae1 800
f7deaa1a 801 cupsd_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL);
802
c0e1af83 803#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
804 cupsd_inactive_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL);
805#endif /* HAVE_EPOLL || HAVE_KQUEUE */
806
f7deaa1a 807#ifdef HAVE_EPOLL
0a682745 808 cupsd_epoll_fd = epoll_create(MaxFDs);
07623986 809 cupsd_epoll_events = calloc((size_t)MaxFDs, sizeof(struct epoll_event));
0a682745 810 cupsd_update_pollfds = 0;
f7deaa1a 811
812#elif defined(HAVE_KQUEUE)
813 cupsd_kqueue_fd = kqueue();
814 cupsd_kqueue_changes = 0;
7e86f2f6 815 cupsd_kqueue_events = calloc((size_t)MaxFDs, sizeof(struct kevent));
f7deaa1a 816
817#elif defined(HAVE_POLL)
818 cupsd_update_pollfds = 0;
819
820#else /* select() */
821 FD_ZERO(&cupsd_global_input);
822 FD_ZERO(&cupsd_global_output);
823#endif /* HAVE_EPOLL */
824}
825
826
827/*
828 * 'cupsdStopSelect()' - Shutdown the file polling engine.
829 */
830
831void
832cupsdStopSelect(void)
833{
834 _cupsd_fd_t *fdptr; /* Current file descriptor */
835
836
f2d18633 837 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopSelect()");
b9faaae1 838
f7deaa1a 839 for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
840 fdptr;
841 fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
842 free(fdptr);
843
844 cupsArrayDelete(cupsd_fds);
845 cupsd_fds = NULL;
846
c0e1af83 847#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
848 cupsArrayDelete(cupsd_inactive_fds);
849 cupsd_inactive_fds = NULL;
850#endif /* HAVE_EPOLL || HAVE_KQUEUE */
851
0a682745 852#ifdef HAVE_KQUEUE
f7deaa1a 853 if (cupsd_kqueue_events)
854 {
855 free(cupsd_kqueue_events);
856 cupsd_kqueue_events = NULL;
857 }
858
859 if (cupsd_kqueue_fd >= 0)
860 {
861 close(cupsd_kqueue_fd);
862 cupsd_kqueue_fd = -1;
863 }
864
865 cupsd_kqueue_changes = 0;
866
867#elif defined(HAVE_POLL)
0a682745
MS
868# ifdef HAVE_EPOLL
869 if (cupsd_epoll_events)
870 {
871 free(cupsd_epoll_events);
872 cupsd_epoll_events = NULL;
873 }
874
875 if (cupsd_epoll_fd >= 0)
876 {
877 close(cupsd_epoll_fd);
878 cupsd_epoll_fd = -1;
879 }
880# endif /* HAVE_EPOLL */
881
f7deaa1a 882 if (cupsd_pollfds)
883 {
884 free(cupsd_pollfds);
885 cupsd_pollfds = NULL;
886 cupsd_alloc_pollfds = 0;
887 }
888
889 cupsd_update_pollfds = 0;
890
891#else /* select() */
892 FD_ZERO(&cupsd_global_input);
893 FD_ZERO(&cupsd_global_output);
894#endif /* HAVE_EPOLL */
895}
896
897
898/*
899 * 'compare_fds()' - Compare file descriptors.
900 */
901
902static int /* O - Result of comparison */
903compare_fds(_cupsd_fd_t *a, /* I - First file descriptor */
904 _cupsd_fd_t *b) /* I - Second file descriptor */
905{
906 return (a->fd - b->fd);
907}
908
909
910/*
911 * 'find_fd()' - Find an existing file descriptor record.
912 */
913
914static _cupsd_fd_t * /* O - FD record pointer or NULL */
915find_fd(int fd) /* I - File descriptor */
916{
917 _cupsd_fd_t *fdptr, /* Matching record (if any) */
918 key; /* Search key */
919
920
921 cupsArraySave(cupsd_fds);
922
923 key.fd = fd;
924 fdptr = (_cupsd_fd_t *)cupsArrayFind(cupsd_fds, &key);
925
926 cupsArrayRestore(cupsd_fds);
927
928 return (fdptr);
929}
930
931
932/*
f2d18633 933 * End of "$Id$".
f7deaa1a 934 */