2 * "$Id: select.c 6376 2007-03-21 06:39:10Z mike $"
4 * Select abstraction functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2006-2007 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * cupsdAddSelect() - Add a file descriptor to the list.
27 * cupsdDoSelect() - Do a select-like operation.
28 * cupsdIsSelecting() - Determine whether we are monitoring a file
30 * cupsdRemoveSelect() - Remove a file descriptor from the list.
31 * cupsdStartSelect() - Initialize the file polling engine.
32 * cupsdStopSelect() - Shutdown the file polling engine.
33 * compare_fds() - Compare file descriptors.
34 * find_fd() - Find an existing file descriptor record.
38 * Include necessary headers...
44 # include <sys/epoll.h>
45 #elif defined(HAVE_KQUEUE)
46 # include <sys/event.h>
47 # include <sys/time.h>
48 #elif defined(HAVE_POLL)
49 # include <sys/poll.h>
51 # include <sys/time.h>
53 # include <sys/select.h>
54 #endif /* HAVE_EPOLL */
58 * Design Notes for Poll/Select API in CUPSD
59 * -----------------------------------------
63 * OS select poll epoll kqueue /dev/poll
64 * -------------- ------ ------ ------ ------ ---------
65 * AIX YES YES NO NO NO
66 * FreeBSD YES YES NO YES NO
67 * HP-UX YES YES NO NO NO
68 * IRIX YES YES NO NO NO
69 * Linux YES YES YES NO NO
70 * MacOS X YES YES NO YES NO
71 * NetBSD YES YES NO YES NO
72 * OpenBSD YES YES NO YES NO
73 * Solaris YES YES NO NO YES
74 * Tru64 YES YES NO NO NO
75 * Windows YES NO NO NO NO
80 * typedef void (*cupsd_selfunc_t)(void *data);
82 * void cupsdStartSelect(void);
83 * void cupsdStopSelect(void);
84 * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
85 * cupsd_selfunc_t write_cb, void *data);
86 * void cupsdRemoveSelect(int fd);
87 * int cupsdDoSelect(int timeout);
90 * IMPLEMENTATION STRATEGY
93 * a. CUPS array of file descriptor to callback functions
95 * b. cupsdStartSelect() creates the array
96 * c. cupsdStopSelect() destroys the array and all elements.
97 * d. cupsdAddSelect() adds to the array and allocates a
98 * new callback element.
99 * e. cupsdRemoveSelect() removes from the array and frees
100 * the callback element.
101 * f. _cupsd_fd_t provides a reference-counted structure for
102 * tracking file descriptors that are monitored.
105 * a. Input/Output fd_set variables, copied to working
106 * copies and then used with select().
107 * b. Loop through CUPS array, using FD_ISSET and calling
108 * the read/write callbacks as needed.
109 * c. cupsdRemoveSelect() clears fd_set bit from main and
111 * d. cupsdStopSelect() frees all of the memory used by the
112 * CUPS array and fd_set's.
114 * 2. poll() - O(n log n)
115 * a. Regular array of pollfd, sorted the same as the CUPS
117 * b. Loop through pollfd array, call the corresponding
118 * read/write callbacks as needed.
119 * c. cupsdAddSelect() adds first to CUPS array and flags the
120 * pollfd array as invalid.
121 * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
122 * poll(), then loops through the pollfd array looking up
124 * e. cupsdRemoveSelect() flags the pollfd array as invalid.
125 * f. cupsdStopSelect() frees all of the memory used by the
126 * CUPS array and pollfd array.
129 * a. cupsdStartSelect() creates epoll file descriptor using
130 * epoll_create() with the maximum fd count, and
131 * allocates an events buffer for the maximum fd count.
132 * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
133 * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
134 * event using the level-triggered semantics. The event
135 * user data field is a pointer to the new callback array
137 * c. cupsdDoSelect() uses epoll_wait() with the global event
138 * buffer allocated in cupsdStartSelect() and then loops
139 * through the events, using the user data field to find
140 * the callback record.
141 * d. cupsdStopSelect() closes the epoll file descriptor and
142 * frees all of the memory used by the event buffer.
145 * b. cupsdStartSelect() creates kqueue file descriptor
146 * using kqyeue() function and allocates a global event
148 * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
149 * register the changes. The event user data field is a
150 * pointer to the new callback array element.
151 * d. cupsdDoSelect() uses kevent() to poll for events and
152 * loops through the events, using the user data field to
153 * find the callback record.
154 * e. cupsdStopSelect() closes the kqyeye() file descriptor
155 * and frees all of the memory used by the event buffer.
157 * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
158 * a. cupsdStartSelect() opens /dev/poll and allocates an
159 * array of pollfd structs; on failure to open /dev/poll,
160 * revert to poll() system call.
161 * b. cupsdAddSelect() writes a single pollfd struct to
162 * /dev/poll with the new file descriptor and the
163 * POLLIN/POLLOUT flags.
164 * c. cupsdRemoveSelect() writes a single pollfd struct to
165 * /dev/poll with the file descriptor and the POLLREMOVE
167 * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
168 * events from /dev/poll and then loops through the
169 * returned pollfd array, looking up the file descriptors
171 * e. cupsdStopSelect() closes /dev/poll and frees the
176 * In tests using the "make test" target with option 0 (keep cupsd
177 * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
178 * performed 5.5% slower select(), followed by kqueue() at 16% slower
179 * than select() and poll() at 18% slower than select(). Similar
180 * results were seen with twice the number of client connections.
182 * The epoll() and kqueue() performance is likely limited by the
183 * number of system calls used to add/modify/remove file
184 * descriptors dynamically. Further optimizations may be possible
185 * in the area of limiting use of cupsdAddSelect() and
186 * cupsdRemoveSelect(), however extreme care will be needed to avoid
187 * excess CPU usage and deadlock conditions.
189 * We may be able to improve the poll() implementation simply by
190 * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
191 * will eliminate the rebuilding of the array whenever there is a
192 * change and eliminate the fd array lookups in the inner loop of
195 * Since /dev/poll will never be able to use a shadow array, it may
196 * not make sense to implement support for it. ioctl() overhead will
197 * impact performance as well, so my guess would be that, for CUPS,
198 * /dev/poll will yield a net performance loss.
202 * Local structures...
205 typedef struct _cupsd_fd_s
207 int fd
, /* File descriptor */
209 cupsd_selfunc_t read_cb
, /* Read callback */
210 write_cb
; /* Write callback */
211 void *data
; /* Data pointer for callbacks */
219 static cups_array_t
*cupsd_fds
= NULL
;
222 static int cupsd_epoll_fd
= -1;
223 static struct epoll_event
*cupsd_epoll_events
= NULL
;
224 #elif defined(HAVE_KQUEUE)
225 static int cupsd_kqueue_fd
= -1,
226 cupsd_kqueue_changes
= 0;
227 static struct kevent
*cupsd_kqueue_events
= NULL
;
228 #elif defined(HAVE_POLL)
229 static int cupsd_alloc_pollfds
= 0,
230 cupsd_update_pollfds
= 0;
231 static struct pollfd
*cupsd_pollfds
= NULL
;
233 static fd_set cupsd_global_input
,
236 cupsd_current_output
;
237 #endif /* HAVE_EPOLL */
244 static int compare_fds(_cupsd_fd_t
*a
, _cupsd_fd_t
*b
);
245 static _cupsd_fd_t
*find_fd(int fd
);
246 #define release_fd(f) { \
248 if (!(f)->use) free((f));\
250 #define retain_fd(f) (f)->use++
254 * 'cupsdAddSelect()' - Add a file descriptor to the list.
257 int /* O - 1 on success, 0 on error */
258 cupsdAddSelect(int fd
, /* I - File descriptor */
259 cupsd_selfunc_t read_cb
, /* I - Read callback */
260 cupsd_selfunc_t write_cb
,/* I - Write callback */
261 void *data
) /* I - Data to pass to callback */
263 _cupsd_fd_t
*fdptr
; /* File descriptor record */
264 int added
; /* 1 if added, 0 if modified */
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 struct epoll_event event
; /* Event data */
314 event
.events
|= EPOLLIN
;
317 event
.events
|= EPOLLOUT
;
319 event
.data
.ptr
= fdptr
;
321 epoll_ctl(cupsd_epoll_fd
, added
? EPOLL_CTL_ADD
: EPOLL_CTL_MOD
, fd
,
325 #elif defined(HAVE_KQUEUE)
327 struct kevent event
; /* Event data */
328 struct timespec timeout
; /* Timeout value */
334 if (fdptr
->read_cb
!= read_cb
)
337 EV_SET(&event
, fd
, EVFILT_READ
, EV_ADD
, 0, 0, fdptr
);
339 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
341 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
343 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
344 "cupsdAddSelect: kevent() returned %s",
350 if (fdptr
->write_cb
!= write_cb
)
353 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_ADD
, 0, 0, fdptr
);
355 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
357 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
359 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
360 "cupsdAddSelect: kevent() returned %s",
367 #elif defined(HAVE_POLL)
368 cupsd_update_pollfds
= 1;
372 * Add or remove the file descriptor in the input and output sets
378 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
379 "cupsdAddSelect: Adding fd %d to input set...", fd
);
380 FD_SET(fd
, &cupsd_global_input
);
384 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
385 "cupsdAddSelect: Removing fd %d from input set...", fd
);
386 FD_CLR(fd
, &cupsd_global_input
);
387 FD_CLR(fd
, &cupsd_current_input
);
392 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
393 "cupsdAddSelect: Adding fd %d to output set...", fd
);
394 FD_SET(fd
, &cupsd_global_output
);
398 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
399 "cupsdAddSelect: Removing fd %d from output set...", fd
);
400 FD_CLR(fd
, &cupsd_global_output
);
401 FD_CLR(fd
, &cupsd_current_output
);
403 #endif /* HAVE_EPOLL */
406 * Save the (new) read and write callbacks...
409 fdptr
->read_cb
= read_cb
;
410 fdptr
->write_cb
= write_cb
;
418 * 'cupsdDoSelect()' - Do a select-like operation.
421 int /* O - Number of files or -1 on error */
422 cupsdDoSelect(long timeout
) /* I - Timeout in seconds */
424 int nfds
; /* Number of file descriptors */
425 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
427 int i
; /* Looping var */
428 struct epoll_event
*event
; /* Current event */
431 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
432 "cupsdDoSelect: polling %d fds for %ld seconds...",
433 cupsArrayCount(cupsd_fds
), timeout
);
435 if (timeout
>= 0 && timeout
< 86400)
436 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
,
439 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
, -1);
441 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: epoll() returned %d...",
444 for (i
= nfds
, event
= cupsd_epoll_events
; i
> 0; i
--, event
++)
446 fdptr
= (_cupsd_fd_t
*)event
->data
.ptr
;
450 if (fdptr
->read_cb
&& (event
->events
& (EPOLLIN
| EPOLLERR
| EPOLLHUP
)))
452 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
454 (*(fdptr
->read_cb
))(fdptr
->data
);
457 if (fdptr
->write_cb
&& (event
->events
& (EPOLLOUT
| EPOLLERR
| EPOLLHUP
)))
459 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
461 (*(fdptr
->write_cb
))(fdptr
->data
);
467 #elif defined(HAVE_KQUEUE)
468 int i
; /* Looping var */
469 struct kevent
*event
; /* Current event */
470 struct timespec ktimeout
; /* kevent() timeout */
473 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
474 "cupsdDoSelect: polling %d fds for %ld seconds...",
475 cupsArrayCount(cupsd_fds
), timeout
);
477 if (timeout
>= 0 && timeout
< 86400)
479 ktimeout
.tv_sec
= timeout
;
480 ktimeout
.tv_nsec
= 0;
482 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
,
486 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
, NULL
);
488 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
489 "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...",
490 cupsd_kqueue_fd
, MaxFDs
, nfds
);
492 cupsd_kqueue_changes
= 0;
494 for (i
= nfds
, event
= cupsd_kqueue_events
; i
> 0; i
--, event
++)
496 fdptr
= (_cupsd_fd_t
*)event
->udata
;
498 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "event->filter=%d, event->ident=%d",
499 event
->filter
, (int)event
->ident
);
503 if (fdptr
->read_cb
&& event
->filter
== EVFILT_READ
)
505 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
507 (*(fdptr
->read_cb
))(fdptr
->data
);
510 if (fdptr
->write_cb
&& event
->filter
== EVFILT_WRITE
)
512 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
514 (*(fdptr
->write_cb
))(fdptr
->data
);
520 #elif defined(HAVE_POLL)
521 struct pollfd
*pfd
; /* Current pollfd structure */
522 int count
; /* Number of file descriptors */
525 count
= cupsArrayCount(cupsd_fds
);
527 if (cupsd_update_pollfds
)
530 * Update the cupsd_pollfds array to match the current FD array...
533 cupsd_update_pollfds
= 0;
535 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Updating pollfd array...");
538 * (Re)allocate memory as needed...
541 if (count
> cupsd_alloc_pollfds
)
543 int allocfds
= count
+ 16;
547 pfd
= realloc(cupsd_pollfds
, allocfds
* sizeof(struct pollfd
));
549 pfd
= malloc(allocfds
* sizeof(struct pollfd
));
553 cupsdLogMessage(CUPSD_LOG_EMERG
,
554 "Unable to allocate %d bytes for polling!",
555 (int)(allocfds
* sizeof(struct pollfd
)));
561 cupsd_alloc_pollfds
= allocfds
;
565 * Rebuild the array...
568 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
), pfd
= cupsd_pollfds
;
570 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
), pfd
++)
576 pfd
->events
|= POLLIN
;
579 pfd
->events
|= POLLOUT
;
583 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
584 "cupsdDoSelect: polling %d fds for %ld seconds...",
587 if (timeout
>= 0 && timeout
< 86400)
588 nfds
= poll(cupsd_pollfds
, count
, timeout
* 1000);
590 nfds
= poll(cupsd_pollfds
, count
, -1);
592 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: poll() returned %d...",
598 * Do callbacks for each file descriptor...
601 for (pfd
= cupsd_pollfds
; count
> 0; pfd
++, count
--)
603 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
604 "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
605 pfd
- cupsd_pollfds
, pfd
->fd
, pfd
->revents
);
610 if ((fdptr
= find_fd(pfd
->fd
)) == NULL
)
615 if (fdptr
->read_cb
&& (pfd
->revents
& (POLLIN
| POLLERR
| POLLHUP
)))
617 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
619 (*(fdptr
->read_cb
))(fdptr
->data
);
622 if (fdptr
->write_cb
&& (pfd
->revents
& (POLLOUT
| POLLERR
| POLLHUP
)))
624 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
626 (*(fdptr
->write_cb
))(fdptr
->data
);
634 struct timeval stimeout
; /* Timeout for select() */
635 int maxfd
; /* Maximum file descriptor */
639 * Figure out the highest file descriptor number...
642 if ((fdptr
= (_cupsd_fd_t
*)cupsArrayLast(cupsd_fds
)) == NULL
)
645 maxfd
= fdptr
->fd
+ 1;
651 cupsd_current_input
= cupsd_global_input
;
652 cupsd_current_output
= cupsd_global_output
;
654 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
655 "cupsdDoSelect: selecting %d fds for %ld seconds...",
658 if (timeout
>= 0 && timeout
< 86400)
660 stimeout
.tv_sec
= timeout
;
661 stimeout
.tv_usec
= 0;
663 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
667 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
670 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: select() returned %d...",
676 * Do callbacks for each file descriptor...
679 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
681 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
685 if (fdptr
->read_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_input
))
687 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
689 (*(fdptr
->read_cb
))(fdptr
->data
);
692 if (fdptr
->write_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_output
))
694 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
696 (*(fdptr
->write_cb
))(fdptr
->data
);
703 #endif /* HAVE_EPOLL */
706 * Return the number of file descriptors handled...
713 #ifdef CUPSD_IS_SELECTING
715 * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
719 int /* O - 1 if selecting, 0 otherwise */
720 cupsdIsSelecting(int fd
) /* I - File descriptor */
722 return (find_fd(fd
) != NULL
);
724 #endif /* CUPSD_IS_SELECTING */
728 * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
732 cupsdRemoveSelect(int fd
) /* I - File descriptor */
734 _cupsd_fd_t
*fdptr
; /* File descriptor record */
736 struct epoll_event event
; /* Event data */
737 #elif defined(HAVE_KQUEUE)
738 struct kevent event
; /* Event data */
739 struct timespec timeout
; /* Timeout value */
740 #elif defined(HAVE_POLL)
741 /* No variables for poll() */
742 #endif /* HAVE_EPOLL */
746 * Range check input...
749 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdRemoveSelect: fd=%d", fd
);
755 * Find the file descriptor...
758 if ((fdptr
= find_fd(fd
)) == NULL
)
762 epoll_ctl(cupsd_epoll_fd
, EPOLL_CTL_DEL
, fd
, &event
);
764 #elif defined(HAVE_KQUEUE)
770 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
772 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
774 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
775 "cupsdRemoveSelect: kevent() returned %s",
783 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
785 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
787 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
788 "cupsdRemoveSelect: kevent() returned %s",
795 #elif defined(HAVE_POLL)
797 * Update the pollfds array...
800 cupsd_update_pollfds
= 1;
803 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
804 "cupsdRemoveSelect: Removing fd %d from input and output "
806 FD_CLR(fd
, &cupsd_global_input
);
807 FD_CLR(fd
, &cupsd_global_output
);
808 FD_CLR(fd
, &cupsd_current_input
);
809 FD_CLR(fd
, &cupsd_current_output
);
810 #endif /* HAVE_EPOLL */
813 * Remove the file descriptor for from the FD array...
816 cupsArrayRemove(cupsd_fds
, fdptr
);
822 * 'cupsdStartSelect()' - Initialize the file polling engine.
826 cupsdStartSelect(void)
828 cupsd_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
831 cupsd_epoll_fd
= epoll_create(MaxFDs
);
832 cupsd_epoll_events
= calloc(MaxFDs
, sizeof(struct epoll_event
));
834 #elif defined(HAVE_KQUEUE)
835 cupsd_kqueue_fd
= kqueue();
836 cupsd_kqueue_changes
= 0;
837 cupsd_kqueue_events
= calloc(MaxFDs
, sizeof(struct kevent
));
839 #elif defined(HAVE_POLL)
840 cupsd_update_pollfds
= 0;
843 FD_ZERO(&cupsd_global_input
);
844 FD_ZERO(&cupsd_global_output
);
845 #endif /* HAVE_EPOLL */
850 * 'cupsdStopSelect()' - Shutdown the file polling engine.
854 cupsdStopSelect(void)
856 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
859 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
861 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
864 cupsArrayDelete(cupsd_fds
);
868 if (cupsd_epoll_events
)
870 free(cupsd_epoll_events
);
871 cupsd_epoll_events
= NULL
;
874 if (cupsd_epoll_fd
>= 0)
876 close(cupsd_epoll_fd
);
880 #elif defined(HAVE_KQUEUE)
881 if (cupsd_kqueue_events
)
883 free(cupsd_kqueue_events
);
884 cupsd_kqueue_events
= NULL
;
887 if (cupsd_kqueue_fd
>= 0)
889 close(cupsd_kqueue_fd
);
890 cupsd_kqueue_fd
= -1;
893 cupsd_kqueue_changes
= 0;
895 #elif defined(HAVE_POLL)
899 cupsd_pollfds
= NULL
;
900 cupsd_alloc_pollfds
= 0;
903 cupsd_update_pollfds
= 0;
906 FD_ZERO(&cupsd_global_input
);
907 FD_ZERO(&cupsd_global_output
);
908 #endif /* HAVE_EPOLL */
913 * 'compare_fds()' - Compare file descriptors.
916 static int /* O - Result of comparison */
917 compare_fds(_cupsd_fd_t
*a
, /* I - First file descriptor */
918 _cupsd_fd_t
*b
) /* I - Second file descriptor */
920 return (a
->fd
- b
->fd
);
925 * 'find_fd()' - Find an existing file descriptor record.
928 static _cupsd_fd_t
* /* O - FD record pointer or NULL */
929 find_fd(int fd
) /* I - File descriptor */
931 _cupsd_fd_t
*fdptr
, /* Matching record (if any) */
932 key
; /* Search key */
935 cupsArraySave(cupsd_fds
);
938 fdptr
= (_cupsd_fd_t
*)cupsArrayFind(cupsd_fds
, &key
);
940 cupsArrayRestore(cupsd_fds
);
947 * End of "$Id: select.c 6376 2007-03-21 06:39:10Z mike $".