2 * "$Id: select.c 6649 2007-07-11 21:46:42Z mike $"
4 * Select abstraction functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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 #elif defined(HAVE_KQUEUE)
37 # include <sys/event.h>
38 # include <sys/time.h>
39 #elif defined(HAVE_POLL)
40 # include <sys/poll.h>
42 # include <sys/time.h>
44 # include <sys/select.h>
45 #endif /* HAVE_EPOLL */
49 * Design Notes for Poll/Select API in CUPSD
50 * -----------------------------------------
54 * OS select poll epoll kqueue /dev/poll
55 * -------------- ------ ------ ------ ------ ---------
56 * AIX YES YES NO NO NO
57 * FreeBSD YES YES NO YES NO
58 * HP-UX YES YES NO NO NO
59 * IRIX YES YES NO NO NO
60 * Linux YES YES YES NO NO
61 * MacOS X YES YES NO YES NO
62 * NetBSD YES YES NO YES NO
63 * OpenBSD YES YES NO YES NO
64 * Solaris YES YES NO NO YES
65 * Tru64 YES YES NO NO NO
66 * Windows YES NO NO NO NO
71 * typedef void (*cupsd_selfunc_t)(void *data);
73 * void cupsdStartSelect(void);
74 * void cupsdStopSelect(void);
75 * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
76 * cupsd_selfunc_t write_cb, void *data);
77 * void cupsdRemoveSelect(int fd);
78 * int cupsdDoSelect(int timeout);
81 * IMPLEMENTATION STRATEGY
84 * a. CUPS array of file descriptor to callback functions
85 * and data + temporary array of removed fd's.
86 * b. cupsdStartSelect() creates the arrays
87 * c. cupsdStopSelect() destroys the arrays and all elements.
88 * d. cupsdAddSelect() adds to the array and allocates a
89 * new callback element.
90 * e. cupsdRemoveSelect() removes from the active array and
91 * adds to the inactive array.
92 * f. _cupsd_fd_t provides a reference-counted structure for
93 * tracking file descriptors that are monitored.
94 * g. cupsdDoSelect() frees all inactive FDs.
97 * a. Input/Output fd_set variables, copied to working
98 * copies and then used with select().
99 * b. Loop through CUPS array, using FD_ISSET and calling
100 * the read/write callbacks as needed.
101 * c. cupsdRemoveSelect() clears fd_set bit from main and
103 * d. cupsdStopSelect() frees all of the memory used by the
104 * CUPS array and fd_set's.
106 * 2. poll() - O(n log n)
107 * a. Regular array of pollfd, sorted the same as the CUPS
109 * b. Loop through pollfd array, call the corresponding
110 * read/write callbacks as needed.
111 * c. cupsdAddSelect() adds first to CUPS array and flags the
112 * pollfd array as invalid.
113 * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
114 * poll(), then loops through the pollfd array looking up
116 * e. cupsdRemoveSelect() flags the pollfd array as invalid.
117 * f. cupsdStopSelect() frees all of the memory used by the
118 * CUPS array and pollfd array.
121 * a. cupsdStartSelect() creates epoll file descriptor using
122 * epoll_create() with the maximum fd count, and
123 * allocates an events buffer for the maximum fd count.
124 * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
125 * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
126 * event using the level-triggered semantics. The event
127 * user data field is a pointer to the new callback array
129 * c. cupsdDoSelect() uses epoll_wait() with the global event
130 * buffer allocated in cupsdStartSelect() and then loops
131 * through the events, using the user data field to find
132 * the callback record.
133 * d. cupsdStopSelect() closes the epoll file descriptor and
134 * frees all of the memory used by the event buffer.
137 * b. cupsdStartSelect() creates kqueue file descriptor
138 * using kqyeue() function and allocates a global event
140 * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
141 * register the changes. The event user data field is a
142 * pointer to the new callback array element.
143 * d. cupsdDoSelect() uses kevent() to poll for events and
144 * loops through the events, using the user data field to
145 * find the callback record.
146 * e. cupsdStopSelect() closes the kqyeye() file descriptor
147 * and frees all of the memory used by the event buffer.
149 * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
150 * a. cupsdStartSelect() opens /dev/poll and allocates an
151 * array of pollfd structs; on failure to open /dev/poll,
152 * revert to poll() system call.
153 * b. cupsdAddSelect() writes a single pollfd struct to
154 * /dev/poll with the new file descriptor and the
155 * POLLIN/POLLOUT flags.
156 * c. cupsdRemoveSelect() writes a single pollfd struct to
157 * /dev/poll with the file descriptor and the POLLREMOVE
159 * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
160 * events from /dev/poll and then loops through the
161 * returned pollfd array, looking up the file descriptors
163 * e. cupsdStopSelect() closes /dev/poll and frees the
168 * In tests using the "make test" target with option 0 (keep cupsd
169 * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
170 * performed 5.5% slower select(), followed by kqueue() at 16% slower
171 * than select() and poll() at 18% slower than select(). Similar
172 * results were seen with twice the number of client connections.
174 * The epoll() and kqueue() performance is likely limited by the
175 * number of system calls used to add/modify/remove file
176 * descriptors dynamically. Further optimizations may be possible
177 * in the area of limiting use of cupsdAddSelect() and
178 * cupsdRemoveSelect(), however extreme care will be needed to avoid
179 * excess CPU usage and deadlock conditions.
181 * We may be able to improve the poll() implementation simply by
182 * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
183 * will eliminate the rebuilding of the array whenever there is a
184 * change and eliminate the fd array lookups in the inner loop of
187 * Since /dev/poll will never be able to use a shadow array, it may
188 * not make sense to implement support for it. ioctl() overhead will
189 * impact performance as well, so my guess would be that, for CUPS,
190 * /dev/poll will yield a net performance loss.
194 * Local structures...
197 typedef struct _cupsd_fd_s
199 int fd
, /* File descriptor */
201 cupsd_selfunc_t read_cb
, /* Read callback */
202 write_cb
; /* Write callback */
203 void *data
; /* Data pointer for callbacks */
211 static cups_array_t
*cupsd_fds
= NULL
;
212 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
213 static cups_array_t
*cupsd_inactive_fds
= NULL
;
214 static int cupsd_in_select
= 0;
215 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
218 static int cupsd_epoll_fd
= -1;
219 static struct epoll_event
*cupsd_epoll_events
= NULL
;
220 #elif defined(HAVE_KQUEUE)
221 static int cupsd_kqueue_fd
= -1,
222 cupsd_kqueue_changes
= 0;
223 static struct kevent
*cupsd_kqueue_events
= NULL
;
224 #elif defined(HAVE_POLL)
225 static int cupsd_alloc_pollfds
= 0,
226 cupsd_update_pollfds
= 0;
227 static struct pollfd
*cupsd_pollfds
= NULL
;
229 static fd_set cupsd_global_input
,
232 cupsd_current_output
;
233 #endif /* HAVE_EPOLL */
240 static int compare_fds(_cupsd_fd_t
*a
, _cupsd_fd_t
*b
);
241 static _cupsd_fd_t
*find_fd(int fd
);
242 #define release_fd(f) { \
244 if (!(f)->use) free((f));\
246 #define retain_fd(f) (f)->use++
250 * 'cupsdAddSelect()' - Add a file descriptor to the list.
253 int /* O - 1 on success, 0 on error */
254 cupsdAddSelect(int fd
, /* I - File descriptor */
255 cupsd_selfunc_t read_cb
, /* I - Read callback */
256 cupsd_selfunc_t write_cb
,/* I - Write callback */
257 void *data
) /* I - Data to pass to callback */
259 _cupsd_fd_t
*fdptr
; /* File descriptor record */
260 int added
; /* 1 if added, 0 if modified */
264 * Range check input...
267 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
268 "cupsdAddSelect: fd=%d, read_cb=%p, write_cb=%p, data=%p",
269 fd
, read_cb
, write_cb
, data
);
275 * See if this FD has already been added...
278 if ((fdptr
= find_fd(fd
)) == NULL
)
281 * No, add a new entry...
284 if ((fdptr
= calloc(1, sizeof(_cupsd_fd_t
))) == NULL
)
290 if (!cupsArrayAdd(cupsd_fds
, fdptr
))
292 cupsdLogMessage(CUPSD_LOG_EMERG
, "Unable to add fd %d to array!", fd
);
304 struct epoll_event event
; /* Event data */
310 event
.events
|= EPOLLIN
;
313 event
.events
|= EPOLLOUT
;
315 event
.data
.ptr
= fdptr
;
317 epoll_ctl(cupsd_epoll_fd
, added
? EPOLL_CTL_ADD
: EPOLL_CTL_MOD
, fd
,
321 #elif defined(HAVE_KQUEUE)
323 struct kevent event
; /* Event data */
324 struct timespec timeout
; /* Timeout value */
330 if (fdptr
->read_cb
!= read_cb
)
333 EV_SET(&event
, fd
, EVFILT_READ
, EV_ADD
, 0, 0, fdptr
);
335 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
337 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
339 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
340 "cupsdAddSelect: kevent() returned %s",
346 if (fdptr
->write_cb
!= write_cb
)
349 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_ADD
, 0, 0, fdptr
);
351 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
353 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
355 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
356 "cupsdAddSelect: kevent() returned %s",
363 #elif defined(HAVE_POLL)
364 cupsd_update_pollfds
= 1;
368 * Add or remove the file descriptor in the input and output sets
374 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
375 "cupsdAddSelect: Adding fd %d to input set...", fd
);
376 FD_SET(fd
, &cupsd_global_input
);
380 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
381 "cupsdAddSelect: Removing fd %d from input set...", fd
);
382 FD_CLR(fd
, &cupsd_global_input
);
383 FD_CLR(fd
, &cupsd_current_input
);
388 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
389 "cupsdAddSelect: Adding fd %d to output set...", fd
);
390 FD_SET(fd
, &cupsd_global_output
);
394 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
395 "cupsdAddSelect: Removing fd %d from output set...", fd
);
396 FD_CLR(fd
, &cupsd_global_output
);
397 FD_CLR(fd
, &cupsd_current_output
);
399 #endif /* HAVE_EPOLL */
402 * Save the (new) read and write callbacks...
405 fdptr
->read_cb
= read_cb
;
406 fdptr
->write_cb
= write_cb
;
414 * 'cupsdDoSelect()' - Do a select-like operation.
417 int /* O - Number of files or -1 on error */
418 cupsdDoSelect(long timeout
) /* I - Timeout in seconds */
420 int nfds
; /* Number of file descriptors */
421 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
423 int i
; /* Looping var */
424 struct epoll_event
*event
; /* Current event */
427 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
428 "cupsdDoSelect: polling %d fds for %ld seconds...",
429 cupsArrayCount(cupsd_fds
), timeout
);
433 if (timeout
>= 0 && timeout
< 86400)
434 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
,
437 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
, -1);
439 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: epoll() returned %d...",
442 for (i
= nfds
, event
= cupsd_epoll_events
; i
> 0; i
--, event
++)
444 fdptr
= (_cupsd_fd_t
*)event
->data
.ptr
;
446 if (cupsArrayFind(cupsd_inactive_fds
, fdptr
))
451 if (fdptr
->read_cb
&& (event
->events
& (EPOLLIN
| EPOLLERR
| EPOLLHUP
)))
453 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
455 (*(fdptr
->read_cb
))(fdptr
->data
);
458 if (fdptr
->write_cb
&& (event
->events
& (EPOLLOUT
| EPOLLERR
| EPOLLHUP
)))
460 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
462 (*(fdptr
->write_cb
))(fdptr
->data
);
468 #elif defined(HAVE_KQUEUE)
469 int i
; /* Looping var */
470 struct kevent
*event
; /* Current event */
471 struct timespec ktimeout
; /* kevent() timeout */
474 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
475 "cupsdDoSelect: polling %d fds for %ld seconds...",
476 cupsArrayCount(cupsd_fds
), timeout
);
480 if (timeout
>= 0 && timeout
< 86400)
482 ktimeout
.tv_sec
= timeout
;
483 ktimeout
.tv_nsec
= 0;
485 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
,
489 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
, NULL
);
491 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
492 "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...",
493 cupsd_kqueue_fd
, MaxFDs
, nfds
);
495 cupsd_kqueue_changes
= 0;
497 for (i
= nfds
, event
= cupsd_kqueue_events
; i
> 0; i
--, event
++)
499 fdptr
= (_cupsd_fd_t
*)event
->udata
;
501 if (cupsArrayFind(cupsd_inactive_fds
, fdptr
))
504 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "event->filter=%d, event->ident=%d",
505 event
->filter
, (int)event
->ident
);
509 if (fdptr
->read_cb
&& event
->filter
== EVFILT_READ
)
511 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
513 (*(fdptr
->read_cb
))(fdptr
->data
);
516 if (fdptr
->write_cb
&& event
->filter
== EVFILT_WRITE
)
518 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
520 (*(fdptr
->write_cb
))(fdptr
->data
);
526 #elif defined(HAVE_POLL)
527 struct pollfd
*pfd
; /* Current pollfd structure */
528 int count
; /* Number of file descriptors */
531 count
= cupsArrayCount(cupsd_fds
);
533 if (cupsd_update_pollfds
)
536 * Update the cupsd_pollfds array to match the current FD array...
539 cupsd_update_pollfds
= 0;
541 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Updating pollfd array...");
544 * (Re)allocate memory as needed...
547 if (count
> cupsd_alloc_pollfds
)
549 int allocfds
= count
+ 16;
553 pfd
= realloc(cupsd_pollfds
, allocfds
* sizeof(struct pollfd
));
555 pfd
= malloc(allocfds
* sizeof(struct pollfd
));
559 cupsdLogMessage(CUPSD_LOG_EMERG
,
560 "Unable to allocate %d bytes for polling!",
561 (int)(allocfds
* sizeof(struct pollfd
)));
567 cupsd_alloc_pollfds
= allocfds
;
571 * Rebuild the array...
574 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
), pfd
= cupsd_pollfds
;
576 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
), pfd
++)
582 pfd
->events
|= POLLIN
;
585 pfd
->events
|= POLLOUT
;
589 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
590 "cupsdDoSelect: polling %d fds for %ld seconds...",
593 if (timeout
>= 0 && timeout
< 86400)
594 nfds
= poll(cupsd_pollfds
, count
, timeout
* 1000);
596 nfds
= poll(cupsd_pollfds
, count
, -1);
598 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: poll() returned %d...",
604 * Do callbacks for each file descriptor...
607 for (pfd
= cupsd_pollfds
; count
> 0; pfd
++, count
--)
609 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
610 "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
611 pfd
- cupsd_pollfds
, pfd
->fd
, pfd
->revents
);
616 if ((fdptr
= find_fd(pfd
->fd
)) == NULL
)
621 if (fdptr
->read_cb
&& (pfd
->revents
& (POLLIN
| POLLERR
| POLLHUP
)))
623 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
625 (*(fdptr
->read_cb
))(fdptr
->data
);
628 if (fdptr
->write_cb
&& (pfd
->revents
& (POLLOUT
| POLLERR
| POLLHUP
)))
630 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
632 (*(fdptr
->write_cb
))(fdptr
->data
);
640 struct timeval stimeout
; /* Timeout for select() */
641 int maxfd
; /* Maximum file descriptor */
645 * Figure out the highest file descriptor number...
648 if ((fdptr
= (_cupsd_fd_t
*)cupsArrayLast(cupsd_fds
)) == NULL
)
651 maxfd
= fdptr
->fd
+ 1;
657 cupsd_current_input
= cupsd_global_input
;
658 cupsd_current_output
= cupsd_global_output
;
660 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
661 "cupsdDoSelect: selecting %d fds for %ld seconds...",
664 if (timeout
>= 0 && timeout
< 86400)
666 stimeout
.tv_sec
= timeout
;
667 stimeout
.tv_usec
= 0;
669 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
673 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
676 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: select() returned %d...",
682 * Do callbacks for each file descriptor...
685 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
687 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
691 if (fdptr
->read_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_input
))
693 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
695 (*(fdptr
->read_cb
))(fdptr
->data
);
698 if (fdptr
->write_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_output
))
700 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
702 (*(fdptr
->write_cb
))(fdptr
->data
);
709 #endif /* HAVE_EPOLL */
711 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
713 * Release all inactive file descriptors...
718 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_inactive_fds
);
720 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_inactive_fds
))
722 cupsArrayRemove(cupsd_inactive_fds
, fdptr
);
725 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
728 * Return the number of file descriptors handled...
735 #ifdef CUPSD_IS_SELECTING
737 * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
741 int /* O - 1 if selecting, 0 otherwise */
742 cupsdIsSelecting(int fd
) /* I - File descriptor */
744 return (find_fd(fd
) != NULL
);
746 #endif /* CUPSD_IS_SELECTING */
750 * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
754 cupsdRemoveSelect(int fd
) /* I - File descriptor */
756 _cupsd_fd_t
*fdptr
; /* File descriptor record */
758 struct epoll_event event
; /* Event data */
759 #elif defined(HAVE_KQUEUE)
760 struct kevent event
; /* Event data */
761 struct timespec timeout
; /* Timeout value */
762 #elif defined(HAVE_POLL)
763 /* No variables for poll() */
764 #endif /* HAVE_EPOLL */
768 * Range check input...
771 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdRemoveSelect: fd=%d", fd
);
777 * Find the file descriptor...
780 if ((fdptr
= find_fd(fd
)) == NULL
)
784 epoll_ctl(cupsd_epoll_fd
, EPOLL_CTL_DEL
, fd
, &event
);
786 #elif defined(HAVE_KQUEUE)
792 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
794 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
796 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
797 "cupsdRemoveSelect: kevent() returned %s",
805 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
807 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
809 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
810 "cupsdRemoveSelect: kevent() returned %s",
817 #elif defined(HAVE_POLL)
819 * Update the pollfds array...
822 cupsd_update_pollfds
= 1;
825 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
826 "cupsdRemoveSelect: Removing fd %d from input and output "
828 FD_CLR(fd
, &cupsd_global_input
);
829 FD_CLR(fd
, &cupsd_global_output
);
830 FD_CLR(fd
, &cupsd_current_input
);
831 FD_CLR(fd
, &cupsd_current_output
);
832 #endif /* HAVE_EPOLL */
835 * Remove the file descriptor from the active array and add to the
836 * inactive array (or release, if we don't need the inactive array...)
839 cupsArrayRemove(cupsd_fds
, fdptr
);
841 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
843 cupsArrayAdd(cupsd_inactive_fds
, fdptr
);
845 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
852 * 'cupsdStartSelect()' - Initialize the file polling engine.
856 cupsdStartSelect(void)
858 cupsd_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
860 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
861 cupsd_inactive_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
862 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
865 cupsd_epoll_fd
= epoll_create(MaxFDs
);
866 cupsd_epoll_events
= calloc(MaxFDs
, sizeof(struct epoll_event
));
868 #elif defined(HAVE_KQUEUE)
869 cupsd_kqueue_fd
= kqueue();
870 cupsd_kqueue_changes
= 0;
871 cupsd_kqueue_events
= calloc(MaxFDs
, sizeof(struct kevent
));
873 #elif defined(HAVE_POLL)
874 cupsd_update_pollfds
= 0;
877 FD_ZERO(&cupsd_global_input
);
878 FD_ZERO(&cupsd_global_output
);
879 #endif /* HAVE_EPOLL */
884 * 'cupsdStopSelect()' - Shutdown the file polling engine.
888 cupsdStopSelect(void)
890 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
893 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
895 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
898 cupsArrayDelete(cupsd_fds
);
901 #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
902 cupsArrayDelete(cupsd_inactive_fds
);
903 cupsd_inactive_fds
= NULL
;
904 #endif /* HAVE_EPOLL || HAVE_KQUEUE */
907 if (cupsd_epoll_events
)
909 free(cupsd_epoll_events
);
910 cupsd_epoll_events
= NULL
;
913 if (cupsd_epoll_fd
>= 0)
915 close(cupsd_epoll_fd
);
919 #elif defined(HAVE_KQUEUE)
920 if (cupsd_kqueue_events
)
922 free(cupsd_kqueue_events
);
923 cupsd_kqueue_events
= NULL
;
926 if (cupsd_kqueue_fd
>= 0)
928 close(cupsd_kqueue_fd
);
929 cupsd_kqueue_fd
= -1;
932 cupsd_kqueue_changes
= 0;
934 #elif defined(HAVE_POLL)
938 cupsd_pollfds
= NULL
;
939 cupsd_alloc_pollfds
= 0;
942 cupsd_update_pollfds
= 0;
945 FD_ZERO(&cupsd_global_input
);
946 FD_ZERO(&cupsd_global_output
);
947 #endif /* HAVE_EPOLL */
952 * 'compare_fds()' - Compare file descriptors.
955 static int /* O - Result of comparison */
956 compare_fds(_cupsd_fd_t
*a
, /* I - First file descriptor */
957 _cupsd_fd_t
*b
) /* I - Second file descriptor */
959 return (a
->fd
- b
->fd
);
964 * 'find_fd()' - Find an existing file descriptor record.
967 static _cupsd_fd_t
* /* O - FD record pointer or NULL */
968 find_fd(int fd
) /* I - File descriptor */
970 _cupsd_fd_t
*fdptr
, /* Matching record (if any) */
971 key
; /* Search key */
974 cupsArraySave(cupsd_fds
);
977 fdptr
= (_cupsd_fd_t
*)cupsArrayFind(cupsd_fds
, &key
);
979 cupsArrayRestore(cupsd_fds
);
986 * End of "$Id: select.c 6649 2007-07-11 21:46:42Z mike $".