2 * "$Id: select.c 7720 2008-07-11 22:46:21Z mike $"
4 * Select abstraction functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 2006-2007 by Easy Software Products.
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/".
17 * cupsdAddSelect() - Add a file descriptor to the list.
18 * cupsdDoSelect() - Do a select-like operation.
19 * cupsdIsSelecting() - Determine whether we are monitoring a file
21 * cupsdRemoveSelect() - Remove a file descriptor from the list.
22 * cupsdStartSelect() - Initialize the file polling engine.
23 * cupsdStopSelect() - Shutdown the file polling engine.
24 * compare_fds() - Compare file descriptors.
25 * find_fd() - Find an existing file descriptor record.
29 * Include necessary headers...
35 # include <sys/epoll.h>
36 # include <sys/poll.h>
37 #elif defined(HAVE_KQUEUE)
38 # include <sys/event.h>
39 # include <sys/time.h>
40 #elif defined(HAVE_POLL)
41 # include <sys/poll.h>
43 # include <sys/time.h>
45 # include <sys/select.h>
46 #endif /* HAVE_EPOLL */
50 * Design Notes for Poll/Select API in CUPSD
51 * -----------------------------------------
55 * OS select poll epoll kqueue /dev/poll
56 * -------------- ------ ------ ------ ------ ---------
57 * AIX YES YES NO NO NO
58 * FreeBSD YES YES NO YES NO
59 * HP-UX YES YES NO NO NO
60 * IRIX YES YES NO NO NO
61 * Linux YES YES YES NO NO
62 * MacOS X YES YES NO YES NO
63 * NetBSD YES YES NO YES NO
64 * OpenBSD YES YES NO YES NO
65 * Solaris YES YES NO NO YES
66 * Tru64 YES YES NO NO NO
67 * Windows YES NO NO NO NO
72 * typedef void (*cupsd_selfunc_t)(void *data);
74 * void cupsdStartSelect(void);
75 * void cupsdStopSelect(void);
76 * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
77 * cupsd_selfunc_t write_cb, void *data);
78 * void cupsdRemoveSelect(int fd);
79 * int cupsdDoSelect(int timeout);
82 * IMPLEMENTATION STRATEGY
85 * a. CUPS array of file descriptor to callback functions
86 * and data + temporary array of removed fd's.
87 * b. cupsdStartSelect() creates the arrays
88 * c. cupsdStopSelect() destroys the arrays and all elements.
89 * d. cupsdAddSelect() adds to the array and allocates a
90 * new callback element.
91 * e. cupsdRemoveSelect() removes from the active array and
92 * adds to the inactive array.
93 * f. _cupsd_fd_t provides a reference-counted structure for
94 * tracking file descriptors that are monitored.
95 * g. cupsdDoSelect() frees all inactive FDs.
98 * a. Input/Output fd_set variables, copied to working
99 * copies and then used with select().
100 * b. Loop through CUPS array, using FD_ISSET and calling
101 * the read/write callbacks as needed.
102 * c. cupsdRemoveSelect() clears fd_set bit from main and
104 * d. cupsdStopSelect() frees all of the memory used by the
105 * CUPS array and fd_set's.
107 * 2. poll() - O(n log n)
108 * a. Regular array of pollfd, sorted the same as the CUPS
110 * b. Loop through pollfd array, call the corresponding
111 * read/write callbacks as needed.
112 * c. cupsdAddSelect() adds first to CUPS array and flags the
113 * pollfd array as invalid.
114 * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
115 * poll(), then loops through the pollfd array looking up
117 * e. cupsdRemoveSelect() flags the pollfd array as invalid.
118 * f. cupsdStopSelect() frees all of the memory used by the
119 * CUPS array and pollfd array.
122 * a. cupsdStartSelect() creates epoll file descriptor using
123 * epoll_create() with the maximum fd count, and
124 * allocates an events buffer for the maximum fd count.
125 * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
126 * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
127 * event using the level-triggered semantics. The event
128 * user data field is a pointer to the new callback array
130 * c. cupsdDoSelect() uses epoll_wait() with the global event
131 * buffer allocated in cupsdStartSelect() and then loops
132 * through the events, using the user data field to find
133 * the callback record.
134 * d. cupsdStopSelect() closes the epoll file descriptor and
135 * frees all of the memory used by the event buffer.
138 * b. cupsdStartSelect() creates kqueue file descriptor
139 * using kqyeue() function and allocates a global event
141 * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
142 * register the changes. The event user data field is a
143 * pointer to the new callback array element.
144 * d. cupsdDoSelect() uses kevent() to poll for events and
145 * loops through the events, using the user data field to
146 * find the callback record.
147 * e. cupsdStopSelect() closes the kqyeye() file descriptor
148 * and frees all of the memory used by the event buffer.
150 * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
151 * a. cupsdStartSelect() opens /dev/poll and allocates an
152 * array of pollfd structs; on failure to open /dev/poll,
153 * revert to poll() system call.
154 * b. cupsdAddSelect() writes a single pollfd struct to
155 * /dev/poll with the new file descriptor and the
156 * POLLIN/POLLOUT flags.
157 * c. cupsdRemoveSelect() writes a single pollfd struct to
158 * /dev/poll with the file descriptor and the POLLREMOVE
160 * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
161 * events from /dev/poll and then loops through the
162 * returned pollfd array, looking up the file descriptors
164 * e. cupsdStopSelect() closes /dev/poll and frees the
169 * In tests using the "make test" target with option 0 (keep cupsd
170 * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
171 * performed 5.5% slower than select(), followed by kqueue() at 16%
172 * slower than select() and poll() at 18% slower than select(). Similar
173 * results were seen with twice the number of client connections.
175 * The epoll() and kqueue() performance is likely limited by the
176 * number of system calls used to add/modify/remove file
177 * descriptors dynamically. Further optimizations may be possible
178 * in the area of limiting use of cupsdAddSelect() and
179 * cupsdRemoveSelect(), however extreme care will be needed to avoid
180 * excess CPU usage and deadlock conditions.
182 * We may be able to improve the poll() implementation simply by
183 * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
184 * will eliminate the rebuilding of the array whenever there is a
185 * change and eliminate the fd array lookups in the inner loop of
188 * Since /dev/poll will never be able to use a shadow array, it may
189 * not make sense to implement support for it. ioctl() overhead will
190 * impact performance as well, so my guess would be that, for CUPS,
191 * /dev/poll will yield a net performance loss.
195 * Local structures...
198 typedef struct _cupsd_fd_s
200 int fd
, /* File descriptor */
202 cupsd_selfunc_t read_cb
, /* Read callback */
203 write_cb
; /* Write callback */
204 void *data
; /* Data pointer for callbacks */
212 static cups_array_t
*cupsd_fds
= NULL
;
213 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
214 static cups_array_t
*cupsd_inactive_fds
= NULL
;
215 static int cupsd_in_select
= 0;
216 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
219 static int cupsd_kqueue_fd
= -1,
220 cupsd_kqueue_changes
= 0;
221 static struct kevent
*cupsd_kqueue_events
= NULL
;
222 #elif defined(HAVE_POLL)
223 static int cupsd_alloc_pollfds
= 0,
224 cupsd_update_pollfds
= 0;
225 static struct pollfd
*cupsd_pollfds
= NULL
;
227 static int cupsd_epoll_fd
= -1;
228 static struct epoll_event
*cupsd_epoll_events
= NULL
;
229 # endif /* HAVE_EPOLL */
231 static fd_set cupsd_global_input
,
234 cupsd_current_output
;
235 #endif /* HAVE_KQUEUE */
242 static int compare_fds(_cupsd_fd_t
*a
, _cupsd_fd_t
*b
);
243 static _cupsd_fd_t
*find_fd(int fd
);
244 #define release_fd(f) { \
246 if (!(f)->use) free((f));\
248 #define retain_fd(f) (f)->use++
252 * 'cupsdAddSelect()' - Add a file descriptor to the list.
255 int /* O - 1 on success, 0 on error */
256 cupsdAddSelect(int fd
, /* I - File descriptor */
257 cupsd_selfunc_t read_cb
, /* I - Read callback */
258 cupsd_selfunc_t write_cb
,/* I - Write callback */
259 void *data
) /* I - Data to pass to callback */
261 _cupsd_fd_t
*fdptr
; /* File descriptor record */
263 int added
; /* 1 if added, 0 if modified */
264 #endif /* HAVE_EPOLL */
268 * Range check input...
271 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
272 "cupsdAddSelect: fd=%d, read_cb=%p, write_cb=%p, data=%p",
273 fd
, read_cb
, write_cb
, data
);
279 * See if this FD has already been added...
282 if ((fdptr
= find_fd(fd
)) == NULL
)
285 * No, add a new entry...
288 if ((fdptr
= calloc(1, sizeof(_cupsd_fd_t
))) == NULL
)
294 if (!cupsArrayAdd(cupsd_fds
, fdptr
))
296 cupsdLogMessage(CUPSD_LOG_EMERG
, "Unable to add fd %d to array!", fd
);
308 #endif /* HAVE_EPOLL */
312 struct kevent event
; /* Event data */
313 struct timespec timeout
; /* Timeout value */
319 if (fdptr
->read_cb
!= read_cb
)
322 EV_SET(&event
, fd
, EVFILT_READ
, EV_ADD
, 0, 0, fdptr
);
324 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
326 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
328 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
329 "cupsdAddSelect: kevent() returned %s",
335 if (fdptr
->write_cb
!= write_cb
)
338 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_ADD
, 0, 0, fdptr
);
340 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
342 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
344 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
345 "cupsdAddSelect: kevent() returned %s",
352 #elif defined(HAVE_POLL)
354 if (cupsd_epoll_fd
>= 0)
356 struct epoll_event event
; /* Event data */
362 event
.events
|= EPOLLIN
;
365 event
.events
|= EPOLLOUT
;
367 event
.data
.ptr
= fdptr
;
369 if (epoll_ctl(cupsd_epoll_fd
, added
? EPOLL_CTL_ADD
: EPOLL_CTL_MOD
, fd
,
372 close(cupsd_epoll_fd
);
374 cupsd_update_pollfds
= 1;
378 # endif /* HAVE_EPOLL */
380 cupsd_update_pollfds
= 1;
384 * Add or remove the file descriptor in the input and output sets
390 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
391 "cupsdAddSelect: Adding fd %d to input set...", fd
);
392 FD_SET(fd
, &cupsd_global_input
);
396 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
397 "cupsdAddSelect: Removing fd %d from input set...", fd
);
398 FD_CLR(fd
, &cupsd_global_input
);
399 FD_CLR(fd
, &cupsd_current_input
);
404 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
405 "cupsdAddSelect: Adding fd %d to output set...", fd
);
406 FD_SET(fd
, &cupsd_global_output
);
410 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
411 "cupsdAddSelect: Removing fd %d from output set...", fd
);
412 FD_CLR(fd
, &cupsd_global_output
);
413 FD_CLR(fd
, &cupsd_current_output
);
415 #endif /* HAVE_KQUEUE */
418 * Save the (new) read and write callbacks...
421 fdptr
->read_cb
= read_cb
;
422 fdptr
->write_cb
= write_cb
;
430 * 'cupsdDoSelect()' - Do a select-like operation.
433 int /* O - Number of files or -1 on error */
434 cupsdDoSelect(long timeout
) /* I - Timeout in seconds */
436 int nfds
; /* Number of file descriptors */
437 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
439 int i
; /* Looping var */
440 struct kevent
*event
; /* Current event */
441 struct timespec ktimeout
; /* kevent() timeout */
444 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
445 "cupsdDoSelect: polling %d fds for %ld seconds...",
446 cupsArrayCount(cupsd_fds
), timeout
);
450 if (timeout
>= 0 && timeout
< 86400)
452 ktimeout
.tv_sec
= timeout
;
453 ktimeout
.tv_nsec
= 0;
455 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
,
459 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
, NULL
);
461 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
462 "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...",
463 cupsd_kqueue_fd
, MaxFDs
, nfds
);
465 cupsd_kqueue_changes
= 0;
467 for (i
= nfds
, event
= cupsd_kqueue_events
; i
> 0; i
--, event
++)
469 fdptr
= (_cupsd_fd_t
*)event
->udata
;
471 if (cupsArrayFind(cupsd_inactive_fds
, fdptr
))
474 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "event->filter=%d, event->ident=%d",
475 event
->filter
, (int)event
->ident
);
479 if (fdptr
->read_cb
&& event
->filter
== EVFILT_READ
)
481 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
483 (*(fdptr
->read_cb
))(fdptr
->data
);
486 if (fdptr
->write_cb
&& event
->filter
== EVFILT_WRITE
)
488 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
490 (*(fdptr
->write_cb
))(fdptr
->data
);
496 #elif defined(HAVE_POLL)
497 struct pollfd
*pfd
; /* Current pollfd structure */
498 int count
; /* Number of file descriptors */
501 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
502 "cupsdDoSelect: polling %d fds for %ld seconds...",
503 cupsArrayCount(cupsd_fds
), timeout
);
508 if (cupsd_epoll_fd
>= 0)
510 int i
; /* Looping var */
511 struct epoll_event
*event
; /* Current event */
514 if (timeout
>= 0 && timeout
< 86400)
515 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
,
518 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
, -1);
520 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: epoll() returned %d...",
523 if (nfds
< 0 && errno
!= EINTR
)
525 close(cupsd_epoll_fd
);
530 for (i
= nfds
, event
= cupsd_epoll_events
; i
> 0; i
--, event
++)
532 fdptr
= (_cupsd_fd_t
*)event
->data
.ptr
;
534 if (cupsArrayFind(cupsd_inactive_fds
, fdptr
))
539 if (fdptr
->read_cb
&& (event
->events
& (EPOLLIN
| EPOLLERR
| EPOLLHUP
)))
541 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
543 (*(fdptr
->read_cb
))(fdptr
->data
);
546 if (fdptr
->write_cb
&& (event
->events
& (EPOLLOUT
| EPOLLERR
| EPOLLHUP
)))
548 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
550 (*(fdptr
->write_cb
))(fdptr
->data
);
556 goto release_inactive
;
559 # endif /* HAVE_EPOLL */
561 count
= cupsArrayCount(cupsd_fds
);
563 if (cupsd_update_pollfds
)
566 * Update the cupsd_pollfds array to match the current FD array...
569 cupsd_update_pollfds
= 0;
571 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Updating pollfd array...");
574 * (Re)allocate memory as needed...
577 if (count
> cupsd_alloc_pollfds
)
579 int allocfds
= count
+ 16;
583 pfd
= realloc(cupsd_pollfds
, allocfds
* sizeof(struct pollfd
));
585 pfd
= malloc(allocfds
* sizeof(struct pollfd
));
589 cupsdLogMessage(CUPSD_LOG_EMERG
,
590 "Unable to allocate %d bytes for polling!",
591 (int)(allocfds
* sizeof(struct pollfd
)));
597 cupsd_alloc_pollfds
= allocfds
;
601 * Rebuild the array...
604 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
), pfd
= cupsd_pollfds
;
606 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
), pfd
++)
612 pfd
->events
|= POLLIN
;
615 pfd
->events
|= POLLOUT
;
619 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
620 "cupsdDoSelect: polling %d fds for %ld seconds...",
623 if (timeout
>= 0 && timeout
< 86400)
624 nfds
= poll(cupsd_pollfds
, count
, timeout
* 1000);
626 nfds
= poll(cupsd_pollfds
, count
, -1);
628 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: poll() returned %d...",
634 * Do callbacks for each file descriptor...
637 for (pfd
= cupsd_pollfds
; count
> 0; pfd
++, count
--)
639 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
640 "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
641 pfd
- cupsd_pollfds
, pfd
->fd
, pfd
->revents
);
646 if ((fdptr
= find_fd(pfd
->fd
)) == NULL
)
651 if (fdptr
->read_cb
&& (pfd
->revents
& (POLLIN
| POLLERR
| POLLHUP
)))
653 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
655 (*(fdptr
->read_cb
))(fdptr
->data
);
658 if (fdptr
->write_cb
&& (pfd
->revents
& (POLLOUT
| POLLERR
| POLLHUP
)))
660 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
662 (*(fdptr
->write_cb
))(fdptr
->data
);
670 struct timeval stimeout
; /* Timeout for select() */
671 int maxfd
; /* Maximum file descriptor */
675 * Figure out the highest file descriptor number...
678 if ((fdptr
= (_cupsd_fd_t
*)cupsArrayLast(cupsd_fds
)) == NULL
)
681 maxfd
= fdptr
->fd
+ 1;
687 cupsd_current_input
= cupsd_global_input
;
688 cupsd_current_output
= cupsd_global_output
;
690 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
691 "cupsdDoSelect: selecting %d fds for %ld seconds...",
694 if (timeout
>= 0 && timeout
< 86400)
696 stimeout
.tv_sec
= timeout
;
697 stimeout
.tv_usec
= 0;
699 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
703 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
706 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: select() returned %d...",
712 * Do callbacks for each file descriptor...
715 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
717 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
721 if (fdptr
->read_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_input
))
723 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
725 (*(fdptr
->read_cb
))(fdptr
->data
);
728 if (fdptr
->write_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_output
))
730 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
732 (*(fdptr
->write_cb
))(fdptr
->data
);
739 #endif /* HAVE_KQUEUE */
741 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
743 * Release all inactive file descriptors...
748 # endif /* !HAVE_KQUEUE */
752 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_inactive_fds
);
754 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_inactive_fds
))
756 cupsArrayRemove(cupsd_inactive_fds
, fdptr
);
759 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
762 * Return the number of file descriptors handled...
769 #ifdef CUPSD_IS_SELECTING
771 * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
775 int /* O - 1 if selecting, 0 otherwise */
776 cupsdIsSelecting(int fd
) /* I - File descriptor */
778 return (find_fd(fd
) != NULL
);
780 #endif /* CUPSD_IS_SELECTING */
784 * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
788 cupsdRemoveSelect(int fd
) /* I - File descriptor */
790 _cupsd_fd_t
*fdptr
; /* File descriptor record */
792 struct epoll_event event
; /* Event data */
793 #elif defined(HAVE_KQUEUE)
794 struct kevent event
; /* Event data */
795 struct timespec timeout
; /* Timeout value */
796 #elif defined(HAVE_POLL)
797 /* No variables for poll() */
798 #endif /* HAVE_EPOLL */
802 * Range check input...
805 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdRemoveSelect: fd=%d", fd
);
811 * Find the file descriptor...
814 if ((fdptr
= find_fd(fd
)) == NULL
)
818 if (epoll_ctl(cupsd_epoll_fd
, EPOLL_CTL_DEL
, fd
, &event
))
820 close(cupsd_epoll_fd
);
822 cupsd_update_pollfds
= 1;
825 #elif defined(HAVE_KQUEUE)
831 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
833 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
835 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
836 "cupsdRemoveSelect: kevent() returned %s",
844 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
846 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
848 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
849 "cupsdRemoveSelect: kevent() returned %s",
856 #elif defined(HAVE_POLL)
858 * Update the pollfds array...
861 cupsd_update_pollfds
= 1;
864 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
865 "cupsdRemoveSelect: Removing fd %d from input and output "
867 FD_CLR(fd
, &cupsd_global_input
);
868 FD_CLR(fd
, &cupsd_global_output
);
869 FD_CLR(fd
, &cupsd_current_input
);
870 FD_CLR(fd
, &cupsd_current_output
);
871 #endif /* HAVE_EPOLL */
874 * Remove the file descriptor from the active array and add to the
875 * inactive array (or release, if we don't need the inactive array...)
878 cupsArrayRemove(cupsd_fds
, fdptr
);
880 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
882 cupsArrayAdd(cupsd_inactive_fds
, fdptr
);
884 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
891 * 'cupsdStartSelect()' - Initialize the file polling engine.
895 cupsdStartSelect(void)
897 cupsd_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
899 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
900 cupsd_inactive_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
901 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
904 cupsd_epoll_fd
= epoll_create(MaxFDs
);
905 cupsd_epoll_events
= calloc(MaxFDs
, sizeof(struct epoll_event
));
906 cupsd_update_pollfds
= 0;
908 #elif defined(HAVE_KQUEUE)
909 cupsd_kqueue_fd
= kqueue();
910 cupsd_kqueue_changes
= 0;
911 cupsd_kqueue_events
= calloc(MaxFDs
, sizeof(struct kevent
));
913 #elif defined(HAVE_POLL)
914 cupsd_update_pollfds
= 0;
917 FD_ZERO(&cupsd_global_input
);
918 FD_ZERO(&cupsd_global_output
);
919 #endif /* HAVE_EPOLL */
924 * 'cupsdStopSelect()' - Shutdown the file polling engine.
928 cupsdStopSelect(void)
930 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
933 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
935 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
938 cupsArrayDelete(cupsd_fds
);
941 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
942 cupsArrayDelete(cupsd_inactive_fds
);
943 cupsd_inactive_fds
= NULL
;
944 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
947 if (cupsd_kqueue_events
)
949 free(cupsd_kqueue_events
);
950 cupsd_kqueue_events
= NULL
;
953 if (cupsd_kqueue_fd
>= 0)
955 close(cupsd_kqueue_fd
);
956 cupsd_kqueue_fd
= -1;
959 cupsd_kqueue_changes
= 0;
961 #elif defined(HAVE_POLL)
963 if (cupsd_epoll_events
)
965 free(cupsd_epoll_events
);
966 cupsd_epoll_events
= NULL
;
969 if (cupsd_epoll_fd
>= 0)
971 close(cupsd_epoll_fd
);
974 # endif /* HAVE_EPOLL */
979 cupsd_pollfds
= NULL
;
980 cupsd_alloc_pollfds
= 0;
983 cupsd_update_pollfds
= 0;
986 FD_ZERO(&cupsd_global_input
);
987 FD_ZERO(&cupsd_global_output
);
988 #endif /* HAVE_EPOLL */
993 * 'compare_fds()' - Compare file descriptors.
996 static int /* O - Result of comparison */
997 compare_fds(_cupsd_fd_t
*a
, /* I - First file descriptor */
998 _cupsd_fd_t
*b
) /* I - Second file descriptor */
1000 return (a
->fd
- b
->fd
);
1005 * 'find_fd()' - Find an existing file descriptor record.
1008 static _cupsd_fd_t
* /* O - FD record pointer or NULL */
1009 find_fd(int fd
) /* I - File descriptor */
1011 _cupsd_fd_t
*fdptr
, /* Matching record (if any) */
1012 key
; /* Search key */
1015 cupsArraySave(cupsd_fds
);
1018 fdptr
= (_cupsd_fd_t
*)cupsArrayFind(cupsd_fds
, &key
);
1020 cupsArrayRestore(cupsd_fds
);
1027 * End of "$Id: select.c 7720 2008-07-11 22:46:21Z mike $".